{"id":13581491,"url":"https://github.com/xcarpentier/rn-tourguide","last_synced_at":"2025-05-14T02:04:56.760Z","repository":{"id":38195004,"uuid":"266895392","full_name":"xcarpentier/rn-tourguide","owner":"xcarpentier","description":"🚩Make an interactive step by step tour guide for your react-native app (a rewrite of react-native-copilot)","archived":false,"fork":false,"pushed_at":"2024-10-30T09:50:59.000Z","size":3409,"stargazers_count":798,"open_issues_count":62,"forks_count":225,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-05-09T10:04:14.411Z","etag":null,"topics":["animation","expo","flubber","mask-svg-path","morphing","react-native","rn-tourguide","svg-animations","tooltip","tourguide","tutorial","web"],"latest_commit_sha":null,"homepage":"https://xcarpentier.github.io/rn-tourguide/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xcarpentier.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"xcarpentier","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2020-05-25T22:50:59.000Z","updated_at":"2025-05-01T09:05:41.000Z","dependencies_parsed_at":"2023-02-15T05:32:20.854Z","dependency_job_id":"6b0b61c6-c17f-45aa-b845-72cacbc355ce","html_url":"https://github.com/xcarpentier/rn-tourguide","commit_stats":{"total_commits":318,"total_committers":44,"mean_commits":"7.2272727272727275","dds":0.5566037735849056,"last_synced_commit":"1de7e86505bb7b35653ecbeedcf67afb073d1bf8"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xcarpentier%2Frn-tourguide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xcarpentier%2Frn-tourguide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xcarpentier%2Frn-tourguide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xcarpentier%2Frn-tourguide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xcarpentier","download_url":"https://codeload.github.com/xcarpentier/rn-tourguide/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253418858,"owners_count":21905330,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animation","expo","flubber","mask-svg-path","morphing","react-native","rn-tourguide","svg-animations","tooltip","tourguide","tutorial","web"],"created_at":"2024-08-01T15:02:03.354Z","updated_at":"2025-05-14T02:04:56.734Z","avatar_url":"https://github.com/xcarpentier.png","language":"TypeScript","funding_links":["https://github.com/sponsors/xcarpentier"],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eRN-TourGuide\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  A flexible \u003cstrong\u003etourguide\u003c/strong\u003e for your react native app!\n  \u003cbr/\u003e\u003csmall\u003e🎉 Webable 🎉\u003c/small\u003e\n  \u003cbr/\u003e\u003csmall\u003e(a rewriting of react-native-copilot)\u003c/small\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"250\" src=\"https://www.dropbox.com/s/9heua3qgd66125k/rn-tourguide.gif?dl=0\u0026raw=1\" alt=\"RN Tourguide\" /\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://xcarpentier.github.io/rn-tourguide/\"\u003e\n      🎉DEMO WEB 🎉\n    \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cp align=\"center\"\u003e\n    \u003ca href=\"https://www.npmjs.com/package/rn-tourguide\"\u003e\n      \u003cimg alt=\"npm downloads\" src=\"https://img.shields.io/npm/dm/rn-tourguide.svg\"/\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://www.npmjs.com/package/rn-tourguide\"\u003e\n      \u003cimg src=\"https://img.shields.io/npm/v/rn-tourguide.svg\" alt=\"NPM Version\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"http://reactnative.gallery/xcarpentier/rn-tourguide\"\u003e\n      \u003cimg src=\"https://img.shields.io/badge/reactnative.gallery-%F0%9F%8E%AC-green.svg\"/\u003e\u003c/a\u003e\n    \u003c/a\u003e\n    \u003ca href=\"#hire-an-expert\"\u003e\n      \u003cimg src=\"https://img.shields.io/badge/%F0%9F%92%AA-hire%20an%20expert-brightgreen\"/\u003e\n    \u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n## Installation\n\n```\nyarn add rn-tourguide\n```\n\n```\nyarn add react-native-svg\nreact-native link react-native-svg\n```\n\nIf you are using Expo:\n\n```\nexpo install react-native-svg\n```\n\n## Usage\n\n```tsx\nimport {\n  TourGuideProvider, // Main provider\n  TourGuideZone, // Main wrapper of highlight component\n  TourGuideZoneByPosition, // Component to use mask on overlay (ie, position absolute)\n  useTourGuideController, // hook to start, etc.\n} from 'rn-tourguide'\n\n// Add \u003cTourGuideProvider/\u003e at the root of you app!\nfunction App() {\n  return (\n// If you added a statusbar in Andoid set androidStatusBarVisible: true as well to avoid vertical position issues\n    \u003cTourGuideProvider {...{ borderRadius: 16 }}\u003e\n      \u003cAppContent /\u003e\n    \u003c/TourGuideProvider\u003e\n  )\n}\n\nconst AppContent = () =\u003e {\n  const iconProps = { size: 40, color: '#888' }\n\n  // Use Hooks to control!\n  const {\n    canStart, // a boolean indicate if you can start tour guide\n    start, // a function to start the tourguide\n    stop, // a function  to stopping it\n    eventEmitter, // an object for listening some events\n  } = useTourGuideController()\n\n  // Can start at mount 🎉\n  // you need to wait until everything is registered 😁\n  React.useEffect(() =\u003e {\n    if (canStart) {\n      // 👈 test if you can start otherwise nothing will happen\n      start()\n    }\n  }, [canStart]) // 👈 don't miss it!\n\n  const handleOnStart = () =\u003e console.log('start')\n  const handleOnStop = () =\u003e console.log('stop')\n  const handleOnStepChange = () =\u003e console.log(`stepChange`)\n\n  React.useEffect(() =\u003e {\n    eventEmitter.on('start', handleOnStart)\n    eventEmitter.on('stop', handleOnStop)\n    eventEmitter.on('stepChange', handleOnStepChange)\n\n    return () =\u003e {\n      eventEmitter.off('start', handleOnStart)\n      eventEmitter.off('stop', handleOnStop)\n      eventEmitter.off('stepChange', handleOnStepChange)\n    }\n  }, [])\n\n  return (\n    \u003cView style={styles.container}\u003e\n      {/*\n\n          Use TourGuideZone only to wrap your component\n\n      */}\n      \u003cTourGuideZone\n        zone={2}\n        text={'A react-native-copilot remastered! 🎉'}\n        borderRadius={16}\n      \u003e\n        \u003cText style={styles.title}\u003e\n          {'Welcome to the demo of\\n\"rn-tourguide\"'}\n        \u003c/Text\u003e\n      \u003c/TourGuideZone\u003e\n      \u003cView style={styles.middleView}\u003e\n        \u003cTouchableOpacity style={styles.button} onPress={() =\u003e start()}\u003e\n          \u003cText style={styles.buttonText}\u003eSTART THE TUTORIAL!\u003c/Text\u003e\n        \u003c/TouchableOpacity\u003e\n\n        \u003cTourGuideZone zone={3} shape={'rectangle_and_keep'}\u003e\n          \u003cTouchableOpacity style={styles.button} onPress={() =\u003e start(4)}\u003e\n            \u003cText style={styles.buttonText}\u003eStep 4\u003c/Text\u003e\n          \u003c/TouchableOpacity\u003e\n        \u003c/TourGuideZone\u003e\n        \u003cTouchableOpacity style={styles.button} onPress={() =\u003e start(2)}\u003e\n          \u003cText style={styles.buttonText}\u003eStep 2\u003c/Text\u003e\n        \u003c/TouchableOpacity\u003e\n        \u003cTouchableOpacity style={styles.button} onPress={stop}\u003e\n          \u003cText style={styles.buttonText}\u003eStop\u003c/Text\u003e\n        \u003c/TouchableOpacity\u003e\n        \u003cTourGuideZone\n          zone={1}\n          shape='circle'\n          text={'With animated SVG morphing with awesome flubber 🍮💯'}\n        \u003e\n          \u003cImage source={{ uri }} style={styles.profilePhoto} /\u003e\n        \u003c/TourGuideZone\u003e\n      \u003c/View\u003e\n      \u003cView style={styles.row}\u003e\n        \u003cTourGuideZone zone={4} shape={'circle'}\u003e\n          \u003cIonicons name='ios-contact' {...iconProps} /\u003e\n        \u003c/TourGuideZone\u003e\n        \u003cIonicons name='ios-chatbubbles' {...iconProps} /\u003e\n        \u003cIonicons name='ios-globe' {...iconProps} /\u003e\n        \u003cTourGuideZone zone={5}\u003e\n          \u003cIonicons name='ios-navigate' {...iconProps} /\u003e\n        \u003c/TourGuideZone\u003e\n        \u003cTourGuideZone zone={6} shape={'circle'}\u003e\n          \u003cIonicons name='ios-rainy' {...iconProps} /\u003e\n        \u003c/TourGuideZone\u003e\n        \u003cTourGuideZoneByPosition\n          zone={7}\n          shape={'circle'}\n          isTourGuide\n          bottom={30}\n          left={35}\n          width={300}\n          height={300}\n        /\u003e\n      \u003c/View\u003e\n    \u003c/View\u003e\n  )\n}\n```\n\n`TourGuide` props:\n\n```ts\ninterface TourGuideZoneProps {\n  zone: number // A positive number indicating the order of the step in the entire walkthrough.\n  tourKey?: string // A string indicating which tour the zone belongs to\n  isTourGuide?: boolean // return children without wrapping id false\n  text?: string // text in tooltip\n  shape?: Shape // which shape\n  maskOffset?: number // offset around zone\n  borderRadius?: number // round corner when rectangle\n  keepTooltipPosition?: boolean\n  tooltipBottomOffset?: number\n  children: React.ReactNode\n}\n\ntype Shape = 'circle' | 'rectangle' | 'circle_and_keep' | 'rectangle_and_keep'\n\nexport interface TourGuideProviderProps {\n  tooltipComponent?: React.ComponentType\u003cTooltipProps\u003e\n  tooltipStyle?: StyleProp\u003cViewStyle\u003e\n  labels?: Labels\n  startAtMount?: boolean | string //  start at mount, boolean for single tours, string for multiple tours\n  androidStatusBarVisible?: boolean\n  backdropColor?: string\n  verticalOffset?: number\n  wrapperStyle?: StyleProp\u003cViewStyle\u003e\n  maskOffset?: number\n  borderRadius?: number\n  animationDuration?: number\n  children: React.ReactNode\n  dismissOnPress?: boolean\n  preventOutsideInteraction?:boolean\n}\n\ninterface TooltipProps {\n  isFirstStep?: boolean\n  isLastStep?: boolean\n  currentStep: Step\n  labels?: Labels\n  handleNext?(): void\n  handlePrev?(): void\n  handleStop?(): void\n}\n\ninterface Labels {\n  skip?: string\n  previous?: string\n  next?: string\n  finish?: string\n}\n```\n\nIn order to start the tutorial, you can call the `start` function from `useTourGuideController` hook:\n\n```js\nfunction HomeScreen() {\n  const { start } = useTourGuideController()\n\n  React.useEffect(() =\u003e {\n    start()\n  }, [])\n\n\n  render() {\n    // ...\n  }\n}\n\nexport default HomeScreen\n```\n\nIf you are looking for a working example, please check out [this link](https://github.com/xcarpentier/rn-tourguide/blob/master/App.tsx).\n\n## Using Multiple Tours\n\nIf 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\n\n(1) If you want to pass along the tourKey\n\n```ts\nimport { TourGuideZone, useTourGuideController } from 'rn-tourguide'\nconst {\n  canStart, // \u003c-- These are all keyed to the tourKey\n  start, // \u003c-- These are all keyed to the tourKey\n  stop, // \u003c-- These are all keyed to the tourKey\n  eventEmitter, // \u003c-- These are all keyed to the tourKey\n  tourKey, // \u003c-- Extract the tourKey\n} = useTourGuideController('results')\n\nreturn (\n  \u003cTourGuideZone\n    tourKey={tourKey} // \u003c-- Pass in the tourKey\n    zone={2}\n    text='Check on your results'\n  \u003e\n    {/** Children */}\n  \u003c/TourGuideZone\u003e\n)\n```\n\nOr (2) if you want to extract the components directly from the hook\n\n```ts\nimport { useTourGuideController } from 'rn-tourguide'\nconst { canStart, start, stop, TourGuideZone } =\n  useTourGuideController('results')\n\nreturn (\n  \u003cTourGuideZone // \u003c-- No need to pass in the tourKey\n    zone={2}\n    text='Check on your results'\n  \u003e\n    {/** Children */}\n  \u003c/TourGuideZone\u003e\n)\n```\n\nIf 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\n\n### Custom tooltip component\n\nYou 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](https://github.com/xcarpentier/rn-tourguide/blob/master/src/components/Tooltip.tsx).\n\n```js\nconst TooltipComponent = ({\n  isFirstStep,\n  isLastStep,\n  handleNext,\n  handlePrev,\n  handleStop,\n  currentStep,\n}) =\u003e (\n  // ...\n);\n\n\u003cTourGuideProvider {...{tooltipComponent: TooltipComponent}}\u003e\n// ...\n\u003c/TourGuideProvider\u003e\n```\n\n### Custom tooltip styling\n\nYou can customize tooltips style:\n\n```tsx\nconst style = {\n  backgroundColor: '#9FA8DA',\n  borderRadius: 10,\n  paddingTop: 5,\n}\n\n\u003cTourGuideProvider {...{ tooltipStyle: style }}\u003e\n// ...\n\u003c/TourGuideProvider\u003e\n```\n\n### Custom mask color\n\nYou can customize the mask color - default is `rgba(0, 0, 0, 0.4)`, by passing a color string to the `copilot` HOC maker.\n\n```tsx\n\u003cTourGuideProvider {...{ backdropColor: 'rgba(50, 50, 100, 0.9)' }}\u003e\n  // ...\n\u003c/TourGuideProvider\u003e\n```\n\n### Custom labels (for i18n)\n\nYou can localize labels:\n\n```tsx\n\u003cTourGuideProvider\n  {...{\n    labels: {\n      previous: 'Vorheriger',\n      next: 'Nächster',\n      skip: 'Überspringen',\n      finish: 'Beenden',\n    },\n  }}\n\u003e\n  // ...\n\u003c/TourGuideProvider\u003e\n```\n\n### Listening to the events\n\nAlong with `start()`, `useTourGuideController` passes `copilotEvents` function to the component to help you with tracking of tutorial progress. It utilizes [mitt](https://github.com/developit/mitt) under the hood, you can see how full API there.\n\nList of available events is:\n\n- `start` — Copilot tutorial has started.\n- `stop` — Copilot tutorial has ended or skipped.\n- `stepChange` — Next step is triggered. Passes [`Step`](https://github.com/mohebifar/react-native-copilot/blob/master/src/types.js#L2) instance as event handler argument.\n\n\n### Prevent Outside Interaction\n\nSometimes you need to prevent users to interact with app while tour is shown, in such case `preventOutsideInteraction` prop is up for you.\n\n```default: false```\n\n```jsx\n\u003cTourGuideProvider preventOutsideInteraction\u003e\n  \u003cAppContent /\u003e\n\u003c/TourGuideProvider\u003e\n```\n\n## Contributing\n\nIssues and Pull Requests are always welcome.\n\n## Hire an expert!\n\nLooking for a ReactNative freelance expert with more than 14 years experience? Contact me from my [website](https://xaviercarpentier.com)!\n\n## License\n\n- [MIT](LICENSE) © 2020 Xavier CARPENTIER SAS, https://xaviercarpentier.com.\n- [MIT](LICENSE) © 2017 OK GROW!, https://www.okgrow.com.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxcarpentier%2Frn-tourguide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxcarpentier%2Frn-tourguide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxcarpentier%2Frn-tourguide/lists"}