项目作者: xcarpentier

项目描述 :
🚩Make an interactive step by step tour guide for your react-native app (a rewrite of react-native-copilot)
高级语言: TypeScript
项目地址: git://github.com/xcarpentier/rn-tourguide.git
创建时间: 2020-05-25T22:50:59Z
项目社区:https://github.com/xcarpentier/rn-tourguide

开源协议:Other

下载


RN-TourGuide


A flexible tourguide for your react native app!

🎉 Webable 🎉

(a rewriting of react-native-copilot)


RN Tourguide




🎉DEMO WEB 🎉

Installation

  1. yarn add rn-tourguide
  1. yarn add react-native-svg
  2. react-native link react-native-svg

If you are using Expo:

  1. expo install react-native-svg

Usage

  1. import {
  2. TourGuideProvider, // Main provider
  3. TourGuideZone, // Main wrapper of highlight component
  4. TourGuideZoneByPosition, // Component to use mask on overlay (ie, position absolute)
  5. useTourGuideController, // hook to start, etc.
  6. } from 'rn-tourguide'
  7. // Add <TourGuideProvider></TourGuideProvider> at the root of you app!
  8. function App() {
  9. return (
  10. // If you added a statusbar in Andoid set androidStatusBarVisible: true as well to avoid vertical position issues
  11. <TourGuideProvider {...{ borderRadius: 16 }}>
  12. <AppContent ></AppContent>
  13. </TourGuideProvider>
  14. )
  15. }
  16. const AppContent = () => {
  17. const iconProps = { size: 40, color: '#888' }
  18. // Use Hooks to control!
  19. const {
  20. canStart, // a boolean indicate if you can start tour guide
  21. start, // a function to start the tourguide
  22. stop, // a function to stopping it
  23. eventEmitter, // an object for listening some events
  24. } = useTourGuideController()
  25. // Can start at mount 🎉
  26. // you need to wait until everything is registered 😁
  27. React.useEffect(() => {
  28. if (canStart) {
  29. // 👈 test if you can start otherwise nothing will happen
  30. start()
  31. }
  32. }, [canStart]) // 👈 don't miss it!
  33. const handleOnStart = () => console.log('start')
  34. const handleOnStop = () => console.log('stop')
  35. const handleOnStepChange = () => console.log(`stepChange`)
  36. React.useEffect(() => {
  37. eventEmitter.on('start', handleOnStart)
  38. eventEmitter.on('stop', handleOnStop)
  39. eventEmitter.on('stepChange', handleOnStepChange)
  40. return () => {
  41. eventEmitter.off('start', handleOnStart)
  42. eventEmitter.off('stop', handleOnStop)
  43. eventEmitter.off('stepChange', handleOnStepChange)
  44. }
  45. }, [])
  46. return (
  47. <View style={styles.container}>
  48. {/*
  49. Use TourGuideZone only to wrap your component
  50. */}
  51. <TourGuideZone
  52. zone={2}
  53. text={'A react-native-copilot remastered! 🎉'}
  54. borderRadius={16}
  55. >
  56. <Text style={styles.title}>
  57. {'Welcome to the demo of\n"rn-tourguide"'}
  58. </Text>
  59. </TourGuideZone>
  60. <View style={styles.middleView}>
  61. <TouchableOpacity style={styles.button} onPress={() => start()}>
  62. <Text style={styles.buttonText}>START THE TUTORIAL!</Text>
  63. </TouchableOpacity>
  64. <TourGuideZone zone={3} shape={'rectangle_and_keep'}>
  65. <TouchableOpacity style={styles.button} onPress={() => start(4)}>
  66. <Text style={styles.buttonText}>Step 4</Text>
  67. </TouchableOpacity>
  68. </TourGuideZone>
  69. <TouchableOpacity style={styles.button} onPress={() => start(2)}>
  70. <Text style={styles.buttonText}>Step 2</Text>
  71. </TouchableOpacity>
  72. <TouchableOpacity style={styles.button} onPress={stop}>
  73. <Text style={styles.buttonText}>Stop</Text>
  74. </TouchableOpacity>
  75. <TourGuideZone
  76. zone={1}
  77. shape='circle'
  78. text={'With animated SVG morphing with awesome flubber 🍮💯'}
  79. >
  80. <Image source={{ uri }} style={styles.profilePhoto} ></Image>
  81. </TourGuideZone>
  82. </View>
  83. <View style={styles.row}>
  84. <TourGuideZone zone={4} shape={'circle'}>
  85. <Ionicons name='ios-contact' {...iconProps} ></Ionicons>
  86. </TourGuideZone>
  87. <Ionicons name='ios-chatbubbles' {...iconProps} ></Ionicons>
  88. <Ionicons name='ios-globe' {...iconProps} ></Ionicons>
  89. <TourGuideZone zone={5}>
  90. <Ionicons name='ios-navigate' {...iconProps} ></Ionicons>
  91. </TourGuideZone>
  92. <TourGuideZone zone={6} shape={'circle'}>
  93. <Ionicons name='ios-rainy' {...iconProps} ></Ionicons>
  94. </TourGuideZone>
  95. <TourGuideZoneByPosition
  96. zone={7}
  97. shape={'circle'}
  98. isTourGuide
  99. bottom={30}
  100. left={35}
  101. width={300}
  102. height={300}
  103. ></TourGuideZoneByPosition>
  104. </View>
  105. </View>
  106. )
  107. }

