• Stars
    star
    676
  • Rank 64,692 (Top 2 %)
  • Language
    TypeScript
  • License
    Other
  • Created about 4 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

🚩Make an interactive step by step tour guide for your react-native app (a rewrite of react-native-copilot)

RN-TourGuide

A flexible tourguide for your react native app!
🎉 Webable 🎉
(a rewriting of react-native-copilot)

RN Tourguide

🎉DEMO WEB 🎉

Installation

yarn add rn-tourguide
yarn add react-native-svg
react-native link react-native-svg

If you are using Expo:

expo install react-native-svg

Usage

import {
  TourGuideProvider, // Main provider
  TourGuideZone, // Main wrapper of highlight component
  TourGuideZoneByPosition, // Component to use mask on overlay (ie, position absolute)
  useTourGuideController, // hook to start, etc.
} from 'rn-tourguide'

// Add <TourGuideProvider/> at the root of you app!
function App() {
  return (
    <TourGuideProvider {...{ borderRadius: 16 }}>
      <AppContent />
    </TourGuideProvider>
  )
}

const AppContent = () => {
  const iconProps = { size: 40, color: '#888' }

  // Use Hooks to control!
  const {
    canStart, // a boolean indicate if you can start tour guide
    start, // a function to start the tourguide
    stop, // a function  to stopping it
    eventEmitter, // an object for listening some events
  } = useTourGuideController()

  // Can start at mount 🎉
  // you need to wait until everything is registered 😁
  React.useEffect(() => {
    if (canStart) {
      // 👈 test if you can start otherwise nothing will happen
      start()
    }
  }, [canStart]) // 👈 don't miss it!

  const handleOnStart = () => console.log('start')
  const handleOnStop = () => console.log('stop')
  const handleOnStepChange = () => console.log(`stepChange`)

  React.useEffect(() => {
    eventEmitter.on('start', handleOnStart)
    eventEmitter.on('stop', handleOnStop)
    eventEmitter.on('stepChange', handleOnStepChange)

    return () => {
      eventEmitter.off('start', handleOnStart)
      eventEmitter.off('stop', handleOnStop)
      eventEmitter.off('stepChange', handleOnStepChange)
    }
  }, [])

  return (
    <View style={styles.container}>
      {/*

          Use TourGuideZone only to wrap your component

      */}
      <TourGuideZone
        zone={2}
        text={'A react-native-copilot remastered! 🎉'}
        borderRadius={16}
      >
        <Text style={styles.title}>
          {'Welcome to the demo of\n"rn-tourguide"'}
        </Text>
      </TourGuideZone>
      <View style={styles.middleView}>
        <TouchableOpacity style={styles.button} onPress={() => start()}>
          <Text style={styles.buttonText}>START THE TUTORIAL!</Text>
        </TouchableOpacity>

        <TourGuideZone zone={3} shape={'rectangle_and_keep'}>
          <TouchableOpacity style={styles.button} onPress={() => start(4)}>
            <Text style={styles.buttonText}>Step 4</Text>
          </TouchableOpacity>
        </TourGuideZone>
        <TouchableOpacity style={styles.button} onPress={() => start(2)}>
          <Text style={styles.buttonText}>Step 2</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.button} onPress={stop}>
          <Text style={styles.buttonText}>Stop</Text>
        </TouchableOpacity>
        <TourGuideZone
          zone={1}
          shape='circle'
          text={'With animated SVG morphing with awesome flubber 🍮💯'}
        >
          <Image source={{ uri }} style={styles.profilePhoto} />
        </TourGuideZone>
      </View>
      <View style={styles.row}>
        <TourGuideZone zone={4} shape={'circle'}>
          <Ionicons name='ios-contact' {...iconProps} />
        </TourGuideZone>
        <Ionicons name='ios-chatbubbles' {...iconProps} />
        <Ionicons name='ios-globe' {...iconProps} />
        <TourGuideZone zone={5}>
          <Ionicons name='ios-navigate' {...iconProps} />
        </TourGuideZone>
        <TourGuideZone zone={6} shape={'circle'}>
          <Ionicons name='ios-rainy' {...iconProps} />
        </TourGuideZone>
        <TourGuideZoneByPosition
          zone={7}
          shape={'circle'}
          isTourGuide
          bottom={30}
          left={35}
          width={300}
          height={300}
        />
      </View>
    </View>
  )
}

TourGuide props:

interface TourGuideZoneProps {
  zone: number // A positive number indicating the order of the step in the entire walkthrough.
  tourKey?: string // A string indicating which tour the zone belongs to
  isTourGuide?: boolean // return children without wrapping id false
  text?: string // text in tooltip
  shape?: Shape // which shape
  maskOffset?: number // offset around zone
  borderRadius?: number // round corner when rectangle
  keepTooltipPosition?: boolean
  tooltipBottomOffset?: number
  children: React.ReactNode
}

type Shape = 'circle' | 'rectangle' | 'circle_and_keep' | 'rectangle_and_keep'

