Skip to content

Commit

Permalink
Simplify addStep API (#464)
Browse files Browse the repository at this point in the history
Our addStep logic was hacky and support varying number of arguments. Now it takes only one argument, either a hash of the step options or an existing Step object.
  • Loading branch information
RobbieTheWagner authored Jul 26, 2019
1 parent 2ff188c commit 4ab71f1
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 91 deletions.
5 changes: 3 additions & 2 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ <h3>Example</h3>
}
});

tour.addStep('creating', {
tour.addStep({
title: 'Creating a Shepherd Tour',
text: `Creating a Shepherd tour is easy. too!\
Just create a \`Tour\` instance, and add as many steps as you want.`,
Expand All @@ -71,7 +71,8 @@ <h3>Example</h3>
action: shepherd.next,
text: 'Next'
}
]
],
id: 'creating'
});

tour.start();
Expand Down
85 changes: 51 additions & 34 deletions demo/js/welcome.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
},
useModalOverlay: true
});
shepherd.addStep('welcome', {
shepherd.addStep({
text: '\n <p>\n Shepherd is a JavaScript library for guiding users through your app.\n It uses <a href="https://atomiks.github.io/tippyjs//" data-test-tippy-link>Tippy.js</a>,\n another open source library, to render dialogs for each tour "step".\n </p>\n \n <p>\n Among many things, Tippy makes sure your steps never end up off screen or cropped by an overflow.\n (Try resizing your browser to see what we mean.)\n </p>\n <p>\n It also offers a robust API for styling animations of steps\n as they enter and exit the view.\n </p>',
attachTo: {
element: '.hero-welcome',
Expand All @@ -44,9 +44,11 @@
{
action: shepherd.next,
text: 'Next'
}]
}
],
id: 'welcome'
});
shepherd.addStep('including', {
shepherd.addStep({
title: 'Including',
text: 'Including Shepherd is easy! Just include shepherd.js. The styles are bundled with the JS.',
attachTo: {
Expand All @@ -58,13 +60,15 @@
action: shepherd.back,
secondary: true,
text: 'Back'
}, {
},
{
action: shepherd.next,
text: 'Next'
}
]
],
id: 'including'
});
shepherd.addStep('creating', {
shepherd.addStep({
title: 'Creating a Shepherd Tour',
text: 'Creating a Shepherd tour is easy. too! ' + 'Just create a \`Tour\` instance, and add as many steps as you want.',
attachTo: {
Expand All @@ -81,51 +85,64 @@
action: shepherd.next,
text: 'Next'
}
]
],
id: 'creating'
});
shepherd.addStep('attaching', {
shepherd.addStep({
title: 'Attaching to Elements',
text: 'Your tour steps can target and attach to elements in DOM (like this step).',
attachTo: {
element: '.hero-example',
on: 'left'
},
buttons: [{
action: shepherd.back,
secondary: true,
text: 'Back'
}, {
action: shepherd.next,
text: 'Next'
}]
buttons: [
{
action: shepherd.back,
secondary: true,
text: 'Back'
},
{
action: shepherd.next,
text: 'Next'
}
],
id: 'attaching'
});
shepherd.addStep('centered-example', {
shepherd.addStep({
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 <a href="https://shepherdjs.dev/docs/">documentation</a> to learn more.',
buttons: [{
action: shepherd.back,
secondary: true,
text: 'Back'
}, {
action: shepherd.next,
text: 'Next'
}]
buttons: [
{
action: shepherd.back,
secondary: true,
text: 'Back'
},
{
action: shepherd.next,
text: 'Next'
}
],
id: 'centered-example'
});
shepherd.addStep('followup', {
shepherd.addStep({
title: 'Learn more',
text: 'Star Shepherd on Github so you remember it for your next project',
attachTo: {
element: '.hero-followup',
on: 'top'
},
buttons: [{
action: shepherd.back,
secondary: true,
text: 'Back'
}, {
action: shepherd.next,
text: 'Done'
}],
buttons: [
{
action: shepherd.back,
secondary: true,
text: 'Back'
},
{
action: shepherd.next,
text: 'Done'
}
],
id: 'followup',
modalOverlayOpeningPadding: '10'
});
return shepherd;
Expand Down
13 changes: 8 additions & 5 deletions docs-src/tutorials/02-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ to all this tour's steps by default.
Next, add your steps:

```javascript
tour.addStep('example-step', {
tour.addStep({
id: 'example-step',
text: 'This step is attached to the bottom of the <code>.example-css-selector</code> element.',
attachTo: {
element: '.example-css-selector',
Expand Down Expand Up @@ -113,7 +114,7 @@ dynamically generated `id` property -- which is also set on the `body` element a

##### Tour Methods

- `addStep(id, options)`: Creates a new Step object with options, and returns the `Step` instance it created. If you'd like you can also just pass an options hash which includes `id` as a key.
- `addStep(options)`: Creates a new Step object with options, and returns the `Step` instance it created.
If the options hash doesn't include an `id`, one will be generated.
You can also pass an existing `Step` instance rather than `options`, but note that Shepherd does not support a Step being attached to multiple Tours.
- `getById(id)`: Return a step with a specific id
Expand All @@ -136,7 +137,7 @@ You can also pass an existing `Step` instance rather than `options`, but note th
- `show`: Triggered with a hash of the `step` and the `previous` step
- `start`

Steps are instances of the Step object. They are generally created by the `Tour::addStep` method, which returns the `Step` instance it
Steps are instances of the Step object. They are generally created by the `Tour::addStep` method, which returns the `Step` instance it
created.

#### Steps
Expand Down Expand Up @@ -193,6 +194,7 @@ the step will execute. For example:
For example: `{selector: '.some-element', event: 'click'}`. It doesn't have to be an event inside the tour, it can be any event fired on any element on the page.
You can also always manually advance the Tour by calling `myTour.next()`.
- `highlightClass`: An extra class to apply to the `attachTo` element when it is highlighted (that is, when its step is active). You can then target that selector in your CSS.
- `id`: The string to use as the `id` for the step. If an id is not passed one will be generated.
- `showCancelLink`: Should a cancel "✕" be shown in the header of the step?
- `showOn`: A function that, when it returns true, will show the step. If it returns false, the step will be skipped.
- `scrollTo`: Should the element be scrolled to when this step is shown?
Expand Down Expand Up @@ -239,7 +241,7 @@ You can use the `advanceOn` option, or the Next button, to advance steps. If yo
complex user action, you can do the following:

```javascript
const myStep = myTour.addStep('my-step', options);
const myStep = myTour.addStep(options);

yourApp.on('some-event', () => {
if (myStep.isOpen()){
Expand Down Expand Up @@ -281,7 +283,8 @@ By default, Shepherd will generate and position an "arrow" element that points t
of a step. This is done by setting [Tippy's `arrow` option](https://atomiks.github.io/tippyjs/#arrow-option) to `true` on each ``Step.options.tippyOptions` &mdash; but you can disable the arrow manually by setting it to false:

```js
myTour.addStep('Step 1', {
myTour.addStep({
id: 'Step 1',
tippyOptions: {
arrow: false
}
Expand Down
1 change: 1 addition & 0 deletions src/js/step.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export class Step extends Evented {
* @param {string} options.classes A string of extra classes to add to the step's content element.
* @param {string} options.highlightClass An extra class to apply to the `attachTo` element when it is
* highlighted (that is, when its step is active). You can then target that selector in your CSS.
* @param {string} options.id The string to use as the `id` for the step.
* @param {Object} options.tippyOptions Extra [options to pass to tippy.js]{@link https://atomiks.github.io/tippyjs/#all-options}
* @param {boolean|Object} options.scrollTo Should the element be scrolled to when this step is shown? If true, uses the default `scrollIntoView`,
* if an object, passes that object as the params to `scrollIntoView` i.e. `{behavior: 'smooth', block: 'center'}`
Expand Down
28 changes: 6 additions & 22 deletions src/js/tour.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import tippy from 'tippy.js';
import { Evented } from './evented.js';
import { Step } from './step.jsx';
import autoBind from './utils/auto-bind';
import { isFunction, isNumber, isString, isUndefined } from './utils/type-check';
import { isFunction, isString } from './utils/type-check';
import { defaults as tooltipDefaults } from './utils/tooltip-defaults';
import { cleanupSteps } from './utils/cleanup';
import { normalizePrefix } from './utils/general';
Expand Down Expand Up @@ -81,25 +81,14 @@ export class Tour extends Evented {

/**
* Adds a new step to the tour
* @param {Object|Number|Step|String} arg1
* When arg2 is defined, arg1 can either be a string or number, to use for the `id` for the step
* When arg2 is undefined, arg1 is either an object containing step options or a Step instance
* @param {Object|Step} arg2 An object containing step options or a Step instance
* @param {Object|Step} options An object containing step options or a Step instance
* @return {Step} The newly added step
*/
addStep(arg1, arg2) {
let name, step;

// If we just have one argument, we can assume it is an object of step options, with an id
if (isUndefined(arg2)) {
step = arg1;
} else {
name = arg1;
step = arg2;
}
addStep(options) {
let step = options;

if (!(step instanceof Step)) {
step = this._setupStep(step, name);
step = this._setupStep(step);
} else {
step.tour = this;
}
Expand Down Expand Up @@ -303,15 +292,10 @@ export class Tour extends Evented {
/**
* Setup a new step object
* @param {Object} stepOptions The object describing the options for the step
* @param {String|Number} name The string or number to use as the `id` for the step
* @return {Step} The step instance
* @private
*/
_setupStep(stepOptions, name) {
if (isString(name) || isNumber(name)) {
stepOptions.id = name.toString();
}

_setupStep(stepOptions) {
stepOptions = Object.assign({}, this.options.defaultStepOptions, stepOptions);

return new Step(this, stepOptions);
Expand Down
9 changes: 3 additions & 6 deletions src/types/tour.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,10 @@ declare class Tour extends Evented {

/**
* Adds a new step to the tour
* @param arg1
* When arg2 is defined, arg1 can either be a string or number, to use for the `id` for the step
* When arg2 is undefined, arg1 is either an object containing step options or a Step instance
* @param arg2 An object containing step options or a Step instance
* @param options An object containing step options or a Step instance
* @return The newly added step
*/
addStep(arg1: Step | Step.StepOptions | number | string, arg2: Step | Step.StepOptions): Step;
addStep(options: Step | Step.StepOptions): Step;

/**
* Go to the previous step in the tour
Expand Down Expand Up @@ -130,4 +127,4 @@ declare class Tour extends Evented {
start(): void;
}

export = Tour;
export = Tour;
10 changes: 5 additions & 5 deletions test/cypress/utils/default-steps.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export default function(shepherd) {
return [
{
id: 'welcome',
options: {
text: `
<p>
Expand Down Expand Up @@ -33,11 +32,11 @@ export default function(shepherd) {
classes: 'shepherd-button-example-primary',
text: 'Next'
}
]
],
id: 'welcome'
}
},
{
id: 'including',
options: {
title: 'Including',
text: 'Including Shepherd is easy! Just include shepherd.js. The styles are bundled with the JS.',
Expand All @@ -56,11 +55,11 @@ export default function(shepherd) {
text: 'Next'
}
],
id: 'including',
classes: 'shepherd-step-element second-step'
}
},
{
id: 'example',
options: {
title: 'Example Shepherd',
text: 'Creating a Shepherd is easy too! Just create Shepherd and add as many steps as you want. Check out the <a href="https://shepherdjs.dev/docs/">documentation</a> to learn more.',
Expand All @@ -79,11 +78,11 @@ export default function(shepherd) {
text: 'Next'
}
],
id: 'example',
classes: 'shepherd-step-element third-step'
}
},
{
id: 'followup',
options: {
title: 'Learn more',
text: 'Star Shepherd on Github so you remember it for your next project',
Expand All @@ -102,6 +101,7 @@ export default function(shepherd) {
text: 'Done'
}
],
id: 'followup',
classes: 'shepherd-step-element fourth-step'
}
}
Expand Down
4 changes: 2 additions & 2 deletions test/cypress/utils/setup-tour.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ export default function(Shepherd, globalDefaults, customSteps, otherOptions) {
const steps = typeof customSteps === 'function' ? customSteps(shepherd) : defaultSteps(shepherd);

steps.forEach((step) => {
const { id, options } = step;
shepherd.addStep(id, options);
const { options } = step;
shepherd.addStep(options);
});

return shepherd;
Expand Down
5 changes: 3 additions & 2 deletions test/dummy/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ <h3>Example</h3>
}
});

tour.addStep('example', {
tour.addStep({
title: 'Example Shepherd',
text: 'Creating a Shepherd is easy too! Just create ...',
attachTo: {
Expand All @@ -62,7 +62,8 @@ <h3>Example</h3>
advanceOn: {
selector: '.docs-link',
event: 'click'
}
},
id: 'example'
});

tour.start();
Expand Down
Loading

0 comments on commit 4ab71f1

Please sign in to comment.