TourGuide props:

  1. interface TourGuideZoneProps {
  2. zone: number // A positive number indicating the order of the step in the entire walkthrough.
  3. tourKey?: string // A string indicating which tour the zone belongs to
  4. isTourGuide?: boolean // return children without wrapping id false
  5. text?: string // text in tooltip
  6. shape?: Shape // which shape
  7. maskOffset?: number // offset around zone
  8. borderRadius?: number // round corner when rectangle
  9. keepTooltipPosition?: boolean
  10. tooltipBottomOffset?: number
  11. children: React.ReactNode
  12. }
  13. type Shape = 'circle' | 'rectangle' | 'circle_and_keep' | 'rectangle_and_keep'
  14. export interface TourGuideProviderProps {
  15. tooltipComponent?: React.ComponentType<TooltipProps>
  16. tooltipStyle?: StyleProp<ViewStyle>
  17. labels?: Labels
  18. startAtMount?: boolean | string // start at mount, boolean for single tours, string for multiple tours
  19. androidStatusBarVisible?: boolean
  20. backdropColor?: string
  21. verticalOffset?: number
  22. wrapperStyle?: StyleProp<ViewStyle>
  23. maskOffset?: number
  24. borderRadius?: number
  25. animationDuration?: number
  26. children: React.ReactNode
  27. dismissOnPress?: boolean
  28. preventOutsideInteraction?:boolean
  29. }
  30. interface TooltipProps {
  31. isFirstStep?: boolean
  32. isLastStep?: boolean
  33. currentStep: Step
  34. labels?: Labels
  35. handleNext?(): void
  36. handlePrev?(): void
  37. handleStop?(): void
  38. }
  39. interface Labels {
  40. skip?: string
  41. previous?: string
  42. next?: string
  43. finish?: string
  44. }

In order to start the tutorial, you can call the start function from useTourGuideController hook:

  1. function HomeScreen() {
  2. const { start } = useTourGuideController()
  3. React.useEffect(() => {
  4. start()
  5. }, [])
  6. render() {
  7. // ...
  8. }
  9. }
  10. export default HomeScreen

If you are looking for a working example, please check out this link.

Using Multiple Tours

If you’d like to have multiple tours (different pages, differnt user types, etc) you can pass in a tourKey to useTourGuideController to create a tour that is keyed to that tourKey. Important If you use a keyed tour, in order for the TourGuideZone components to register correctly you must do one of two things. Either (1) pass along the tourKey to the TourGuideZone components, or (2) extract the TourGuideZone components from the hook itself

(1) If you want to pass along the tourKey

  1. import { TourGuideZone, useTourGuideController } from 'rn-tourguide'
  2. const {
  3. canStart, // <-- These are all keyed to the tourKey
  4. start, // <-- These are all keyed to the tourKey
  5. stop, // <-- These are all keyed to the tourKey
  6. eventEmitter, // <-- These are all keyed to the tourKey
  7. tourKey, // <-- Extract the tourKey
  8. } = useTourGuideController('results')
  9. return (
  10. <TourGuideZone
  11. tourKey={tourKey} // <-- Pass in the tourKey
  12. zone={2}
  13. text='Check on your results'
  14. >
  15. {/** Children */}
  16. </TourGuideZone>
  17. )

Or (2) if you want to extract the components directly from the hook

  1. import { useTourGuideController } from 'rn-tourguide'
  2. const { canStart, start, stop, TourGuideZone } =
  3. useTourGuideController('results')
  4. return (
  5. <TourGuideZone // <-- No need to pass in the tourKey
  6. zone={2}
  7. text='Check on your results'
  8. >
  9. {/** Children */}
  10. </TourGuideZone>
  11. )

If you use multiple tours and would like to use the startAtMount prop on the TourGuideProvider component, then pass in the string of the tour you’d like to start

Custom tooltip component

You can customize the tooltip by passing a component to the copilot HOC maker. If you are looking for an example tooltip component, take a look at the default tooltip implementation.

  1. const TooltipComponent = ({
  2. isFirstStep,
  3. isLastStep,
  4. handleNext,
  5. handlePrev,
  6. handleStop,
  7. currentStep,
  8. }) => (
  9. // ...
  10. );
  11. <TourGuideProvider {...{tooltipComponent: TooltipComponent}}>
  12. // ...
  13. </TourGuideProvider>

Custom tooltip styling

You can customize tooltips style:

  1. const style = {
  2. backgroundColor: '#9FA8DA',
  3. borderRadius: 10,
  4. paddingTop: 5,
  5. }
  6. <TourGuideProvider {...{ tooltipStyle: style }}>
  7. // ...
  8. </TourGuideProvider>

Custom mask color

You can customize the mask color - default is rgba(0, 0, 0, 0.4), by passing a color string to the copilot HOC maker.

  1. <TourGuideProvider {...{ backdropColor: 'rgba(50, 50, 100, 0.9)' }}>
  2. // ...
  3. </TourGuideProvider>

Custom labels (for i18n)

You can localize labels:

  1. <TourGuideProvider
  2. {...{
  3. labels: {
  4. previous: 'Vorheriger',
  5. next: 'Nächster',
  6. skip: 'Überspringen',
  7. finish: 'Beenden',
  8. },
  9. }}
  10. >
  11. // ...
  12. </TourGuideProvider>

Listening to the events

Along with start(), useTourGuideController passes copilotEvents function to the component to help you with tracking of tutorial progress. It utilizes mitt under the hood, you can see how full API there.

List of available events is:

  • start — Copilot tutorial has started.
  • stop — Copilot tutorial has ended or skipped.
  • stepChange — Next step is triggered. Passes Step instance as event handler argument.

Prevent Outside Interaction

Sometimes you need to prevent users to interact with app while tour is shown, in such case preventOutsideInteraction prop is up for you.

default: false

  1. <TourGuideProvider preventOutsideInteraction>
  2. <AppContent ></AppContent>
  3. </TourGuideProvider>

Contributing

Issues and Pull Requests are always welcome.

Hire an expert!

Looking for a ReactNative freelance expert with more than 14 years experience? Contact me from my website!

License