export interface TourGuideProviderProps {
  tooltipComponent?: React.ComponentType<TooltipProps>
  tooltipStyle?: StyleProp<ViewStyle>
  labels?: Labels
  startAtMount?: boolean | string //  start at mount, boolean for single tours, string for multiple tours
  androidStatusBarVisible?: boolean
  backdropColor?: string
  verticalOffset?: number
  wrapperStyle?: StyleProp<ViewStyle>
  maskOffset?: number
  borderRadius?: number
  animationDuration?: number
  children: React.ReactNode
  dismissOnPress?: boolean
  preventOutsideInteraction?:boolean
}

interface TooltipProps {
  isFirstStep?: boolean
  isLastStep?: boolean
  currentStep: Step
  labels?: Labels
  handleNext?(): void
  handlePrev?(): void
  handleStop?(): void
}

interface Labels {
  skip?: string
  previous?: string
  next?: string
  finish?: string
}

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

function HomeScreen() {
  const { start } = useTourGuideController()

  React.useEffect(() => {
    start()
  }, [])


  render() {
    // ...
  }
}

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

import { TourGuideZone, useTourGuideController } from 'rn-tourguide'
const {
  canStart, // <-- These are all keyed to the tourKey
  start, // <-- These are all keyed to the tourKey
  stop, // <-- These are all keyed to the tourKey
  eventEmitter, // <-- These are all keyed to the tourKey
  tourKey, // <-- Extract the tourKey
} = useTourGuideController('results')

return (
  <TourGuideZone
    tourKey={tourKey} // <-- Pass in the tourKey
    zone={2}
    text='Check on your results'
  >
    {/** Children */}
  </TourGuideZone>
)

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

import { useTourGuideController } from 'rn-tourguide'
const { canStart, start, stop, TourGuideZone } =
  useTourGuideController('results')

return (
  <TourGuideZone // <-- No need to pass in the tourKey
    zone={2}
    text='Check on your results'
  >
    {/** Children */}
  </TourGuideZone>
)

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.

const TooltipComponent = ({
  isFirstStep,
  isLastStep,
  handleNext,
  handlePrev,
  handleStop,
  currentStep,
}) => (
  // ...
);

<TourGuideProvider {...{tooltipComponent: TooltipComponent}}>
// ...
</TourGuideProvider>

Custom tooltip styling

You can customize tooltips style:

const style = {
  backgroundColor: '#9FA8DA',
  borderRadius: 10,
  paddingTop: 5,
}

<TourGuideProvider {...{ tooltipStyle: style }}>
// ...
</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.

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

Custom labels (for i18n)

You can localize labels:

<TourGuideProvider
  {...{
    labels: {
      previous: 'Vorheriger',
      next: 'Nächster',
      skip: 'Überspringen',
      finish: 'Beenden',
    },
  }}
>
  // ...
</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

<TourGuideProvider preventOutsideInteraction>
  <AppContent />
</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

More Repositories

1

react-native-country-picker-modal

🇦🇶 Country picker provides a modal allowing a user to select a country from a list. It display a flag next to each country name.
TypeScript
1,044
star
2

rn-pdf-reader-js

📄 PDF reader in JavaScript only for Expo - Android & iOS capable
TypeScript
375
star
3

react-native-suggester

🔎 React-Native package to decorate TextInput and get suggestions with good UX
TypeScript
56
star
4

react-native-slack-webhook

💬 Follow some activities (new user, payment, ...) from your app via Slack and this webhook lib
Objective-C
55
star
5

gifted-chat-web-demo

Gifted chat web demo
TypeScript
44
star
6

react-native-safe-image

Really light React-Native package to handle fallback when image is on error
TypeScript
27
star
7

rn-verifcode

🔢 React-Native component to input confirmation code for both Android and IOS
TypeScript
25
star
8

vitrine

🖼 vitrine: professional website and app showcase
TypeScript
18
star
9

clean-archi-boilerplate

clean-archi-boilerplate
TypeScript
9
star
10

rn-slideshow

🌁Slideshow with expo, theming, customizable footer, etc
TypeScript
7
star
11

react-redux-dispatch-async

🎸 react-redux hook & redux middleware to be able to wait for async actions with fixed defined suffixes
TypeScript
7
star
12

bs-react-native-gifted-chat

🏗💬Gifted Chat clone with Reason
JavaScript
6
star
13

redux-actions-ts

⚛️ Redux-Actions with TypeScript helper package
TypeScript
4
star
14

find-emoji

😀 A simple mobile app to find the appropriate emoji!
JavaScript
3
star
15

mooditor

Mooditor, simple in browser markdown editor.
JavaScript
2
star
16

react-redux-dispatch-async-example

Created with CodeSandbox
TypeScript
2
star
17

ng-uri

A wrapper for URI.js
JavaScript
2
star
18

lbpt-website

Site en python + django pour Google App Engine pour une association
Python
2
star
19

breizhcamp

1
star
20

fibo-premier

experimentation with rust programming
Rust
1
star
21

prezmash

PrezMash : France 2012 presidential with Play!
Java
1
star
22

developers.scalingo.com

API documentation of Scalingo's platform
HTML
1
star
23

newbie

newbie
HTML
1
star
24

ng-spa

Formation AngularJS et industrialisation pour les développeurs front end
1
star
25

expo-notif

JavaScript
1
star