**[react-shepherd is built and maintained by Ship Shape. Contact us for web app consulting, development, and training for your project](https://shipshape.io/)**.
[](https://www.npmjs.com/package/react-shepherd)
[](https://github.com/shipshapecode/react-shepherd/actions?query=workflow%3ATest)
[](https://codeclimate.com/github/shipshapecode/react-shepherd/maintainability)
[](https://codeclimate.com/github/shipshapecode/react-shepherd/test_coverage)
[](https://standardjs.com)
This is a React wrapper for the [Shepherd](https://github.com/shipshapecode/shepherd), site tour, library.
It's mainly a wrapper around the Shepherd library that exposes the tour object and methods to the context object
that can be passed into props for dynamic interactivity.
## Install
```bash
npm install --save react-shepherd
```
## Usage
### Via Provider/Context
```jsx
import React, { Component, useContext } from "react";
import { ShepherdTour, ShepherdTourContext } from "react-shepherd";
import newSteps from "./steps";
const tourOptions = {
defaultStepOptions: {
cancelIcon: {
enabled: true,
},
},
useModalOverlay: true,
};
function Button() {
const tour = useContext(ShepherdTourContext);
return (
);
}
export default function App() {
return (
);
}
```
### Via Hook
```jsx
import React, { Component } from "react";
import { useShepherdTour } from "react-shepherd";
import newSteps from "./steps";
const tourOptions = {
defaultStepOptions: {
cancelIcon: {
enabled: true,
},
},
useModalOverlay: true,
};
export default function App() {
const tour = useShepherdTour({ tourOptions, steps: newSteps });
return (
);
}
```
## Configuration
The following configuration options for a tour can be set on the ShepherdTour to control the way that Shepherd is used. This is simply a POJO passed to Shepherd to use the options noted in the Shepherd Tour [options](https://shepherdjs.dev/docs/Tour.html).
**The only required option is `steps`, which is an array passed to the props.**
### tourOptions
`PropTypes.object`
Used to set the options that will be applied to each step by default. You can pass in any of the options that you can with Shepherd.
### steps
`PropTypes.array`
You must pass an array of steps to `steps`, something like this:
```js
const steps = [
{
id: 'intro',
attachTo: { element: '.first-element', on: 'bottom' },
beforeShowPromise: function () {
return new Promise(function (resolve) {
setTimeout(function () {
window.scrollTo(0, 0);
resolve();
}, 500);
});
},
buttons: [
{
classes: 'shepherd-button-secondary',
text: 'Exit',
type: 'cancel'
},
{
classes: 'shepherd-button-primary',
text: 'Back',
type: 'back'
},
{
classes: 'shepherd-button-primary',
text: 'Next',
type: 'next'
}
],
classes: 'custom-class-name-1 custom-class-name-2',
highlightClass: 'highlight',
scrollTo: false,
cancelIcon: {
enabled: true,
},
title: 'Welcome to React-Shepherd!',
text: ['React-Shepherd is a JavaScript library for guiding users through your React app.'],
when: {
show: () => {
console.log('show step');
},
hide: () => {
console.log('hide step');
}
}
},
// ...
];
```
## Steps
The options are the same as Shepherd [options](https://shepherdjs.dev/docs/Step.html).
## License
MIT
================================================
FILE: RELEASE.md
================================================
# Release
Releases are mostly automated using
[release-it](https://github.com/release-it/release-it/) and
[lerna-changelog](https://github.com/lerna/lerna-changelog/).
## Preparation
Since the majority of the actual release process is automated, the primary
remaining task prior to releasing is confirming that all pull requests that
have been merged since the last release have been labeled with the appropriate
`lerna-changelog` labels and the titles have been updated to ensure they
represent something that would make sense to our users. Some great information
on why this is important can be found at
[keepachangelog.com](https://keepachangelog.com/en/1.0.0/), but the overall
guiding principle here is that changelogs are for humans, not machines.
When reviewing merged PR's the labels to be used are:
* breaking - Used when the PR is considered a breaking change.
* enhancement - Used when the PR adds a new feature or enhancement.
* bug - Used when the PR fixes a bug included in a previous release.
* documentation - Used when the PR adds or updates documentation.
* internal - Used for internal changes that still require a mention in the
changelog/release notes.
## Release
Once the prep work is completed, the actual release is straight forward:
* First, ensure that you have installed your projects dependencies:
```
yarn install
```
* Second, ensure that you have obtained a
[GitHub personal access token][generate-token] with the `repo` scope (no
other permissions are needed). Make sure the token is available as the
`GITHUB_AUTH` environment variable.
For instance:
```bash
export GITHUB_AUTH=abc123def456
```
[generate-token]: https://github.com/settings/tokens/new?scopes=repo&description=GITHUB_AUTH+env+variable
* And last (but not least 😁) do your release.
```
npx release-it
```
[release-it](https://github.com/release-it/release-it/) manages the actual
release process. It will prompt you to to choose the version number after which
you will have the chance to hand tweak the changelog to be used (for the
`CHANGELOG.md` and GitHub release), then `release-it` continues on to tagging,
pushing the tag and commits, etc.
================================================
FILE: netlify.toml
================================================
[build]
command = "yarn build && cd packages/example && yarn build"
publish = "packages/example/dist"
================================================
FILE: package.json
================================================
{
"repository": {
"type": "git",
"url": "https://github.com/shipshapecode/react-shepherd.git"
},
"private": true,
"workspaces": [
"packages/**/*"
],
"devDependencies": {
"npm-run-all": "^4.1.5",
"release-it-yarn-workspaces": "^2.0.1"
},
"scripts": {
"build": "yarn workspace react-shepherd build",
"release": "yarn workspace react-shepherd release",
"start:lib": "yarn workspace react-shepherd start",
"start:site": "yarn workspace react-shepherd-example dev",
"start": "run-p start:*",
"lint": "yarn workspace react-shepherd lint",
"test": "yarn workspace react-shepherd test"
},
"release-it": {
"plugins": {
"release-it-yarn-workspaces": {
"workspaces": [
"packages/lib"
]
},
"release-it-lerna-changelog": {
"infile": "CHANGELOG.md",
"launchEditor": true
}
},
"git": {
"tagName": "v${version}"
},
"github": {
"release": true,
"tokenRef": "GITHUB_AUTH"
},
"npm": false
}
}
================================================
FILE: packages/example/.eslintrc.json
================================================
{
"extends": "next"
}
================================================
FILE: packages/example/README.md
================================================
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
================================================
FILE: packages/example/astro.config.mjs
================================================
import { defineConfig } from 'astro/config';
import react from "@astrojs/react";
// https://astro.build/config
export default defineConfig({
site: "https://shipshape-react-shepherd.netlify.app/",
integrations: [react()],
});
================================================
FILE: packages/example/jsconfig.json
================================================
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"@components/*": ["components/*"],
"@css/*": ["css/*"]
}
}
}
================================================
FILE: packages/example/package.json
================================================
{
"name": "react-shepherd-example",
"homepage": "https://shipshapecode.github.io/react-shepherd",
"version": "0.0.0",
"license": "MIT",
"private": true,
"dependencies": {
"@astrojs/prism": "^2.1.2",
"@astrojs/react": "^2.2.1",
"astro": "^2.10.7",
"react": "latest",
"react-dom": "latest",
"react-syntax-highlighter": "^15.5.0"
},
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
}
}
================================================
FILE: packages/example/src/components/home.astro
================================================
---
import { Prism } from '@astrojs/prism';
import Tour from './tour';
const installString = 'yarn add react-shepherd';
const componentSetupString = `
import React, { Component } from 'react'
import { useShepherdTour } from 'react-shepherd'
import newSteps from './steps'
const tourOptions = {
defaultStepOptions: {
cancelIcon: {
enabled: true
}
},
useModalOverlay: true
};
`;
const usageString = `
${componentSetupString}
function Button() {
const tour = useContext(ShepherdTourContext);
return (
);
}
class App extends Component {
render() {
return (
Shepherd is a JavaScript library for guiding users through your app.
It uses Popper.js,
another open source library, to render dialogs for each tour "step".
Among many things, Popper makes sure your steps never end up off screen or
cropped by an overflow. (Try resizing your browser to see what we mean.)
`
],
attachTo: { element: '.hero-welcome', on: 'bottom' },
classes: 'shepherd shepherd-welcome',
buttons: [
{
type: 'cancel',
classes: 'shepherd-button-secondary',
text: 'Exit'
},
{
type: 'next',
text: 'Next'
}
]
},
{
id: 'installation',
title: 'Installation',
text:
'Installation is simple, if you are using npm or yarn, just install like any other package.',
attachTo: { element: '.install-element', on: 'bottom' },
buttons: [
{
type: 'back',
classes: 'shepherd-button-secondary',
text: 'Back'
},
{
type: 'next',
text: 'Next'
}
]
},
{
id: 'usage',
title: 'Usage',
text: [
'To use the tour service, simply inject it into your application and use it like this example.'
],
attachTo: { element: '.usage-element', on: 'bottom' },
buttons: [
{
type: 'back',
classes: 'shepherd-button-secondary',
text: 'Back'
},
{
type: 'next',
text: 'Next'
}
]
},
{
id: 'centered-example',
title: 'Centered Shepherd Element',
text: `But attachment is totally optional!\n \
Without a target, a tour step will create an element that's centered within the view. \
Check out the documentation to learn more.`,
buttons: [
{
type: 'back',
classes: 'shepherd-button-secondary',
text: 'Back'
},
{
type: 'next',
text: 'Next'
}
]
},
{
id: 'followup',
title: 'Learn more',
text: 'Star Shepherd on Github so you remember it for your next project',
attachTo: { element: '.hero-followup', on: 'top' },
scrollTo: true,
buttons: [
{
type: 'back',
classes: 'shepherd-button-secondary',
text: 'Back'
},
{
type: 'next',
text: 'Done'
}
]
}
];
================================================
FILE: packages/lib/.eslintrc.js
================================================
module.exports = {
env: {
browser: true,
es2021: true,
jest: true,
},
extends: [
'plugin:react/recommended',
'airbnb',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: [
'react',
'@typescript-eslint',
],
rules: {
'no-param-reassign': ['error', { 'props': false }],
'react/function-component-definition': [2, { 'namedComponents': 'arrow-function' }],
'react/jsx-filename-extension': [1, { 'extensions': ['.tsx', '.ts'] }],
},
settings: {
'import/resolver': {
typescript: {},
},
}
};
================================================
FILE: packages/lib/CHANGELOG.md
================================================
## v4.3.0 (2024-01-21)
## v4.0.1 (2022-07-06)
#### :bug: Bug Fix
* `lib`
* [#637](https://github.com/shipshapecode/react-shepherd/pull/637) Add children field for React 18 ([@andersaamodt](https://github.com/andersaamodt))
#### Committers: 2
- Anders ([@andersaamodt](https://github.com/andersaamodt))
- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))
## v3.3.1 (2020-11-13)
#### :rocket: Enhancement
* [#439](https://github.com/shipshapecode/react-shepherd/pull/439) ✨ Shepmaster expose more types ([@chuckcarpenter](https://github.com/chuckcarpenter))
* [#391](https://github.com/shipshapecode/react-shepherd/pull/391) Manage secondary property on Step button ([@linsolas](https://github.com/linsolas))
#### :bug: Bug Fix
* [#528](https://github.com/shipshapecode/react-shepherd/pull/528) 🐛 Remove check for current action assignment ([@chuckcarpenter](https://github.com/chuckcarpenter))
#### Committers: 4
- Chuck Carpenter ([@chuckcarpenter](https://github.com/chuckcarpenter))
- Hakeem Almidan ([@Hakeemmidan](https://github.com/Hakeemmidan))
- Romain Linsolas ([@linsolas](https://github.com/linsolas))
- [@cyremur](https://github.com/cyremur)
## v2.0.0 (2019-08-29)
#### :bug: Bug Fix
* [#36](https://github.com/shipshapecode/react-shepherd/pull/36) Make custom button actions work, if specified ([@jmfirth](https://github.com/jmfirth))
* [#38](https://github.com/shipshapecode/react-shepherd/pull/38) Fix adding steps ([@jmfirth](https://github.com/jmfirth))
#### Committers: 1
- Justin Firth ([@jmfirth](https://github.com/jmfirth))
================================================
FILE: packages/lib/README.md
================================================
# react-shepherd
**[react-shepherd is built and maintained by Ship Shape. Contact us for web app consulting, development, and training for your project](https://shipshape.io/)**.
[](https://www.npmjs.com/package/react-shepherd)
[](https://github.com/shipshapecode/react-shepherd/actions?query=workflow%3ATest)
[](https://codeclimate.com/github/shipshapecode/react-shepherd/maintainability)
[](https://codeclimate.com/github/shipshapecode/react-shepherd/test_coverage)
[](https://standardjs.com)
This is a React wrapper for the [Shepherd](https://github.com/shipshapecode/shepherd), site tour, library.
It's mainly a wrapper around the Shepherd library that exposes the tour object and methods to the context object
that can be passed into props for dynamic interactivity.
## Install
```bash
npm install --save react-shepherd
```
## Usage
### Via Provider/Context
```jsx
import React, { Component, useContext } from "react";
import { ShepherdTour, ShepherdTourContext } from "react-shepherd";
import newSteps from "./steps";
const tourOptions = {
defaultStepOptions: {
cancelIcon: {
enabled: true,
},
},
useModalOverlay: true,
};
function Button() {
const tour = useContext(ShepherdTourContext);
return (
);
}
export default function App() {
return (
);
}
```
### Via Hook
```jsx
import React, { Component } from "react";
import { useShepherdTour } from "react-shepherd";
import newSteps from "./steps";
const tourOptions = {
defaultStepOptions: {
cancelIcon: {
enabled: true,
},
},
useModalOverlay: true,
};
export default function App() {
const tour = useShepherdTour({ tourOptions, steps: newSteps });
return (
);
}
```
## Configuration
The following configuration options for a tour can be set on the ShepherdTour to control the way that Shepherd is used. This is simply a POJO passed to Shepherd to use the options noted in the Shepherd Tour [options](https://shepherdjs.dev/docs/Tour.html).
**The only required option is `steps`, which is an array passed to the props.**
### tourOptions
`PropTypes.object`
Used to set the options that will be applied to each step by default. You can pass in any of the options that you can with Shepherd.
### steps
`PropTypes.array`
You must pass an array of steps to `steps`, something like this:
```js
const steps = [
{
id: 'intro',
attachTo: { element: '.first-element', on: 'bottom' },
beforeShowPromise: function () {
return new Promise(function (resolve) {
setTimeout(function () {
window.scrollTo(0, 0);
resolve();
}, 500);
});
},
buttons: [
{
classes: 'shepherd-button-secondary',
text: 'Exit',
type: 'cancel'
},
{
classes: 'shepherd-button-primary',
text: 'Back',
type: 'back'
},
{
classes: 'shepherd-button-primary',
text: 'Next',
type: 'next'
}
],
classes: 'custom-class-name-1 custom-class-name-2',
highlightClass: 'highlight',
scrollTo: false,
cancelIcon: {
enabled: true,
},
title: 'Welcome to React-Shepherd!',
text: ['React-Shepherd is a JavaScript library for guiding users through your React app.'],
when: {
show: () => {
console.log('show step');
},
hide: () => {
console.log('hide step');
}
}
},
// ...
];
```
## Steps
The options are the same as Shepherd [options](https://shepherdjs.dev/docs/Step.html).
## License
MIT
================================================
FILE: packages/lib/jest.config.js
================================================
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
preset: 'ts-jest',
rootDir: 'src',
testEnvironment: 'jsdom',
};
================================================
FILE: packages/lib/package.json
================================================
{
"name": "react-shepherd",
"version": "4.3.0",
"description": "A React wrapper for the site tour library Shepherd",
"homepage": "https://react-shepherd.vercel.app/",
"repository": {
"type": "git",
"url": "https://github.com/shipshapecode/react-shepherd.git"
},
"license": "MIT",
"main": "dist/Shepherd.js",
"module": "dist/Shepherd.es.js",
"jsnext:main": "dist/Shepherd.es.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"prebuild": "tsc --project ./tsconfig-declarations.json",
"build": "rollup -c",
"predeploy": "cd example && yarn && yarn build",
"prepare": "install-peers",
"problems": "tsc --noEmit",
"release": "release-it",
"start": "rollup -c -w",
"test": "cross-env CI=1 jest",
"test:watch": "jest --watch",
"lint": "eslint src --ext js,jsx,ts,tsx --max-warnings 0",
"lint:ci": "TIMING=all yarn lint --format junit --output-file reports/junit/junit.xml",
"lint:fix": "yarn lint --fix"
},
"dependencies": {
"resize-observer-polyfill": "^1.5.1",
"shepherd.js": "^11.0.1"
},
"devDependencies": {
"@babel/core": "^7.5.4",
"@babel/plugin-external-helpers": "^7.2.0",
"@babel/plugin-proposal-class-properties": "^7.5.0",
"@babel/plugin-proposal-decorators": "^7.4.4",
"@babel/plugin-proposal-do-expressions": "^7.5.0",
"@babel/plugin-proposal-export-default-from": "^7.5.2",
"@babel/plugin-proposal-export-namespace-from": "^7.5.2",
"@babel/plugin-proposal-function-bind": "^7.2.0",
"@babel/plugin-proposal-function-sent": "^7.5.0",
"@babel/plugin-proposal-json-strings": "^7.2.0",
"@babel/plugin-proposal-logical-assignment-operators": "^7.2.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.4.4",
"@babel/plugin-proposal-numeric-separator": "^7.2.0",
"@babel/plugin-proposal-optional-chaining": "^7.2.0",
"@babel/plugin-proposal-pipeline-operator": "^7.5.0",
"@babel/plugin-proposal-throw-expressions": "^7.2.0",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/plugin-syntax-import-meta": "^7.2.0",
"@babel/preset-env": "^7.5.4",
"@babel/preset-react": "^7.0.0",
"@svgr/rollup": "^8.1.0",
"@testing-library/react": "^14.0.0",
"@types/jest": "^29.0.0",
"@types/node": "^18.0.3",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"@typescript-eslint/eslint-plugin": "^6.19.0",
"@typescript-eslint/parser": "^5.30.5",
"cross-env": "^7.0.0",
"eslint": "^7.32.0 || ^8.2.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-import-resolver-typescript": "^3.2.5",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.3.0",
"install-peers-cli": "^2.2.0",
"jest": "^28.1.2",
"jest-environment-jsdom": "^29.0.1",
"release-it": "^14.0.2",
"release-it-lerna-changelog": "^5.0.0",
"rollup": "^2.6.1",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-commonjs": "^10.0.1",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-peer-deps-external": "^2.2.0",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-typescript": "^1.0.1",
"rollup-plugin-url": "^3.0.0",
"ts-jest": "^28.0.5",
"tslib": "^2.0.1",
"typescript": "^4.7.4"
},
"peerDependencies": {
"react": "^17.0.2 || 18.x",
"react-dom": "^17.0.2 || 18.x"
},
"engines": {
"node": ">=16",
"npm": ">=7"
},
"publishConfig": {
"registry": "https://registry.npmjs.org"
}
}
================================================
FILE: packages/lib/rollup.config.js
================================================
import babel from 'rollup-plugin-babel';
import commonjs from 'rollup-plugin-commonjs';
import external from 'rollup-plugin-peer-deps-external';
import postcss from 'rollup-plugin-postcss';
import resolve from 'rollup-plugin-node-resolve';
import typescript from 'rollup-plugin-typescript';
import url from 'rollup-plugin-url';
import svgr from '@svgr/rollup';
import pkg from './package.json';
export default {
input: 'src/index.tsx',
output: [
{
file: pkg.main,
format: 'cjs',
sourcemap: true
},
{
file: pkg.module,
format: 'es',
sourcemap: true
}
],
plugins: [
typescript(),
external(),
postcss({
modules: true
}),
url(),
svgr(),
babel({
exclude: 'node_modules/**'
}),
resolve(),
commonjs()
]
};
================================================
FILE: packages/lib/src/__tests__/shepherd.test.tsx
================================================
import React, { useContext } from 'react';
import ResizeObserver from 'resize-observer-polyfill';
import { render, fireEvent } from '@testing-library/react';
import { ShepherdTour, ShepherdTourContext } from '..';
window.ResizeObserver = ResizeObserver;
const steps = [
{
id: 'welcome',
text: [
`
Shepherd is a JavaScript library for guiding users through your app.
It uses Tippy.js,
another open source library, to render dialogs for each tour "step".
`,
`
Among many things, Tippy makes sure your steps never end up off screen or cropped by an overflow.
Try resizing your browser to see what we mean.
`,
],
classes: 'shepherd shepherd-welcome',
buttons: [
{
type: 'cancel',
classes: 'shepherd-button-secondary',
text: 'Exit',
},
{
type: 'next',
text: 'Next',
},
],
},
];
const tourOptions = {
defaultStepOptions: {
cancelIcon: {
enabled: true,
},
},
useModalOverlay: true,
};
describe('', () => {
it('exists', () => {
expect(ShepherdTour).toBeTruthy();
});
it('renders the component and starts tour', async () => {
const Button = () => {
const tour = useContext(ShepherdTourContext);
return (
);
};
const TestApp = () => (
);
const container = render();
await fireEvent.click(container.getByText(/Start Tour/));
const cancelBtn = await container.findByText('Exit');
const nextBtn = await container.findByText('Next');
expect(cancelBtn).toBeTruthy();
expect(nextBtn).toBeTruthy();
});
});
================================================
FILE: packages/lib/src/index.tsx
================================================
import React, { FC, useMemo } from 'react';
import Shepherd from 'shepherd.js';
import Step from 'shepherd.js/src/types/step';
import Tour from 'shepherd.js/src/types/tour';
type StepType = 'back' | 'cancel' | 'next';
export interface ShepherdButtonWithType extends Step.StepOptionsButton {
type?: StepType;
}
export interface ShepherdOptionsWithType extends Step.StepOptions {
buttons?: ReadonlyArray;
}
interface ShepherdProps {
steps: Array;
tourOptions: Tour.TourOptions;
children: React.ReactNode;
}
const ShepherdTourContext = React.createContext(null);
const ShepherdTourContextConsumer = ShepherdTourContext.Consumer;
/**
* Take a set of steps and formats to use actions on the buttons in the current context
* @param {Array} steps
* @param {Array} tour
* @private
*/
const addSteps = (steps: Array, tour: Tour) => {
// Return nothing if there are no steps
if (!steps.length) {
return [];
}
const parsedStepsforAction = steps.map((step: Step.StepOptions): Step.StepOptions => {
const { buttons } = step;
if (buttons) {
step.buttons = buttons.map((button: ShepherdButtonWithType) => {
const {
action, classes, disabled, label, secondary, text, type,
} = button;
return {
action: type ? tour[type] : action,
classes,
disabled,
label,
secondary,
text,
type,
};
});
}
return step;
});
return parsedStepsforAction.forEach((step: any) => tour.addStep(step));
};
// for instances where Context can't be used or doesn't make sense
export const useShepherdTour = ({ tourOptions, steps }: Pick) => {
const tourObject = useMemo(() => {
const tourInstance = new Shepherd.Tour(tourOptions);
addSteps(steps, tourInstance);
return tourInstance;
}, [tourOptions, steps]);
return tourObject;
};
export const ShepherdTour: FC = ({ children, tourOptions, steps }) => {
const tourObject = useMemo(() => {
const tourInstance = new Shepherd.Tour(tourOptions);
addSteps(steps, tourInstance);
return tourInstance;
}, [tourOptions, steps]);
return (
{children}
);
};
export type { default as Step } from 'shepherd.js/src/types/step';
export type { default as Tour } from 'shepherd.js/src/types/tour';
export { ShepherdTourContextConsumer as TourMethods, ShepherdTourContext };
================================================
FILE: packages/lib/src/styles.css
================================================
/* add css styles here (optional) */
.test {
display: inline-block;
margin: 2em auto;
border: 2px solid #000;
font-size: 2em;
}
================================================
FILE: packages/lib/tsconfig-declarations.json
================================================
{
"extends": "./tsconfig.json",
"compilerOptions": {
"isolatedModules": false,
"noEmit": false,
"declaration": true,
"emitDeclarationOnly": true
}
}
================================================
FILE: packages/lib/tsconfig.json
================================================
{
"compilerOptions": {
"outDir": "./dist",
"jsx": "react",
"allowJs": true,
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true
},
"include": [
"./src/**/*"
]
}