react-joyride
Advanced tools
Comparing version 2.0.0 to 2.0.1
135
package.json
{ | ||
"name": "react-joyride", | ||
"version": "2.0.0", | ||
"description": "Create walkthroughs and guided tours for your apps", | ||
"version": "2.0.1", | ||
"description": "Create guided tours for your apps", | ||
"author": "Gil Barbara <gilbarbara@gmail.com>", | ||
@@ -28,4 +28,6 @@ "repository": { | ||
"lib", | ||
"src" | ||
"src", | ||
"types/*.ts" | ||
], | ||
"types": "./types/index.d.ts", | ||
"peerDependencies": { | ||
@@ -37,8 +39,8 @@ "react": "^0.14.0 || ^15.0.0 || ^16.0.0", | ||
"dependencies": { | ||
"deep-diff": "^1.0.1", | ||
"deepmerge": "^2.1.1", | ||
"deep-diff": "^1.0.2", | ||
"deepmerge": "^3.0.0", | ||
"exenv": "^1.2.2", | ||
"is-lite": "^0.2.0", | ||
"is-lite": "^0.2.2", | ||
"nested-property": "^0.0.7", | ||
"react-floater": "^0.5.5", | ||
"react-floater": "^0.6.2", | ||
"react-proptype-conditional-require": "^1.0.4", | ||
@@ -48,54 +50,69 @@ "scroll": "^2.0.3", | ||
"scrollparent": "^2.0.1", | ||
"tree-changes": "^0.3.2" | ||
"tree-changes": "^0.4.0" | ||
}, | ||
"devDependencies": { | ||
"babel-core": "^6.26.3", | ||
"babel-eslint": "^8.2.6", | ||
"babel-jest": "^23.4.2", | ||
"@babel/core": "^7.2.2", | ||
"@babel/plugin-proposal-class-properties": "^7.2.3", | ||
"@babel/plugin-proposal-decorators": "^7.2.3", | ||
"@babel/plugin-proposal-do-expressions": "^7.2.0", | ||
"@babel/plugin-proposal-export-default-from": "^7.2.0", | ||
"@babel/plugin-proposal-export-namespace-from": "^7.2.0", | ||
"@babel/plugin-proposal-function-sent": "^7.2.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.2.0", | ||
"@babel/plugin-proposal-numeric-separator": "^7.2.0", | ||
"@babel/plugin-proposal-optional-chaining": "^7.2.0", | ||
"@babel/plugin-proposal-pipeline-operator": "^7.2.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/plugin-transform-flow-strip-types": "^7.2.3", | ||
"@babel/plugin-transform-runtime": "^7.2.0", | ||
"@babel/preset-env": "^7.2.3", | ||
"@babel/preset-flow": "^7.0.0", | ||
"@babel/preset-react": "^7.0.0", | ||
"@types/react": "^16.7.18", | ||
"babel-core": "^7.0.0-bridge.0", | ||
"babel-eslint": "^10.0.1", | ||
"babel-jest": "^23.6.0", | ||
"babel-plugin-array-includes": "^2.0.3", | ||
"babel-plugin-external-helpers": "^6.22.0", | ||
"babel-plugin-transform-flow-strip-types": "^6.22.0", | ||
"babel-plugin-jsx-remove-data-test-id": "^1.2.1", | ||
"babel-plugin-transform-node-env-inline": "^0.4.3", | ||
"babel-plugin-transform-react-remove-prop-types": "^0.4.14", | ||
"babel-plugin-transform-runtime": "^6.23.0", | ||
"babel-preset-env": "^1.7.0", | ||
"babel-preset-react": "^6.24.1", | ||
"babel-preset-stage-1": "^6.24.1", | ||
"babel-plugin-transform-react-remove-prop-types": "^0.4.21", | ||
"bundlesize": "^0.17.0", | ||
"chalk": "^2.4.1", | ||
"cross-env": "^5.2.0", | ||
"date-fns": "^1.29.0", | ||
"enzyme": "^3.4.0", | ||
"enzyme-adapter-react-16": "^1.2.0", | ||
"eslint": "^5.3.0", | ||
"eslint-config-airbnb": "^17.0.0", | ||
"eslint-plugin-babel": "^5.1.0", | ||
"eslint-plugin-flowtype": "^2.50.0", | ||
"eslint-plugin-import": "^2.13.0", | ||
"eslint-plugin-jsx-a11y": "^6.1.1", | ||
"eslint-plugin-react": "^7.10.0", | ||
"flow-bin": "^0.76.0", | ||
"husky": "^0.14.3", | ||
"jest": "^23.4.2", | ||
"jest-chain": "^1.0.3", | ||
"date-fns": "^1.30.1", | ||
"dtslint": "^0.4.2", | ||
"enzyme": "^3.8.0", | ||
"enzyme-adapter-react-16": "^1.7.1", | ||
"eslint": "^5.11.0", | ||
"eslint-config-airbnb": "^17.1.0", | ||
"eslint-plugin-babel": "^5.3.0", | ||
"eslint-plugin-flowtype": "^3.2.0", | ||
"eslint-plugin-import": "^2.14.0", | ||
"eslint-plugin-jsx-a11y": "^6.1.2", | ||
"eslint-plugin-react": "^7.11.1", | ||
"flow-bin": "^0.89.0", | ||
"husky": "^1.2.1", | ||
"jest": "^23.6.0", | ||
"jest-chain": "^1.0.5", | ||
"jest-environment-jsdom-global": "^1.1.0", | ||
"jest-enzyme": "^6.0.3", | ||
"jest-extended": "^0.7.2", | ||
"jest-enzyme": "^7.0.1", | ||
"jest-extended": "^0.11.0", | ||
"jest-watch-typeahead": "^0.2.0", | ||
"prop-types": "^15.6.2", | ||
"react": "^16.4.2", | ||
"react-dom": "^16.4.2", | ||
"react": "^16.7.0", | ||
"react-dom": "^16.7.0", | ||
"rimraf": "^2.6.2", | ||
"rollup": "^0.62.0", | ||
"rollup-plugin-babel": "^3.0.7", | ||
"rollup-plugin-commonjs": "^9.1.4", | ||
"rollup-plugin-node-resolve": "^3.3.0" | ||
"rollup": "^0.68.2", | ||
"rollup-plugin-babel": "^4.1.0", | ||
"rollup-plugin-commonjs": "^9.2.0", | ||
"rollup-plugin-filesize": "^5.0.1", | ||
"rollup-plugin-node-resolve": "^4.0.0", | ||
"yargs": "^12.0.5" | ||
}, | ||
"scripts": { | ||
"build": "npm run clean && npm run build:cjs && npm run build:es", | ||
"build:cjs": "cross-env NODE_ENV=production npm run build:cjs:src && npm run build:cjs:constants", | ||
"build:cjs:src": "rollup -c -f cjs -o lib/index.js", | ||
"build:cjs:constants": "rollup -i src/constants/index.js -c -f cjs -o lib/constants.js", | ||
"build:es": "cross-env NODE_ENV=production npm run build:es:src && npm run build:es:constants", | ||
"build:es:src": "cross-env NODE_ENV=production rollup -c", | ||
"build:es:constants": "cross-env NODE_ENV=production rollup -i src/constants/index.js -c -o es/constants.js", | ||
"build": "cross-env NODE_ENV=production npm run clean && rollup -c", | ||
"watch": "cross-env NODE_ENV=production rollup -cw", | ||
@@ -105,7 +122,23 @@ "clean": "rimraf es && rimraf lib", | ||
"test": "jest --coverage", | ||
"test:watch": "jest --watch", | ||
"precommit": "node tools commits && npm run lint && npm test", | ||
"postmerge": "node tools update && npm update", | ||
"prepublishOnly": "npm run build" | ||
"test:watch": "jest --watch --verbose", | ||
"bundlesize": "bundlesize", | ||
"validate": "npm run lint && npm test && flow && npm run build && npm run bundlesize", | ||
"prepublishOnly": "npm run validate" | ||
}, | ||
"bundlesize": [ | ||
{ | ||
"path": "./es/index.js", | ||
"maxSize": "20 kB" | ||
}, | ||
{ | ||
"path": "./lib/index.js", | ||
"maxSize": "20 kB" | ||
} | ||
], | ||
"husky": { | ||
"hooks": { | ||
"post-merge": "node tools update", | ||
"pre-commit": "node tools upstream && npm run validate" | ||
} | ||
} | ||
} |
@@ -7,15 +7,17 @@ # React Joyride | ||
Create a tour for your app! | ||
Use it to showcase your app for new users! Or explain functionality of complex features! | ||
#### Create awesome tours for your app! | ||
#### View the demo [here](https://2zpjporp4p.codesandbox.io/) | ||
Showcase your app to new users or explain functionality of new features. | ||
You can edit the demo [here](https://codesandbox.io/s/2zpjporp4p) | ||
It uses [react-floater](https://github.com/gilbarbara/react-floater) for positioning and styling. | ||
And you can use your own components too! | ||
> If you are looking for the documentation for the old 1.x version, go [here](https://github.com/gilbarbara/react-joyride/tree/v1.11.4) | ||
**View the demo [here](https://2zpjporp4p.codesandbox.io/)** | ||
**Read the [docs](https://gilbarbara.gitbook.io/react-joyride/)** | ||
## Setup | ||
```bash | ||
npm i react-joyride@next | ||
npm i react-joyride | ||
``` | ||
@@ -25,7 +27,3 @@ | ||
Just set a `steps` array to the Joyride component and you're good to go! | ||
You can use your own component for the tooltip body or beacon, if you want. | ||
```js | ||
```jsx | ||
import Joyride from 'react-joyride'; | ||
@@ -35,13 +33,10 @@ | ||
state = { | ||
run: false, | ||
steps: [ | ||
{ | ||
target: '.my-first-step', | ||
content: 'This if my awesome feature!', | ||
placement: 'bottom', | ||
content: 'This is my awesome feature!', | ||
}, | ||
{ | ||
target: '.my-other-step', | ||
content: 'This if my awesome feature!', | ||
placement: 'bottom', | ||
content: 'This another awesome feature!', | ||
}, | ||
@@ -52,12 +47,4 @@ ... | ||
componentDidMount() { | ||
this.setState({ run: true }); | ||
} | ||
callback = (data) => { | ||
const { action, index, type } = data; | ||
}; | ||
render () { | ||
const { steps, run } = this.state; | ||
const { steps } = this.state; | ||
@@ -68,4 +55,2 @@ return ( | ||
steps={steps} | ||
run={run} | ||
callback={this.callback} | ||
... | ||
@@ -79,18 +64,1 @@ /> | ||
``` | ||
## Documentation | ||
[Props](docs/props.md) | ||
[Step](docs/step.md) | ||
[Styling](docs/styling.md) | ||
[Callback](docs/callback.md) | ||
[Constants](docs/constants.md) | ||
[Migration from 1.x](docs/migration.md) | ||
This library uses [react-floater](https://github.com/gilbarbara/react-floater) and [popper.js](https://github.com/FezVrasta/popper.js) for positioning and styling. | ||
@@ -12,27 +12,27 @@ import React from 'react'; | ||
const css = ` | ||
@keyframes joyride-beacon-inner { | ||
20% { | ||
opacity: 0.9; | ||
} | ||
90% { | ||
opacity: 0.7; | ||
} | ||
} | ||
@keyframes joyride-beacon-outer { | ||
0% { | ||
transform: scale(1); | ||
} | ||
45% { | ||
opacity: 0.7; | ||
transform: scale(0.75); | ||
} | ||
100% { | ||
opacity: 0.9; | ||
transform: scale(1); | ||
} | ||
} | ||
@keyframes joyride-beacon-inner { | ||
20% { | ||
opacity: 0.9; | ||
} | ||
90% { | ||
opacity: 0.7; | ||
} | ||
} | ||
@keyframes joyride-beacon-outer { | ||
0% { | ||
transform: scale(1); | ||
} | ||
45% { | ||
opacity: 0.7; | ||
transform: scale(0.75); | ||
} | ||
100% { | ||
opacity: 0.9; | ||
transform: scale(1); | ||
} | ||
} | ||
`; | ||
@@ -77,8 +77,4 @@ | ||
if (beaconComponent) { | ||
if (React.isValidElement(beaconComponent)) { | ||
component = React.cloneElement(beaconComponent, props); | ||
} | ||
else { | ||
component = beaconComponent(props); | ||
} | ||
const BeaconComponent = beaconComponent; | ||
component = <BeaconComponent {...props} />; | ||
} | ||
@@ -89,5 +85,6 @@ else { | ||
key="JoyrideBeacon" | ||
className="joyride-beacon" | ||
className="react-joyride__beacon" | ||
style={styles.beacon} | ||
type="button" | ||
data-test-id="button-beacon" | ||
{...props} | ||
@@ -94,0 +91,0 @@ > |
@@ -9,4 +9,4 @@ import React from 'react'; | ||
getElement, | ||
getScrollParent, | ||
getScrollTo, | ||
getScrollParent, | ||
hasCustomScrollParent, | ||
@@ -19,6 +19,3 @@ isFixed, | ||
import ACTIONS from '../constants/actions'; | ||
import EVENTS from '../constants/events'; | ||
import LIFECYCLE from '../constants/lifecycle'; | ||
import STATUS from '../constants/status'; | ||
import { ACTIONS, EVENTS, LIFECYCLE, STATUS } from '../constants'; | ||
@@ -31,8 +28,3 @@ import Step from './Step'; | ||
this.store = new Store({ | ||
...props, | ||
controlled: props.run && is.number(props.stepIndex), | ||
}); | ||
this.state = this.store.getState(); | ||
this.helpers = this.store.getHelpers(); | ||
this.state = this.initStore(); | ||
} | ||
@@ -52,5 +44,7 @@ | ||
disableScrolling: PropTypes.bool, | ||
disableScrollParentFix: PropTypes.bool, | ||
floaterProps: PropTypes.shape({ | ||
offset: PropTypes.number, | ||
}), | ||
getHelpers: PropTypes.func, | ||
hideBackButton: PropTypes.bool, | ||
@@ -81,2 +75,4 @@ locale: PropTypes.object, | ||
disableScrolling: false, | ||
disableScrollParentFix: false, | ||
getHelpers: () => {}, | ||
hideBackButton: false, | ||
@@ -96,22 +92,5 @@ run: true, | ||
const { | ||
debug, | ||
disableCloseOnEsc, | ||
run, | ||
steps, | ||
} = this.props; | ||
const { disableCloseOnEsc, debug, run, steps } = this.props; | ||
const { start } = this.store; | ||
log({ | ||
title: 'init', | ||
data: [ | ||
{ key: 'props', value: this.props }, | ||
{ key: 'state', value: this.state }, | ||
], | ||
debug, | ||
}); | ||
// Sync the store to this component state. | ||
this.store.addListener(this.syncState); | ||
if (validateSteps(steps, debug) && run) { | ||
@@ -127,11 +106,15 @@ start(); | ||
componentWillReceiveProps(nextProps) { | ||
componentDidUpdate(prevProps, prevState) { | ||
if (!canUseDOM) return; | ||
const { action, status } = this.state; | ||
const { steps, stepIndex } = this.props; | ||
const { debug, run, steps: nextSteps, stepIndex: nextStepIndex } = nextProps; | ||
const { setSteps, start, stop, update } = this.store; | ||
const diffProps = !isEqual(this.props, nextProps); | ||
const { changed } = treeChanges(this.props, nextProps); | ||
const { action, controlled, index, lifecycle, status } = this.state; | ||
const { debug, run, stepIndex, steps } = this.props; | ||
const { steps: prevSteps, stepIndex: prevStepIndex } = prevProps; | ||
const { setSteps, reset, start, stop, update } = this.store; | ||
const { changed: changedProps } = treeChanges(prevProps, this.props); | ||
const { changed, changedFrom, changedTo } = treeChanges(prevState, this.state); | ||
const diffProps = !isEqual(prevProps, this.props); | ||
const diffState = !isEqual(prevState, this.state); | ||
const step = getMergedStep(steps[index], this.props); | ||
if (diffProps) { | ||
@@ -141,4 +124,4 @@ log({ | ||
data: [ | ||
{ key: 'nextProps', value: nextProps }, | ||
{ key: 'props', value: this.props }, | ||
{ key: 'nextProps', value: this.props }, | ||
{ key: 'props', value: prevProps }, | ||
], | ||
@@ -148,21 +131,21 @@ debug, | ||
const stepsChanged = !isEqual(nextSteps, steps); | ||
const stepIndexChanged = is.number(nextStepIndex) && changed('stepIndex'); | ||
const stepsChanged = !isEqual(prevSteps, steps); | ||
const stepIndexChanged = is.number(stepIndex) && changedProps('stepIndex'); | ||
/* istanbul ignore else */ | ||
if (changed('run')) { | ||
if (run) { | ||
start(nextStepIndex); | ||
if (stepsChanged) { | ||
if (validateSteps(steps, debug)) { | ||
setSteps(steps); | ||
} | ||
else { | ||
stop(); | ||
console.warn('Steps are not valid', steps); //eslint-disable-line no-console | ||
} | ||
} | ||
if (stepsChanged) { | ||
if (validateSteps(nextSteps, debug)) { | ||
setSteps(nextSteps); | ||
/* istanbul ignore else */ | ||
if (changedProps('run')) { | ||
if (run) { | ||
start(stepIndex); | ||
} | ||
else { | ||
console.warn('Steps are not valid', nextSteps); //eslint-disable-line no-console | ||
stop(); | ||
} | ||
@@ -173,3 +156,3 @@ } | ||
if (stepIndexChanged) { | ||
let nextAction = stepIndex < nextStepIndex ? ACTIONS.NEXT : ACTIONS.PREV; | ||
let nextAction = prevStepIndex < stepIndex ? ACTIONS.NEXT : ACTIONS.PREV; | ||
@@ -183,3 +166,3 @@ if (action === ACTIONS.STOP) { | ||
action: action === ACTIONS.CLOSE ? ACTIONS.CLOSE : nextAction, | ||
index: nextStepIndex, | ||
index: stepIndex, | ||
lifecycle: LIFECYCLE.INIT, | ||
@@ -190,13 +173,3 @@ }); | ||
} | ||
} | ||
componentDidUpdate(prevProps, prevState) { | ||
if (!canUseDOM) return; | ||
const { index, lifecycle, status } = this.state; | ||
const { debug, steps } = this.props; | ||
const { changed, changedFrom, changedTo } = treeChanges(prevState, this.state); | ||
const diffState = !isEqual(prevState, this.state); | ||
let step = getMergedStep(steps[index], this.props); | ||
if (diffState) { | ||
@@ -213,24 +186,65 @@ log({ | ||
let currentIndex = index; | ||
const callbackData = { | ||
...this.state, | ||
index, | ||
step, | ||
}; | ||
const isAfterAction = changedTo('action', [ | ||
ACTIONS.NEXT, | ||
ACTIONS.PREV, | ||
ACTIONS.SKIP, | ||
ACTIONS.CLOSE, | ||
]); | ||
if (changed('status')) { | ||
let type = EVENTS.TOUR_STATUS; | ||
if (isAfterAction && changedTo('status', STATUS.PAUSED)) { | ||
const prevStep = getMergedStep(steps[prevState.index], this.props); | ||
if (changedTo('status', STATUS.FINISHED) || changedTo('status', STATUS.SKIPPED)) { | ||
type = EVENTS.TOUR_END; | ||
// Return the last step when the tour is finished | ||
step = getMergedStep(steps[prevState.index], this.props); | ||
currentIndex = prevState.index; | ||
this.callback({ | ||
...callbackData, | ||
index: prevState.index, | ||
lifecycle: LIFECYCLE.COMPLETE, | ||
step: prevStep, | ||
type: EVENTS.STEP_AFTER, | ||
}); | ||
} | ||
if (changedTo('status', [STATUS.FINISHED, STATUS.SKIPPED])) { | ||
const prevStep = getMergedStep(steps[prevState.index], this.props); | ||
if (!controlled) { | ||
this.callback({ | ||
...callbackData, | ||
index: prevState.index, | ||
lifecycle: LIFECYCLE.COMPLETE, | ||
step: prevStep, | ||
type: EVENTS.STEP_AFTER, | ||
}); | ||
} | ||
else if (changedFrom('status', STATUS.READY, STATUS.RUNNING)) { | ||
type = EVENTS.TOUR_START; | ||
} | ||
this.callback({ | ||
...this.state, | ||
index: currentIndex, | ||
step, | ||
type, | ||
...callbackData, | ||
type: EVENTS.TOUR_END, | ||
// Return the last step when the tour is finished | ||
step: prevStep, | ||
index: prevState.index, | ||
}); | ||
reset(); | ||
} | ||
else if (changedFrom('status', [STATUS.IDLE, STATUS.READY], STATUS.RUNNING)) { | ||
this.callback({ | ||
...callbackData, | ||
type: EVENTS.TOUR_START, | ||
}); | ||
} | ||
else if (changed('status')) { | ||
this.callback({ | ||
...callbackData, | ||
type: EVENTS.TOUR_STATUS, | ||
}); | ||
} | ||
else if (changedTo('action', ACTIONS.RESET)) { | ||
this.callback({ | ||
...callbackData, | ||
type: EVENTS.TOUR_STATUS, | ||
}); | ||
} | ||
@@ -244,7 +258,2 @@ if (step) { | ||
} | ||
if (changedTo('lifecycle', LIFECYCLE.INIT)) { | ||
delete this.beaconPopper; | ||
delete this.tooltipPopper; | ||
} | ||
} | ||
@@ -262,12 +271,41 @@ } | ||
initStore = () => { | ||
const { debug, getHelpers, run, stepIndex } = this.props; | ||
this.store = new Store({ | ||
...this.props, | ||
controlled: run && is.number(stepIndex), | ||
}); | ||
this.helpers = this.store.getHelpers(); | ||
const { addListener } = this.store; | ||
log({ | ||
title: 'init', | ||
data: [ | ||
{ key: 'props', value: this.props }, | ||
{ key: 'state', value: this.state }, | ||
], | ||
debug, | ||
}); | ||
// Sync the store to this component's state. | ||
addListener(this.syncState); | ||
getHelpers(this.helpers); | ||
return this.store.getState(); | ||
}; | ||
scrollToStep(prevState) { | ||
const { index, lifecycle, status } = this.state; | ||
const { debug, disableScrolling, scrollToFirstStep, scrollOffset, steps } = this.props; | ||
const { debug, disableScrolling, disableScrollParentFix, scrollToFirstStep, scrollOffset, steps } = this.props; | ||
const step = getMergedStep(steps[index], this.props); | ||
/* istanbul ignore else */ | ||
if (step) { | ||
const target = getElement(step.target); | ||
const shouldScroll = step | ||
&& !disableScrolling | ||
&& step.placement !== 'center' | ||
&& (!step.isFixed || !isFixed(target)) // fixed steps don't need to scroll | ||
@@ -278,5 +316,5 @@ && (prevState.lifecycle !== lifecycle && [LIFECYCLE.BEACON, LIFECYCLE.TOOLTIP].includes(lifecycle)) | ||
if (status === STATUS.RUNNING && shouldScroll) { | ||
const hasCustomScroll = hasCustomScrollParent(target); | ||
const scrollParent = getScrollParent(target); | ||
let scrollY = Math.floor(getScrollTo(target, scrollOffset)); | ||
const hasCustomScroll = hasCustomScrollParent(target, disableScrollParentFix); | ||
const scrollParent = getScrollParent(target, disableScrollParentFix); | ||
let scrollY = Math.floor(getScrollTo(target, scrollOffset, disableScrollParentFix)) || 0; | ||
@@ -293,5 +331,7 @@ log({ | ||
/* istanbul ignore else */ | ||
if (lifecycle === LIFECYCLE.BEACON && this.beaconPopper) { | ||
const { placement, popper } = this.beaconPopper; | ||
/* istanbul ignore else */ | ||
if (!['bottom'].includes(placement) && !hasCustomScroll) { | ||
@@ -304,3 +344,3 @@ scrollY = Math.floor(popper.top - scrollOffset); | ||
if (['top', 'right'].includes(placement) && !flipped && !hasCustomScroll) { | ||
if (['top', 'right', 'left'].includes(placement) && !flipped && !hasCustomScroll) { | ||
scrollY = Math.floor(popper.top - scrollOffset); | ||
@@ -313,3 +353,6 @@ } | ||
if (status === STATUS.RUNNING && shouldScroll && scrollY >= 0) { | ||
scrollY = scrollY >= 0 ? scrollY : 0; | ||
/* istanbul ignore else */ | ||
if (status === STATUS.RUNNING && shouldScroll) { | ||
scrollTo(scrollY, scrollParent); | ||
@@ -364,3 +407,3 @@ } | ||
getPopper = (popper, type) => { | ||
setPopper = (popper, type) => { | ||
if (type === 'wrapper') { | ||
@@ -378,3 +421,3 @@ this.beaconPopper = popper; | ||
const { index, status } = this.state; | ||
const { continuous, debug, disableScrolling, steps } = this.props; | ||
const { continuous, debug, steps } = this.props; | ||
const step = getMergedStep(steps[index], this.props); | ||
@@ -390,4 +433,3 @@ let output; | ||
debug={debug} | ||
disableScrolling={disableScrolling} | ||
getPopper={this.getPopper} | ||
setPopper={this.setPopper} | ||
helpers={this.helpers} | ||
@@ -401,3 +443,3 @@ step={step} | ||
return ( | ||
<div className="joyride"> | ||
<div className="react-joyride"> | ||
{output} | ||
@@ -404,0 +446,0 @@ </div> |
@@ -14,3 +14,3 @@ import React from 'react'; | ||
} from '../modules/dom'; | ||
import { getBrowser, isLegacy } from '../modules/helpers'; | ||
import { getBrowser, isLegacy, log } from '../modules/helpers'; | ||
@@ -21,3 +21,3 @@ import LIFECYCLE from '../constants/lifecycle'; | ||
export default class Overlay extends React.Component { | ||
export default class JoyrideOverlay extends React.Component { | ||
constructor(props) { | ||
@@ -34,4 +34,6 @@ super(props); | ||
static propTypes = { | ||
debug: PropTypes.bool.isRequired, | ||
disableOverlay: PropTypes.bool.isRequired, | ||
disableScrolling: PropTypes.bool.isRequired, | ||
disableScrollParentFix: PropTypes.bool.isRequired, | ||
lifecycle: PropTypes.string.isRequired, | ||
@@ -50,7 +52,19 @@ onClickOverlay: PropTypes.func.isRequired, | ||
componentDidMount() { | ||
const { disableScrolling, target } = this.props; | ||
const { debug, disableScrolling, disableScrollParentFix, target } = this.props; | ||
/* istanbul ignore else */ | ||
if (!disableScrolling) { | ||
const element = getElement(target); | ||
this.scrollParent = hasCustomScrollParent(element) ? getScrollParent(element) : document; | ||
this.scrollParent = getScrollParent(element, disableScrollParentFix); | ||
/* istanbul ignore else */ | ||
if (hasCustomScrollParent(element, true)) { | ||
log({ | ||
title: 'step has a custom scroll parent and can cause trouble with scrolling', | ||
data: [ | ||
{ key: 'parent', value: this.scrollParent }, | ||
], | ||
debug, | ||
}); | ||
} | ||
} | ||
@@ -61,6 +75,7 @@ | ||
componentWillReceiveProps(nextProps) { | ||
const { disableScrolling, lifecycle, spotlightClicks } = nextProps; | ||
const { changed, changedTo } = treeChanges(this.props, nextProps); | ||
componentDidUpdate(prevProps) { | ||
const { disableScrolling, lifecycle, spotlightClicks } = this.props; | ||
const { changed, changedTo } = treeChanges(prevProps, this.props); | ||
/* istanbul ignore else */ | ||
if (!disableScrolling) { | ||
@@ -97,2 +112,3 @@ if (changedTo('lifecycle', LIFECYCLE.TOOLTIP)) { | ||
/* istanbul ignore else */ | ||
if (!disableScrolling) { | ||
@@ -121,3 +137,2 @@ clearTimeout(this.scrollTimeout); | ||
const { isScrolling } = this.state; | ||
if (!isScrolling) { | ||
@@ -130,3 +145,2 @@ this.setState({ isScrolling: true, showSpotlight: false }); | ||
this.scrollTimeout = setTimeout(() => { | ||
clearTimeout(this.scrollTimeout); | ||
this.setState({ isScrolling: false, showSpotlight: true }); | ||
@@ -148,7 +162,7 @@ this.scrollParent.removeEventListener('scroll', this.handleScroll); | ||
const { showSpotlight } = this.state; | ||
const { spotlightClicks, spotlightPadding, styles, target } = this.props; | ||
const { disableScrollParentFix, spotlightClicks, spotlightPadding, styles, target } = this.props; | ||
const element = getElement(target); | ||
const elementRect = getClientRect(element); | ||
const isFixedTarget = isFixed(element); | ||
const top = getElementPosition(element, spotlightPadding); | ||
const top = getElementPosition(element, spotlightPadding, disableScrollParentFix); | ||
@@ -182,2 +196,9 @@ return { | ||
let baseStyles = styles.overlay; | ||
/* istanbul ignore else */ | ||
if (isLegacy()) { | ||
baseStyles = placement === 'center' ? styles.overlayLegacyCenter : styles.overlayLegacy; | ||
} | ||
const stylesOverlay = { | ||
@@ -187,3 +208,3 @@ cursor: disableOverlay ? 'default' : 'pointer', | ||
pointerEvents: mouseOverSpotlight ? 'none' : 'auto', | ||
...(isLegacy() ? styles.overlayLegacy : styles.overlay), | ||
...baseStyles, | ||
}; | ||
@@ -209,3 +230,3 @@ | ||
<div | ||
className="joyride-overlay" | ||
className="react-joyride__overlay" | ||
style={stylesOverlay} | ||
@@ -212,0 +233,0 @@ onClick={onClickOverlay} |
@@ -13,2 +13,4 @@ import React from 'react'; | ||
this.node = document.createElement('div'); | ||
/* istanbul ignore else */ | ||
if (props.id) { | ||
@@ -15,0 +17,0 @@ this.node.id = props.id; |
@@ -7,3 +7,3 @@ import React from 'react'; | ||
key="JoyrideSpotlight" | ||
className="joyride-spotlight" | ||
className="react-joyride__spotlight" | ||
style={styles} | ||
@@ -10,0 +10,0 @@ /> |
@@ -8,7 +8,6 @@ import React from 'react'; | ||
import ACTIONS from '../constants/actions'; | ||
import LIFECYCLE from '../constants/lifecycle'; | ||
import { ACTIONS, EVENTS, LIFECYCLE, STATUS } from '../constants'; | ||
import { getElement, isFixed } from '../modules/dom'; | ||
import { log } from '../modules/helpers'; | ||
import { getElement, isElementVisible, isFixed } from '../modules/dom'; | ||
import { log, hideBeacon } from '../modules/helpers'; | ||
import { setScope, removeScope } from '../modules/scope'; | ||
@@ -20,5 +19,3 @@ import { validateStep } from '../modules/step'; | ||
import Tooltip from './Tooltip/index'; | ||
import JoyridePortal from './Portal'; | ||
import EVENTS from '../constants/events'; | ||
import STATUS from '../constants/status'; | ||
import Portal from './Portal'; | ||
@@ -32,6 +29,6 @@ export default class JoyrideStep extends React.Component { | ||
debug: PropTypes.bool.isRequired, | ||
getPopper: PropTypes.func.isRequired, | ||
helpers: PropTypes.object.isRequired, | ||
index: PropTypes.number.isRequired, | ||
lifecycle: PropTypes.string.isRequired, | ||
setPopper: PropTypes.func.isRequired, | ||
size: PropTypes.number.isRequired, | ||
@@ -48,2 +45,4 @@ status: PropTypes.string.isRequired, | ||
disableOverlayClose: PropTypes.bool, | ||
disableScrolling: PropTypes.bool, | ||
disableScrollParentFix: PropTypes.bool, | ||
event: PropTypes.string, | ||
@@ -54,2 +53,4 @@ floaterProps: PropTypes.shape({ | ||
hideBackButton: PropTypes.bool, | ||
hideCloseButton: PropTypes.bool, | ||
hideFooter: PropTypes.bool, | ||
isFixed: PropTypes.bool, | ||
@@ -93,28 +94,11 @@ locale: PropTypes.object, | ||
componentWillReceiveProps(nextProps) { | ||
const { action, continuous, debug, index, lifecycle, step, update } = this.props; | ||
const { changed, changedFrom } = treeChanges(this.props, nextProps); | ||
const skipBeacon = continuous && action !== ACTIONS.CLOSE && (index > 0 || action === ACTIONS.PREV); | ||
if (changedFrom('lifecycle', LIFECYCLE.INIT, LIFECYCLE.READY)) { | ||
update({ lifecycle: step.disableBeacon || skipBeacon ? LIFECYCLE.TOOLTIP : LIFECYCLE.BEACON }); | ||
} | ||
if (changed('index')) { | ||
log({ | ||
title: `step:${lifecycle}`, | ||
data: [ | ||
{ key: 'props', value: this.props }, | ||
], | ||
debug, | ||
}); | ||
} | ||
} | ||
componentDidUpdate(prevProps) { | ||
const { action, callback, controlled, index, lifecycle, size, status, step, update } = this.props; | ||
const { action, callback, continuous, controlled, debug, index, lifecycle, size, status, step, update } = this.props; | ||
const { changed, changedTo, changedFrom } = treeChanges(prevProps, this.props); | ||
const state = { action, controlled, index, lifecycle, size, status }; | ||
const isAfterAction = [ | ||
const skipBeacon = continuous && action !== ACTIONS.CLOSE && (index > 0 || action === ACTIONS.PREV); | ||
const hasStoreChanged = changed('action') || changed('index') || changed('lifecycle') || changed('status'); | ||
const hasStarted = changedFrom('lifecycle', [LIFECYCLE.TOOLTIP, LIFECYCLE.INIT], LIFECYCLE.INIT); | ||
const isAfterAction = changedTo('action', [ | ||
ACTIONS.NEXT, | ||
@@ -124,7 +108,5 @@ ACTIONS.PREV, | ||
ACTIONS.CLOSE, | ||
].includes(action) && changed('action'); | ||
]); | ||
const hasChangedIndex = changed('index') && changedFrom('lifecycle', LIFECYCLE.TOOLTIP, LIFECYCLE.INIT); | ||
if (!changed('status') && (hasChangedIndex || (controlled && isAfterAction))) { | ||
if (isAfterAction && (hasStarted || controlled)) { | ||
callback({ | ||
@@ -140,7 +122,8 @@ ...state, | ||
// There's a step to use, but there's no target in the DOM | ||
if (step) { | ||
const hasRenderedTarget = !!getElement(step.target); | ||
if (hasStoreChanged && step) { | ||
const element = getElement(step.target); | ||
const hasRenderedTarget = !!element && isElementVisible(element); | ||
if (hasRenderedTarget) { | ||
if (changedFrom('status', STATUS.READY, STATUS.RUNNING) || changed('index')) { | ||
if (changedFrom('status', STATUS.READY, STATUS.RUNNING) || changedFrom('lifecycle', LIFECYCLE.INIT, LIFECYCLE.READY)) { | ||
callback({ | ||
@@ -153,4 +136,3 @@ ...state, | ||
} | ||
if (!hasRenderedTarget) { | ||
else { | ||
console.warn('Target not mounted', step); //eslint-disable-line no-console | ||
@@ -169,2 +151,16 @@ callback({ | ||
if (changedFrom('lifecycle', LIFECYCLE.INIT, LIFECYCLE.READY)) { | ||
update({ lifecycle: hideBeacon(step) || skipBeacon ? LIFECYCLE.TOOLTIP : LIFECYCLE.BEACON }); | ||
} | ||
if (changed('index')) { | ||
log({ | ||
title: `step:${lifecycle}`, | ||
data: [ | ||
{ key: 'props', value: this.props }, | ||
], | ||
debug, | ||
}); | ||
} | ||
/* istanbul ignore else */ | ||
@@ -189,7 +185,4 @@ if (changedTo('lifecycle', LIFECYCLE.BEACON)) { | ||
if (changedFrom('lifecycle', LIFECYCLE.TOOLTIP, LIFECYCLE.INIT)) { | ||
if (changedFrom('lifecycle', [LIFECYCLE.TOOLTIP, LIFECYCLE.INIT], LIFECYCLE.INIT)) { | ||
removeScope(); | ||
} | ||
if (changedTo('lifecycle', LIFECYCLE.INIT)) { | ||
delete this.beaconPopper; | ||
@@ -200,2 +193,6 @@ delete this.tooltipPopper; | ||
componentWillUnmount() { | ||
removeScope(); | ||
} | ||
/** | ||
@@ -229,3 +226,3 @@ * Beacon click/hover event listener | ||
setPopper = (popper, type) => { | ||
const { action, getPopper, update } = this.props; | ||
const { action, setPopper, update } = this.props; | ||
@@ -239,3 +236,3 @@ if (type === 'wrapper') { | ||
getPopper(popper, type); | ||
setPopper(popper, type); | ||
@@ -253,3 +250,3 @@ if (this.beaconPopper && this.tooltipPopper) { | ||
return !!(step.disableBeacon || lifecycle === LIFECYCLE.TOOLTIP); | ||
return !!(hideBeacon(step) || lifecycle === LIFECYCLE.TOOLTIP); | ||
} | ||
@@ -260,3 +257,2 @@ | ||
continuous, | ||
controlled, | ||
debug, | ||
@@ -276,10 +272,11 @@ helpers, | ||
return ( | ||
<div key={`JoyrideStep-${index}`} className="joyride-step"> | ||
<JoyridePortal> | ||
<div key={`JoyrideStep-${index}`} className="react-joyride__step"> | ||
<Portal id="react-joyride-portal"> | ||
<Overlay | ||
{...step} | ||
debug={debug} | ||
lifecycle={lifecycle} | ||
onClickOverlay={this.handleClickOverlay} | ||
/> | ||
</JoyridePortal> | ||
</Portal> | ||
<Floater | ||
@@ -289,8 +286,7 @@ component={( | ||
continuous={continuous} | ||
controlled={controlled} | ||
helpers={helpers} | ||
index={index} | ||
isLastStep={index + 1 === size} | ||
setTooltipRef={this.setTooltipRef} | ||
size={size} | ||
isLastStep={index + 1 === size} | ||
step={step} | ||
@@ -301,3 +297,3 @@ /> | ||
getPopper={this.setPopper} | ||
id={`react-joyride:${index}`} | ||
id={`react-joyride-step-${index}`} | ||
isPositioned={step.isFixed || isFixed(target)} | ||
@@ -304,0 +300,0 @@ open={this.open} |
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
const CloseBtn = ({ styles, ...props }) => { | ||
const JoyrideTooltipCloseBtn = ({ styles, ...props }) => { | ||
const { color, height, width, ...style } = styles; | ||
@@ -32,6 +32,6 @@ | ||
CloseBtn.propTypes = { | ||
JoyrideTooltipCloseBtn.propTypes = { | ||
styles: PropTypes.object.isRequired, | ||
}; | ||
export default CloseBtn; | ||
export default JoyrideTooltipCloseBtn; |
@@ -18,3 +18,13 @@ import React from 'react'; | ||
}) => { | ||
const { content, hideBackButton, locale, showProgress, showSkipButton, title, styles } = step; | ||
const { | ||
content, | ||
hideBackButton, | ||
hideCloseButton, | ||
hideFooter, | ||
locale, | ||
showProgress, | ||
showSkipButton, | ||
title, | ||
styles, | ||
} = step; | ||
const { back, close, last, next, skip } = locale; | ||
@@ -26,11 +36,6 @@ const output = { | ||
if (continuous) { | ||
if (isLastStep) { | ||
output.primary = last; | ||
} | ||
else { | ||
output.primary = next; | ||
} | ||
output.primary = isLastStep ? last : next; | ||
if (showProgress) { | ||
output.primary += ` (${index + 1}/${size})`; | ||
output.primary = <span>{output.primary} ({index + 1}/{size})</span>; | ||
} | ||
@@ -44,2 +49,3 @@ } | ||
type="button" | ||
data-test-id="button-skip" | ||
{...skipProps} | ||
@@ -57,2 +63,3 @@ > | ||
type="button" | ||
data-test-id="button-back" | ||
{...backProps} | ||
@@ -65,3 +72,9 @@ > | ||
output.close = (<CloseBtn {...closeProps} styles={styles.buttonClose} />); | ||
output.close = !hideCloseButton && ( | ||
<CloseBtn | ||
styles={styles.buttonClose} | ||
data-test-id="button-close" | ||
{...closeProps} | ||
/> | ||
); | ||
@@ -71,2 +84,3 @@ return ( | ||
key="JoyrideTooltip" | ||
className="react-joyride__tooltip" | ||
ref={setTooltipRef} | ||
@@ -84,13 +98,16 @@ style={styles.tooltip} | ||
</div> | ||
<div style={styles.tooltipFooter}> | ||
{output.skip} | ||
{output.back} | ||
<button | ||
style={styles.buttonNext} | ||
type="button" | ||
{...primaryProps} | ||
> | ||
{output.primary} | ||
</button> | ||
</div> | ||
{!hideFooter && ( | ||
<div style={styles.tooltipFooter}> | ||
{output.skip} | ||
{output.back} | ||
<button | ||
style={styles.buttonNext} | ||
type="button" | ||
data-test-id="button-primary" | ||
{...primaryProps} | ||
> | ||
{output.primary} | ||
</button> | ||
</div> | ||
)} | ||
</div> | ||
@@ -97,0 +114,0 @@ ); |
@@ -52,4 +52,4 @@ import React from 'react'; | ||
const { continuous, index, isLastStep, setTooltipRef, size, step } = this.props; | ||
const { content, locale, title, tooltipComponent } = step; | ||
const { back, close, last, next, skip } = locale; | ||
const { beaconComponent, tooltipComponent, ...cleanStep } = step; | ||
const { back, close, last, next, skip } = step.locale; | ||
let primaryText = continuous ? next : close; | ||
@@ -72,18 +72,12 @@ | ||
...buttonProps, | ||
content, | ||
continuous, | ||
index, | ||
isLastStep, | ||
locale, | ||
setTooltipRef, | ||
size, | ||
title, | ||
step: cleanStep, | ||
}; | ||
if (React.isValidElement(tooltipComponent)) { | ||
component = React.cloneElement(tooltipComponent, renderProps); | ||
} | ||
else { | ||
component = tooltipComponent(renderProps); | ||
} | ||
const TooltipComponent = tooltipComponent; | ||
component = <TooltipComponent {...renderProps} />; | ||
} | ||
@@ -90,0 +84,0 @@ else { |
@@ -6,7 +6,5 @@ export default { | ||
RESET: 'reset', | ||
RESTART: 'restart', | ||
PREV: 'prev', | ||
NEXT: 'next', | ||
GO: 'go', | ||
INDEX: 'index', | ||
CLOSE: 'close', | ||
@@ -13,0 +11,0 @@ SKIP: 'skip', |
@@ -6,3 +6,2 @@ export default { | ||
TOOLTIP: 'tooltip', | ||
TOOLTIP_CLOSE: 'close', | ||
STEP_AFTER: 'step:after', | ||
@@ -9,0 +8,0 @@ TOUR_END: 'tour:end', |
@@ -1,7 +0,4 @@ | ||
import ACTIONS from './actions'; | ||
import EVENTS from './events'; | ||
import LIFECYCLE from './lifecycle'; | ||
import STATUS from './status'; | ||
export { ACTIONS, EVENTS, LIFECYCLE, STATUS }; | ||
export default { ACTIONS, EVENTS, LIFECYCLE, STATUS }; | ||
export { default as ACTIONS } from './actions'; | ||
export { default as EVENTS } from './events'; | ||
export { default as LIFECYCLE } from './lifecycle'; | ||
export { default as STATUS } from './status'; |
import Joyride from './components'; | ||
export { default as ACTIONS } from './constants/actions'; | ||
export { default as EVENTS } from './constants/events'; | ||
export { default as LIFECYCLE } from './constants/lifecycle'; | ||
export { default as STATUS } from './constants/status'; | ||
export default Joyride; |
// @flow | ||
import scroll from 'scroll'; | ||
import scrollDoc from 'scroll-doc'; | ||
import getScrollParent from 'scrollparent'; | ||
import scrollParent from 'scrollparent'; | ||
export { getScrollParent }; | ||
/** | ||
@@ -38,2 +36,18 @@ * Find the bounding client rect | ||
/** | ||
* Find and return the target DOM element based on a step's 'target'. | ||
* | ||
* @private | ||
* @param {string|HTMLElement} element | ||
* | ||
* @returns {HTMLElement|null} | ||
*/ | ||
export function getElement(element: string | HTMLElement): ?HTMLElement { | ||
if (typeof element === 'string') { | ||
return element ? document.querySelector(element) : null; | ||
} | ||
return element; | ||
} | ||
/** | ||
* Find the bounding client rect relative to the parent | ||
@@ -69,2 +83,9 @@ * | ||
/** | ||
* Get computed style property | ||
* | ||
* @param {HTMLElement} el | ||
* | ||
* @returns {Object} | ||
*/ | ||
export function getStyleComputedProperty(el: HTMLElement): Object { | ||
@@ -78,9 +99,50 @@ if (!el || el.nodeType !== 1) { | ||
export function hasCustomScrollParent(element: ?HTMLElement): boolean { | ||
if (!element) { | ||
return false; | ||
/** | ||
* Get scroll parent with fix | ||
* | ||
* @param {HTMLElement} element | ||
* @param {boolean} skipFix | ||
* | ||
* @returns {*} | ||
*/ | ||
export function getScrollParent(element: HTMLElement, skipFix: boolean): HTMLElement { | ||
const parent = scrollParent(element); | ||
if (parent.isSameNode(scrollDoc())) { | ||
return scrollDoc(); | ||
} | ||
return getScrollParent(element) !== scrollDoc(); | ||
const hasScrolling = parent.scrollHeight > parent.offsetHeight; | ||
if (!hasScrolling && !skipFix) { | ||
parent.style.overflow = 'initial'; | ||
return scrollDoc(); | ||
} | ||
return parent; | ||
} | ||
/** | ||
* Check if the element has custom scroll parent | ||
* | ||
* @param {HTMLElement} element | ||
* @param {boolean} skipFix | ||
* | ||
* @returns {boolean} | ||
*/ | ||
export function hasCustomScrollParent(element: ?HTMLElement, skipFix: boolean): boolean { | ||
if (!element) return false; | ||
const parent = getScrollParent(element, skipFix); | ||
return !parent.isSameNode(scrollDoc()); | ||
} | ||
/** | ||
* Check if the element has custom offset parent | ||
* | ||
* @param {HTMLElement} element | ||
* | ||
* @returns {boolean} | ||
*/ | ||
export function hasCustomOffsetParent(element: HTMLElement): boolean { | ||
@@ -90,2 +152,35 @@ return element.offsetParent !== document.body; | ||
/** | ||
* Check if the element is visible | ||
* | ||
* @param {HTMLElement} element | ||
* | ||
* @returns {boolean} | ||
*/ | ||
export function isElementVisible(element: ?HTMLElement): boolean { | ||
if (!element) return false; | ||
let parentElement = element; | ||
while (parentElement) { | ||
if (parentElement === document.body) break; | ||
if (parentElement instanceof HTMLElement) { | ||
const { display, visibility } = getComputedStyle(parentElement); | ||
if (display === 'none' || visibility === 'hidden') { | ||
return false; | ||
} | ||
} | ||
parentElement = parentElement.parentNode; | ||
} | ||
return true; | ||
} | ||
/** | ||
* Check if the element is fixed | ||
* @param {HTMLElement} el | ||
* @returns {boolean} | ||
*/ | ||
export function isFixed(el: ?HTMLElement | Node): boolean { | ||
@@ -110,2 +205,22 @@ if (!el || !(el instanceof HTMLElement)) { | ||
/** | ||
* Find and return the target DOM element based on a step's 'target'. | ||
* | ||
* @private | ||
* @param {string|HTMLElement} element | ||
* @param {number} offset | ||
* @param {boolean} skipFix | ||
* | ||
* @returns {HTMLElement|undefined} | ||
*/ | ||
export function getElementPosition(element: HTMLElement, offset: number, skipFix: boolean): number { | ||
const elementRect = getClientRect(element); | ||
const parent = getScrollParent(element, skipFix); | ||
const hasScrollParent = hasCustomScrollParent(element, skipFix); | ||
const top = elementRect.top + (!hasScrollParent && !isFixed(element) ? parent.scrollTop : 0); | ||
return Math.floor(top - offset); | ||
} | ||
/** | ||
* Get the scrollTop position | ||
@@ -115,6 +230,7 @@ * | ||
* @param {number} offset | ||
* @param {boolean} skipFix | ||
* | ||
* @returns {number} | ||
*/ | ||
export function getScrollTo(element: HTMLElement, offset: number): number { | ||
export function getScrollTo(element: HTMLElement, offset: number, skipFix: boolean): number { | ||
if (!element) { | ||
@@ -124,6 +240,6 @@ return 0; | ||
const parent = getScrollParent(element); | ||
const parent = scrollParent(element); | ||
let top = element.offsetTop; | ||
if (hasCustomScrollParent(element) && !hasCustomOffsetParent(element)) { | ||
if (hasCustomScrollParent(element, skipFix) && !hasCustomOffsetParent(element)) { | ||
top -= parent.offsetTop; | ||
@@ -136,36 +252,7 @@ } | ||
/** | ||
* Find and return the target DOM element based on a step's 'target'. | ||
* | ||
* @private | ||
* @param {string|HTMLElement} element | ||
* | ||
* @returns {HTMLElement|undefined} | ||
* Scroll to position | ||
* @param {number} value | ||
* @param {HTMLElement} element | ||
* @returns {Promise<*>} | ||
*/ | ||
export function getElement(element: string | HTMLElement): ?HTMLElement { | ||
if (typeof element !== 'string') { | ||
return element; | ||
} | ||
return element ? document.querySelector(element) : null; | ||
} | ||
/** | ||
* Find and return the target DOM element based on a step's 'target'. | ||
* | ||
* @private | ||
* @param {string|HTMLElement} element | ||
* @param {number} offset | ||
* | ||
* @returns {HTMLElement|undefined} | ||
*/ | ||
export function getElementPosition(element: HTMLElement, offset: number): number { | ||
const elementRect = getClientRect(element); | ||
const scrollParent = getScrollParent(element); | ||
const hasScrollParent = hasCustomScrollParent(element); | ||
const top = elementRect.top + (!hasScrollParent && !isFixed(element) ? scrollParent.scrollTop : 0); | ||
return Math.floor(top - offset); | ||
} | ||
export function scrollTo(value: number, element: HTMLElement = scrollDoc()): Promise<*> { | ||
@@ -172,0 +259,0 @@ return new Promise((resolve, reject) => { |
@@ -9,6 +9,2 @@ // @flow | ||
export function isMobile(): boolean { | ||
return ('ontouchstart' in window) && /Mobi/.test(navigator.userAgent); | ||
} | ||
/** | ||
@@ -75,47 +71,2 @@ * Convert hex to RGB | ||
/** | ||
* Detect legacy browsers | ||
* | ||
* @returns {boolean} | ||
*/ | ||
export function isLegacy(): boolean { | ||
return !['chrome', 'safari', 'firefox', 'opera'].includes(getBrowser()); | ||
} | ||
/** | ||
* Log method calls if debug is enabled | ||
* | ||
* @private | ||
* @param {Object} arg | ||
* @param {string} arg.title - The title the logger was called from | ||
* @param {Object|Array} [arg.data] - The data to be logged | ||
* @param {boolean} [arg.warn] - If true, the message will be a warning | ||
* @param {boolean} [arg.debug] - Nothing will be logged unless debug is true | ||
*/ | ||
export function log({ title, data, warn = false, debug = false }: Object) { | ||
/* eslint-disable no-console */ | ||
const logFn = warn ? console.warn || console.error : console.log; | ||
if (debug && title && data) { | ||
console.groupCollapsed(`%creact-joyride: ${title}`, 'color: #ff0044; font-weight: bold; font-size: 12px;'); | ||
if (Array.isArray(data)) { | ||
data.forEach(d => { | ||
if (is.plainObject(d) && d.key) { | ||
logFn.apply(console, [d.key, d.value]); | ||
} | ||
else { | ||
logFn.apply(console, [d]); | ||
} | ||
}); | ||
} | ||
else { | ||
logFn.apply(console, [data]); | ||
} | ||
console.groupEnd(); | ||
} | ||
/* eslint-enable */ | ||
} | ||
export function hasKey(value: Object, key: string): boolean { | ||
@@ -138,27 +89,40 @@ return Object.prototype.hasOwnProperty.call(value, key); | ||
export function isEqual(a: any, b: any): boolean { | ||
let p; | ||
export function hideBeacon(step: Object): boolean { | ||
return step.disableBeacon || step.placement === 'center'; | ||
} | ||
export function isEqual(left: any, right: any): boolean { | ||
let t; | ||
const leftIsDOM = is.domElement(left); | ||
const rightIsDom = is.domElement(right); | ||
for (p in a) { | ||
if (Object.prototype.hasOwnProperty.call(a, p)) { | ||
if (typeof b[p] === 'undefined') { | ||
if (leftIsDOM && rightIsDom) { | ||
return left.isSameNode(right); | ||
} | ||
if ((leftIsDOM && !rightIsDom) || (!leftIsDOM && rightIsDom)) { | ||
return true; | ||
} | ||
for (const p in left) { | ||
if (Object.prototype.hasOwnProperty.call(left, p)) { | ||
if (typeof right[p] === 'undefined') { | ||
return false; | ||
} | ||
if (b[p] && !a[p]) { | ||
if (right[p] && !left[p]) { | ||
return false; | ||
} | ||
t = typeof a[p]; | ||
t = typeof left[p]; | ||
if (t === 'object' && !isEqual(a[p], b[p])) { | ||
if (t === 'object' && !isEqual(left[p], right[p])) { | ||
return false; | ||
} | ||
if (t === 'function' && (typeof b[p] === 'undefined' || a[p].toString() !== b[p].toString())) { | ||
if (t === 'function' && (typeof right[p] === 'undefined' || left[p].toString() !== right[p].toString())) { | ||
return false; | ||
} | ||
if (a[p] !== b[p]) { | ||
if (left[p] !== right[p]) { | ||
return false; | ||
@@ -169,5 +133,7 @@ } | ||
for (p in b) { | ||
if (typeof a[p] === 'undefined') { | ||
return false; | ||
for (const p in right) { | ||
if (Object.prototype.hasOwnProperty.call(right, p)) { | ||
if (typeof left[p] === 'undefined') { | ||
return false; | ||
} | ||
} | ||
@@ -178,1 +144,55 @@ } | ||
} | ||
/** | ||
* Detect legacy browsers | ||
* | ||
* @returns {boolean} | ||
*/ | ||
export function isLegacy(): boolean { | ||
return !['chrome', 'safari', 'firefox', 'opera'].includes(getBrowser()); | ||
} | ||
export function isMobile(): boolean { | ||
return ('ontouchstart' in window) && /Mobi/.test(navigator.userAgent); | ||
} | ||
/** | ||
* Log method calls if debug is enabled | ||
* | ||
* @private | ||
* @param {Object} arg | ||
* @param {string} arg.title - The title the logger was called from | ||
* @param {Object|Array} [arg.data] - The data to be logged | ||
* @param {boolean} [arg.warn] - If true, the message will be a warning | ||
* @param {boolean} [arg.debug] - Nothing will be logged unless debug is true | ||
*/ | ||
export function log({ title, data, warn = false, debug = false }: Object) { | ||
/* eslint-disable no-console */ | ||
const logFn = warn ? console.warn || console.error : console.log; | ||
if (debug) { | ||
if (title && data) { | ||
console.groupCollapsed(`%creact-joyride: ${title}`, 'color: #ff0044; font-weight: bold; font-size: 12px;'); | ||
if (Array.isArray(data)) { | ||
data.forEach(d => { | ||
if (is.plainObject(d) && d.key) { | ||
logFn.apply(console, [d.key, d.value]); | ||
} | ||
else { | ||
logFn.apply(console, [d]); | ||
} | ||
}); | ||
} | ||
else { | ||
logFn.apply(console, [data]); | ||
} | ||
console.groupEnd(); | ||
} | ||
else { | ||
console.error('log', 'Missing title or data props'); | ||
} | ||
} | ||
/* eslint-enable */ | ||
} |
const validTabNodes = /input|select|textarea|button|object/; | ||
const TAB_KEY = 9; | ||
let modalElement = null; | ||
function isHidden(element) { | ||
const noSize = element.offsetWidth <= 0 && element.offsetHeight <= 0; | ||
class Scope { | ||
constructor(tooltip) { | ||
this.tooltip = tooltip; | ||
} | ||
if (noSize && !element.innerHTML) return true; | ||
canBeTabbed = (element) => { | ||
let tabIndex = element.getAttribute('tabindex'); | ||
if (tabIndex === null) tabIndex = undefined; | ||
const isTabIndexNaN = isNaN(tabIndex); | ||
return (isTabIndexNaN || tabIndex >= 0) && this.canHaveFocus(element, !isTabIndexNaN); | ||
}; | ||
const style = window.getComputedStyle(element); | ||
return noSize ? style.getPropertyValue('overflow') !== 'visible' : style.getPropertyValue('display') === 'none'; | ||
} | ||
canHaveFocus = (element, isTabIndexNotNaN) => { | ||
const nodeName = element.nodeName.toLowerCase(); | ||
const res = (validTabNodes.test(nodeName) && !element.disabled) | ||
|| (nodeName === 'a' ? element.href || isTabIndexNotNaN : isTabIndexNotNaN); | ||
return res && this.isVisible(element); | ||
}; | ||
function isVisible(element) { | ||
let parentElement = element; | ||
while (parentElement) { | ||
if (parentElement === document.body) break; | ||
if (isHidden(parentElement)) return false; | ||
parentElement = parentElement.parentNode; | ||
} | ||
return true; | ||
} | ||
findValidTabElements = (element) => [].slice.call(element.querySelectorAll('*'), 0).filter(this.canBeTabbed); | ||
function canHaveFocus(element, isTabIndexNotNaN) { | ||
const nodeName = element.nodeName.toLowerCase(); | ||
const res = (validTabNodes.test(nodeName) && !element.disabled) | ||
|| (nodeName === 'a' ? element.href || isTabIndexNotNaN : isTabIndexNotNaN); | ||
return res && isVisible(element); | ||
} | ||
handleKeyDown = (e) => { | ||
if (!this.tooltip) { | ||
return; | ||
} | ||
function canBeTabbed(element) { | ||
let tabIndex = element.getAttribute('tabindex'); | ||
if (tabIndex === null) tabIndex = undefined; | ||
const isTabIndexNaN = isNaN(tabIndex); | ||
return (isTabIndexNaN || tabIndex >= 0) && canHaveFocus(element, !isTabIndexNaN); | ||
} | ||
if (e.keyCode === TAB_KEY) { | ||
this.interceptTab(this.tooltip, e); | ||
} | ||
}; | ||
function findValidTabElements(element) { | ||
return [].slice.call(element.querySelectorAll('*'), 0).filter(canBeTabbed); | ||
} | ||
interceptTab = (node, event) => { | ||
const elements = this.findValidTabElements(node); | ||
const { shiftKey } = event; | ||
function interceptTab(node, event) { | ||
const elements = findValidTabElements(node); | ||
const { shiftKey } = event; | ||
if (!elements.length) { | ||
event.preventDefault(); | ||
return; | ||
} | ||
if (!elements.length) { | ||
let x = elements.indexOf(document.activeElement); | ||
if (x === -1 || (!shiftKey && x + 1 === elements.length)) { | ||
x = 0; | ||
} | ||
else { | ||
x += shiftKey ? -1 : 1; | ||
} | ||
event.preventDefault(); | ||
return; | ||
} | ||
let x = elements.indexOf(document.activeElement); | ||
elements[x].focus(); | ||
}; | ||
if (x === -1 || (!shiftKey && x + 1 === elements.length)) { | ||
x = 0; | ||
} | ||
else { | ||
x += shiftKey ? -1 : 1; | ||
} | ||
isHidden = (element) => { | ||
const noSize = element.offsetWidth <= 0 && element.offsetHeight <= 0; | ||
const style = window.getComputedStyle(element); | ||
event.preventDefault(); | ||
if (noSize && !element.innerHTML) return true; | ||
elements[x].focus(); | ||
return (noSize && style.getPropertyValue('overflow') !== 'visible') || style.getPropertyValue('display') === 'none'; | ||
}; | ||
isVisible = (element) => { | ||
let parentElement = element; | ||
while (parentElement) { | ||
if (parentElement === document.body) break; | ||
if (this.isHidden(parentElement)) return false; | ||
parentElement = parentElement.parentNode; | ||
} | ||
return true; | ||
}; | ||
} | ||
function handleKeyDown(e) { | ||
if (!modalElement) { | ||
return; | ||
} | ||
let scope; | ||
if (e.keyCode === TAB_KEY) { | ||
interceptTab(modalElement, e); | ||
} | ||
} | ||
export function setScope(element) { | ||
modalElement = element; | ||
scope = new Scope(element); | ||
window.addEventListener('keydown', handleKeyDown, false); | ||
window.addEventListener('keydown', scope.handleKeyDown, false); | ||
} | ||
export function removeScope() { | ||
modalElement = null; | ||
window.removeEventListener('keydown', handleKeyDown); | ||
window.removeEventListener('keydown', scope.handleKeyDown); | ||
} |
@@ -11,60 +11,3 @@ // @flow | ||
import type { StepProps, JoyrideProps } from '../config/types'; | ||
/** | ||
* Validate if a step is valid | ||
* | ||
* @param {Object} step - A step object | ||
* @param {boolean} debug | ||
* | ||
* @returns {boolean} - True if the step is valid, false otherwise | ||
*/ | ||
export function validateStep(step: StepProps, debug: boolean = false): boolean { | ||
if (!is.plainObject(step)) { | ||
log({ | ||
title: 'validateStep', | ||
data: 'step must be an object', | ||
warn: true, | ||
debug, | ||
}); | ||
return false; | ||
} | ||
if (!step.target) { | ||
log({ | ||
title: 'validateStep', | ||
data: 'target is missing from the step', | ||
warn: true, | ||
debug, | ||
}); | ||
return false; | ||
} | ||
return true; | ||
} | ||
/** | ||
* Validate if steps is valid | ||
* | ||
* @param {Array} steps - A steps array | ||
* @param {boolean} debug | ||
* | ||
* @returns {boolean} - True if the steps are valid, false otherwise | ||
*/ | ||
export function validateSteps(steps: Array<Object>, debug: boolean = false): boolean { | ||
if (!is.array(steps)) { | ||
log({ | ||
title: 'validateSteps', | ||
data: 'steps must be an array', | ||
warn: true, | ||
debug, | ||
}); | ||
return false; | ||
} | ||
return steps.every(d => validateStep(d, debug)); | ||
} | ||
function getTourProps(props: JoyrideProps): JoyrideProps { | ||
function getTourProps(props: Object): Object { | ||
const sharedTourProps = [ | ||
@@ -76,2 +19,3 @@ 'beaconComponent', | ||
'disableScrolling', | ||
'disableScrollParentFix', | ||
'floaterProps', | ||
@@ -97,8 +41,8 @@ 'hideBackButton', | ||
export function getMergedStep(step: StepProps, props: JoyrideProps): StepProps { | ||
if (!step) return undefined; | ||
export function getMergedStep(step: StepProps, props: JoyrideProps): ?StepProps { | ||
if (!step) return null; | ||
const mergedStep = deepmerge.all([getTourProps(props), DEFAULTS.step, step]); | ||
const mergedStep = deepmerge.all([getTourProps(props), DEFAULTS.step, step], { isMergeableObject: is.plainObject }); | ||
const mergedStyles = getStyles(deepmerge(props.styles || {}, step.styles || {})); | ||
const scrollParent = hasCustomScrollParent(getElement(step.target)); | ||
const scrollParent = hasCustomScrollParent(getElement(step.target), mergedStep.disableScrollParentFix); | ||
const floaterProps = deepmerge.all([props.floaterProps || {}, DEFAULTS.floaterProps, mergedStep.floaterProps || {}]); | ||
@@ -135,1 +79,56 @@ | ||
} | ||
/** | ||
* Validate if a step is valid | ||
* | ||
* @param {Object} step - A step object | ||
* @param {boolean} debug | ||
* | ||
* @returns {boolean} - True if the step is valid, false otherwise | ||
*/ | ||
export function validateStep(step: StepProps, debug: boolean = false): boolean { | ||
if (!is.plainObject(step)) { | ||
log({ | ||
title: 'validateStep', | ||
data: 'step must be an object', | ||
warn: true, | ||
debug, | ||
}); | ||
return false; | ||
} | ||
if (!step.target) { | ||
log({ | ||
title: 'validateStep', | ||
data: 'target is missing from the step', | ||
warn: true, | ||
debug, | ||
}); | ||
return false; | ||
} | ||
return true; | ||
} | ||
/** | ||
* Validate if steps is valid | ||
* | ||
* @param {Array} steps - A steps array | ||
* @param {boolean} debug | ||
* | ||
* @returns {boolean} - True if the steps are valid, false otherwise | ||
*/ | ||
export function validateSteps(steps: Array<Object>, debug: boolean = false): boolean { | ||
if (!is.array(steps)) { | ||
log({ | ||
title: 'validateSteps', | ||
data: 'steps must be an array', | ||
warn: true, | ||
debug, | ||
}); | ||
return false; | ||
} | ||
return steps.every(d => validateStep(d, debug)); | ||
} |
// @flow | ||
import is from 'is-lite'; | ||
import STATUS from '../constants/status'; | ||
import ACTIONS from '../constants/actions'; | ||
import LIFECYCLE from '../constants/lifecycle'; | ||
import { ACTIONS, LIFECYCLE, STATUS } from '../constants'; | ||
import { hasValidKeys } from './helpers'; | ||
import type { StateHelpers, StateInstance, StateObject } from '../config/types'; | ||
const defaultState: StateObject = { | ||
const defaultState: StoreState = { | ||
action: '', | ||
@@ -22,3 +18,3 @@ controlled: false, | ||
export default function createStore(props: StateObject): StateInstance { | ||
export default function createStore(props: StoreState): StoreInstance { | ||
const store: Map<string, any> = new Map(); | ||
@@ -43,10 +39,6 @@ const data: Map<string, any> = new Map(); | ||
addListener(listener: Function) { | ||
this.listener = listener; | ||
} | ||
setState(nextState: Object, initial: boolean = false) { | ||
const state = this.getState(); | ||
const { action, index, lifecycle, status } = { | ||
const { action, index, lifecycle, size, status } = { | ||
...state, | ||
@@ -59,2 +51,3 @@ ...nextState, | ||
store.set('lifecycle', lifecycle); | ||
store.set('size', size); | ||
store.set('status', status); | ||
@@ -74,3 +67,3 @@ | ||
getState(): Object { | ||
getState(): StoreState { | ||
if (!store.size) { | ||
@@ -80,17 +73,13 @@ return { ...defaultState }; | ||
const index = parseInt(store.get('index'), 10); | ||
const steps = this.getSteps(); | ||
const size = steps.length; | ||
return { | ||
action: store.get('action'), | ||
controlled: store.get('controlled'), | ||
index, | ||
lifecycle: store.get('lifecycle'), | ||
size, | ||
status: store.get('status'), | ||
action: store.get('action') || '', | ||
controlled: store.get('controlled') || false, | ||
index: parseInt(store.get('index'), 10), | ||
lifecycle: store.get('lifecycle') || '', | ||
size: store.get('size') || 0, | ||
status: store.get('status') || '', | ||
}; | ||
} | ||
getNextState(state: StateObject, force: ?boolean = false): Object { | ||
getNextState(state: Object, force: ?boolean = false): StoreState { | ||
const { action, controlled, index, size, status } = this.getState(); | ||
@@ -102,4 +91,6 @@ const newIndex = is.number(state.index) ? state.index : index; | ||
action: state.action || action, | ||
controlled, | ||
index: nextIndex, | ||
lifecycle: state.lifecycle || LIFECYCLE.INIT, | ||
size: state.size || size, | ||
status: nextIndex === size ? STATUS.FINISHED : (state.status || status), | ||
@@ -109,3 +100,3 @@ }; | ||
hasUpdatedState(oldState: StateObject): boolean { | ||
hasUpdatedState(oldState: StoreState): boolean { | ||
const before = JSON.stringify(oldState); | ||
@@ -117,11 +108,2 @@ const after = JSON.stringify(this.getState()); | ||
setSteps = (steps: Array<Object>) => { | ||
const { size, status } = this.getState(); | ||
data.set('steps', steps); | ||
if (status === STATUS.WAITING && !size && steps.length) { | ||
this.setState({ status: STATUS.RUNNING }); | ||
} | ||
}; | ||
getSteps(): Array<Object> { | ||
@@ -133,14 +115,10 @@ const steps = data.get('steps'); | ||
getHelpers(): StateHelpers { | ||
getHelpers(): StoreHelpers { | ||
return { | ||
start: this.start, | ||
stop: this.stop, | ||
restart: this.restart, | ||
reset: this.reset, | ||
prev: this.prev, | ||
next: this.next, | ||
go: this.go, | ||
index: this.index, | ||
close: this.close, | ||
skip: this.skip, | ||
reset: this.reset, | ||
info: this.info, | ||
@@ -150,3 +128,23 @@ }; | ||
update = (state: StateObject) => { | ||
setSteps = (steps: Array<Object>) => { | ||
const { size, status } = this.getState(); | ||
const state = { | ||
size: steps.length, | ||
status, | ||
}; | ||
data.set('steps', steps); | ||
if (status === STATUS.WAITING && !size && steps.length) { | ||
state.status = STATUS.RUNNING; | ||
} | ||
this.setState(state); | ||
}; | ||
addListener = (listener: Function) => { | ||
this.listener = listener; | ||
}; | ||
update = (state: StoreState) => { | ||
if (!hasValidKeys(state, validKeys)) { | ||
@@ -165,8 +163,2 @@ throw new Error('state is not valid'); | ||
steps = (nextSteps) => { | ||
if (!is.array(nextSteps)) return; | ||
this.setSteps(nextSteps); | ||
}; | ||
start = (nextIndex: number) => { | ||
@@ -195,22 +187,2 @@ const { index, size } = this.getState(); | ||
restart = () => { | ||
const { controlled } = this.getState(); | ||
if (controlled) return; | ||
this.setState({ | ||
...this.getNextState({ action: ACTIONS.RESTART, index: 0 }), | ||
status: STATUS.RUNNING, | ||
}); | ||
}; | ||
reset = () => { | ||
const { controlled } = this.getState(); | ||
if (controlled) return; | ||
this.setState({ | ||
...this.getNextState({ action: ACTIONS.RESET, index: 0 }), | ||
status: STATUS.READY, | ||
}); | ||
}; | ||
prev = () => { | ||
@@ -227,2 +199,3 @@ const { index, status } = this.getState(); | ||
const { index, status } = this.getState(); | ||
if (status !== STATUS.RUNNING) return; | ||
@@ -233,19 +206,10 @@ | ||
go = (number) => { | ||
const { index, status } = this.getState(); | ||
if (status !== STATUS.RUNNING) return; | ||
go = (nextIndex) => { | ||
const { controlled, status } = this.getState(); | ||
if (controlled || status !== STATUS.RUNNING) return; | ||
this.setState({ | ||
...this.getNextState({ action: ACTIONS.GO, index: index + number }), | ||
}); | ||
}; | ||
index = (nextIndex) => { | ||
const { status } = this.getState(); | ||
if (status !== STATUS.RUNNING) return; | ||
const step = this.getSteps()[nextIndex]; | ||
this.setState({ | ||
...this.getNextState({ action: ACTIONS.INDEX, index: nextIndex }), | ||
...this.getNextState({ action: ACTIONS.GO, index: nextIndex }), | ||
status: step ? status : STATUS.FINISHED, | ||
@@ -275,2 +239,12 @@ }); | ||
reset = (restart = false) => { | ||
const { controlled } = this.getState(); | ||
if (controlled) return; | ||
this.setState({ | ||
...this.getNextState({ action: ACTIONS.RESET, index: 0 }), | ||
status: restart ? STATUS.RUNNING : STATUS.READY, | ||
}); | ||
}; | ||
info = (): Object => this.getState() | ||
@@ -277,0 +251,0 @@ } |
@@ -15,3 +15,3 @@ import deepmerge from 'deepmerge'; | ||
const buttonReset = { | ||
const buttonBase = { | ||
backgroundColor: 'transparent', | ||
@@ -22,2 +22,3 @@ border: 0, | ||
cursor: 'pointer', | ||
fontSize: 16, | ||
lineHeight: 1, | ||
@@ -65,3 +66,3 @@ padding: 8, | ||
beacon: { | ||
...buttonReset, | ||
...buttonBase, | ||
display: 'inline-block', | ||
@@ -118,3 +119,3 @@ height: options.beaconSize, | ||
fontSize: 18, | ||
margin: '0 0 10px 0', | ||
margin: 0, | ||
}, | ||
@@ -131,3 +132,3 @@ tooltipContent: { | ||
buttonNext: { | ||
...buttonReset, | ||
...buttonBase, | ||
backgroundColor: options.primaryColor, | ||
@@ -138,3 +139,3 @@ borderRadius: 4, | ||
buttonBack: { | ||
...buttonReset, | ||
...buttonBase, | ||
color: options.primaryColor, | ||
@@ -145,3 +146,3 @@ marginLeft: 'auto', | ||
buttonClose: { | ||
...buttonReset, | ||
...buttonBase, | ||
color: options.textColor, | ||
@@ -156,3 +157,3 @@ height: 14, | ||
buttonSkip: { | ||
...buttonReset, | ||
...buttonBase, | ||
color: options.textColor, | ||
@@ -169,2 +170,6 @@ fontSize: 14, | ||
}, | ||
overlayLegacyCenter: { | ||
...overlay, | ||
backgroundColor: options.overlayColor, | ||
}, | ||
spotlight: { | ||
@@ -182,3 +187,3 @@ ...spotlight, | ||
}, | ||
floater: { | ||
options: { | ||
zIndex: options.zIndex, | ||
@@ -185,0 +190,0 @@ }, |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
239456
7213
61
28
59
+ Addeddeepmerge@3.3.04.3.1(transitive)
+ Addedis-lite@0.4.1(transitive)
+ Addedreact-floater@0.6.5(transitive)
+ Addedtree-changes@0.4.0(transitive)
- Removeddeepmerge@2.2.1(transitive)
- Removedreact-floater@0.5.5(transitive)
- Removedtree-changes@0.3.4(transitive)
Updateddeep-diff@^1.0.2
Updateddeepmerge@^3.0.0
Updatedis-lite@^0.2.2
Updatedreact-floater@^0.6.2
Updatedtree-changes@^0.4.0