UNPKG

react-joyride

Version:

Create guided tours for your apps

1,822 lines (1,546 loc) 85.6 kB
import React, { isValidElement } from 'react'; import 'prop-types'; import treeChanges from 'tree-changes'; import is from 'is-lite'; import ReactDOM, { createPortal } from 'react-dom'; import ExecutionEnvironment from 'exenv'; import scroll from 'scroll'; import scrollParent from 'scrollparent'; import { isValidElementType, Element, ForwardRef, typeOf } from 'react-is'; import deepmerge from 'deepmerge'; import Floater from 'react-floater'; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } var ACTIONS = { INIT: 'init', START: 'start', STOP: 'stop', RESET: 'reset', PREV: 'prev', NEXT: 'next', GO: 'go', CLOSE: 'close', SKIP: 'skip', UPDATE: 'update' }; var EVENTS = { TOUR_START: 'tour:start', STEP_BEFORE: 'step:before', BEACON: 'beacon', TOOLTIP: 'tooltip', STEP_AFTER: 'step:after', TOUR_END: 'tour:end', TOUR_STATUS: 'tour:status', TARGET_NOT_FOUND: 'error:target_not_found', ERROR: 'error' }; var LIFECYCLE = { INIT: 'init', READY: 'ready', BEACON: 'beacon', TOOLTIP: 'tooltip', COMPLETE: 'complete', ERROR: 'error' }; var STATUS = { IDLE: 'idle', READY: 'ready', WAITING: 'waiting', RUNNING: 'running', PAUSED: 'paused', SKIPPED: 'skipped', FINISHED: 'finished', ERROR: 'error' }; var canUseDOM = ExecutionEnvironment.canUseDOM; var isReact16 = createPortal !== undefined; /** * Get the current browser * * @param {string} userAgent * * @returns {String} */ function getBrowser() { var userAgent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : navigator.userAgent; var browser = userAgent; if (typeof window === 'undefined') { browser = 'node'; } else if (document.documentMode) { browser = 'ie'; } else if (/Edge/.test(userAgent)) { browser = 'edge'; } // Opera 8.0+ else if (Boolean(window.opera) || userAgent.indexOf(' OPR/') >= 0) { browser = 'opera'; } // Firefox 1.0+ else if (typeof window.InstallTrigger !== 'undefined') { browser = 'firefox'; } // Chrome 1+ else if (window.chrome) { browser = 'chrome'; } // Safari (and Chrome iOS, Firefox iOS) else if (/(Version\/([0-9._]+).*Safari|CriOS|FxiOS| Mobile\/)/.test(userAgent)) { browser = 'safari'; } return browser; } /** * Get the toString Object type * @param {*} value * @returns {string} */ function getObjectType(value) { return Object.prototype.toString.call(value).slice(8, -1).toLowerCase(); } /** * Get text from React components * * @param {*} root * * @returns {string} */ function getText(root) { var content = []; var recurse = function recurse(child) { /* istanbul ignore else */ if (typeof child === 'string' || typeof child === 'number') { content.push(child); } else if (Array.isArray(child)) { child.forEach(function (c) { return recurse(c); }); } else if (child && child.props) { var children = child.props.children; if (Array.isArray(children)) { children.forEach(function (c) { return recurse(c); }); } else { recurse(children); } } }; recurse(root); return content.join(' ').trim(); } function hasOwnProperty(value, key) { return Object.prototype.hasOwnProperty.call(value, key); } function hasValidKeys(value, keys) { if (!is.plainObject(value) || !is.array(keys)) { return false; } return Object.keys(value).every(function (d) { return keys.indexOf(d) !== -1; }); } /** * Convert hex to RGB * * @param {string} hex * @returns {Array} */ function hexToRGB(hex) { var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; var properHex = hex.replace(shorthandRegex, function (m, r, g, b) { return r + r + g + g + b + b; }); var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(properHex); return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : []; } /** * Decide if the step shouldn't skip the beacon * @param {Object} step * * @returns {boolean} */ function hideBeacon(step) { return step.disableBeacon || step.placement === 'center'; } /** * Compare if two variables are equal * * @param {*} left * @param {*} right * * @returns {boolean} */ function isEqual(left, right) { var type; var hasReactElement = /*#__PURE__*/isValidElement(left) || /*#__PURE__*/isValidElement(right); var hasUndefined = is.undefined(left) || is.undefined(right); if (getObjectType(left) !== getObjectType(right) || hasReactElement || hasUndefined) { return false; } if (is.domElement(left)) { return left.isSameNode(right); } if (is.number(left)) { return left === right; } if (is["function"](left)) { return left.toString() === right.toString(); } for (var key in left) { /* istanbul ignore else */ if (hasOwnProperty(left, key)) { if (typeof left[key] === 'undefined' || typeof right[key] === 'undefined') { return false; } type = getObjectType(left[key]); if (['object', 'array'].indexOf(type) !== -1 && isEqual(left[key], right[key])) { continue; } if (type === 'function' && isEqual(left[key], right[key])) { continue; } if (left[key] !== right[key]) { return false; } } } for (var p in right) { /* istanbul ignore else */ if (hasOwnProperty(right, p)) { if (typeof left[p] === 'undefined') { return false; } } } return true; } /** * Detect legacy browsers * * @returns {boolean} */ function isLegacy() { return !(['chrome', 'safari', 'firefox', 'opera'].indexOf(getBrowser()) !== -1); } /** * 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 */ function log(_ref) { var title = _ref.title, data = _ref.data, _ref$warn = _ref.warn, warn = _ref$warn === void 0 ? false : _ref$warn, _ref$debug = _ref.debug, debug = _ref$debug === void 0 ? false : _ref$debug; /* eslint-disable no-console */ var logFn = warn ? console.warn || console.error : console.log; if (debug) { if (title && data) { console.groupCollapsed("%creact-joyride: ".concat(title), 'color: #ff0044; font-weight: bold; font-size: 12px;'); if (Array.isArray(data)) { data.forEach(function (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('Missing title or data props'); } } /* eslint-enable */ } var defaultState = { action: '', controlled: false, index: 0, lifecycle: LIFECYCLE.INIT, size: 0, status: STATUS.IDLE }; var validKeys = ['action', 'index', 'lifecycle', 'status']; function createStore(props) { var store = new Map(); var data = new Map(); var Store = /*#__PURE__*/function () { function Store() { var _this = this; var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, _ref$continuous = _ref.continuous, continuous = _ref$continuous === void 0 ? false : _ref$continuous, stepIndex = _ref.stepIndex, _ref$steps = _ref.steps, _steps = _ref$steps === void 0 ? [] : _ref$steps; _classCallCheck(this, Store); _defineProperty(this, "listener", void 0); _defineProperty(this, "setSteps", function (steps) { var _this$getState = _this.getState(), size = _this$getState.size, status = _this$getState.status; var state = { size: steps.length, status: status }; data.set('steps', steps); if (status === STATUS.WAITING && !size && steps.length) { state.status = STATUS.RUNNING; } _this.setState(state); }); _defineProperty(this, "addListener", function (listener) { _this.listener = listener; }); _defineProperty(this, "update", function (state) { if (!hasValidKeys(state, validKeys)) { throw new Error("State is not valid. Valid keys: ".concat(validKeys.join(', '))); } _this.setState(_objectSpread2({}, _this.getNextState(_objectSpread2(_objectSpread2(_objectSpread2({}, _this.getState()), state), {}, { action: state.action || ACTIONS.UPDATE }), true))); }); _defineProperty(this, "start", function (nextIndex) { var _this$getState2 = _this.getState(), index = _this$getState2.index, size = _this$getState2.size; _this.setState(_objectSpread2(_objectSpread2({}, _this.getNextState({ action: ACTIONS.START, index: is.number(nextIndex) ? nextIndex : index }, true)), {}, { status: size ? STATUS.RUNNING : STATUS.WAITING })); }); _defineProperty(this, "stop", function () { var advance = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var _this$getState3 = _this.getState(), index = _this$getState3.index, status = _this$getState3.status; if ([STATUS.FINISHED, STATUS.SKIPPED].indexOf(status) !== -1) return; _this.setState(_objectSpread2(_objectSpread2({}, _this.getNextState({ action: ACTIONS.STOP, index: index + (advance ? 1 : 0) })), {}, { status: STATUS.PAUSED })); }); _defineProperty(this, "close", function () { var _this$getState4 = _this.getState(), index = _this$getState4.index, status = _this$getState4.status; if (status !== STATUS.RUNNING) return; _this.setState(_objectSpread2({}, _this.getNextState({ action: ACTIONS.CLOSE, index: index + 1 }))); }); _defineProperty(this, "go", function (nextIndex) { var _this$getState5 = _this.getState(), controlled = _this$getState5.controlled, status = _this$getState5.status; if (controlled || status !== STATUS.RUNNING) return; var step = _this.getSteps()[nextIndex]; _this.setState(_objectSpread2(_objectSpread2({}, _this.getNextState({ action: ACTIONS.GO, index: nextIndex })), {}, { status: step ? status : STATUS.FINISHED })); }); _defineProperty(this, "info", function () { return _this.getState(); }); _defineProperty(this, "next", function () { var _this$getState6 = _this.getState(), index = _this$getState6.index, status = _this$getState6.status; if (status !== STATUS.RUNNING) return; _this.setState(_this.getNextState({ action: ACTIONS.NEXT, index: index + 1 })); }); _defineProperty(this, "open", function () { var _this$getState7 = _this.getState(), status = _this$getState7.status; if (status !== STATUS.RUNNING) return; _this.setState(_objectSpread2({}, _this.getNextState({ action: ACTIONS.UPDATE, lifecycle: LIFECYCLE.TOOLTIP }))); }); _defineProperty(this, "prev", function () { var _this$getState8 = _this.getState(), index = _this$getState8.index, status = _this$getState8.status; if (status !== STATUS.RUNNING) return; _this.setState(_objectSpread2({}, _this.getNextState({ action: ACTIONS.PREV, index: index - 1 }))); }); _defineProperty(this, "reset", function () { var restart = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var _this$getState9 = _this.getState(), controlled = _this$getState9.controlled; if (controlled) return; _this.setState(_objectSpread2(_objectSpread2({}, _this.getNextState({ action: ACTIONS.RESET, index: 0 })), {}, { status: restart ? STATUS.RUNNING : STATUS.READY })); }); _defineProperty(this, "skip", function () { var _this$getState10 = _this.getState(), status = _this$getState10.status; if (status !== STATUS.RUNNING) return; _this.setState({ action: ACTIONS.SKIP, lifecycle: LIFECYCLE.INIT, status: STATUS.SKIPPED }); }); this.setState({ action: ACTIONS.INIT, controlled: is.number(stepIndex), continuous: continuous, index: is.number(stepIndex) ? stepIndex : 0, lifecycle: LIFECYCLE.INIT, status: _steps.length ? STATUS.READY : STATUS.IDLE }, true); this.setSteps(_steps); } _createClass(Store, [{ key: "setState", value: function setState(nextState) { var initial = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var state = this.getState(); var _state$nextState = _objectSpread2(_objectSpread2({}, state), nextState), action = _state$nextState.action, index = _state$nextState.index, lifecycle = _state$nextState.lifecycle, size = _state$nextState.size, status = _state$nextState.status; store.set('action', action); store.set('index', index); store.set('lifecycle', lifecycle); store.set('size', size); store.set('status', status); if (initial) { store.set('controlled', nextState.controlled); store.set('continuous', nextState.continuous); } /* istanbul ignore else */ if (this.listener && this.hasUpdatedState(state)) { // console.log('▶ ▶ ▶ NEW STATE', this.getState()); this.listener(this.getState()); } } }, { key: "getState", value: function getState() { if (!store.size) { return _objectSpread2({}, defaultState); } return { 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') || '' }; } }, { key: "getNextState", value: function getNextState(state) { var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var _this$getState11 = this.getState(), action = _this$getState11.action, controlled = _this$getState11.controlled, index = _this$getState11.index, size = _this$getState11.size, status = _this$getState11.status; var newIndex = is.number(state.index) ? state.index : index; var nextIndex = controlled && !force ? index : Math.min(Math.max(newIndex, 0), size); return { action: state.action || action, controlled: controlled, index: nextIndex, lifecycle: state.lifecycle || LIFECYCLE.INIT, size: state.size || size, status: nextIndex === size ? STATUS.FINISHED : state.status || status }; } }, { key: "hasUpdatedState", value: function hasUpdatedState(oldState) { var before = JSON.stringify(oldState); var after = JSON.stringify(this.getState()); return before !== after; } }, { key: "getSteps", value: function getSteps() { var steps = data.get('steps'); return Array.isArray(steps) ? steps : []; } }, { key: "getHelpers", value: function getHelpers() { return { close: this.close, go: this.go, info: this.info, next: this.next, open: this.open, prev: this.prev, reset: this.reset, skip: this.skip }; } }]); return Store; }(); return new Store(props); } function scrollDoc() { return document.scrollingElement || document.createElement('body'); } /** * Find the bounding client rect * * @private * @param {HTMLElement} element - The target element * @returns {Object} */ function getClientRect(element) { if (!element) { return {}; } return element.getBoundingClientRect(); } /** * Helper function to get the browser-normalized "document height" * @returns {Number} */ function getDocumentHeight() { var _document = document, body = _document.body, html = _document.documentElement; if (!body || !html) { return 0; } return Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight); } /** * Find and return the target DOM element based on a step's 'target'. * * @private * @param {string|HTMLElement} element * * @returns {HTMLElement|null} */ function getElement(element) { /* istanbul ignore else */ if (typeof element === 'string') { return document.querySelector(element); } return element; } /** * Get computed style property * * @param {HTMLElement} el * * @returns {Object} */ function getStyleComputedProperty(el) { if (!el || el.nodeType !== 1) { return {}; } return getComputedStyle(el); } /** * Get scroll parent with fix * * @param {HTMLElement} element * @param {boolean} skipFix * @param {boolean} [forListener] * * @returns {*} */ function getScrollParent(element, skipFix, forListener) { var parent = scrollParent(element); if (parent.isSameNode(scrollDoc())) { if (forListener) { return document; } return scrollDoc(); } var hasScrolling = parent.scrollHeight > parent.offsetHeight; /* istanbul ignore else */ 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} */ function hasCustomScrollParent(element, skipFix) { if (!element) return false; var parent = getScrollParent(element, skipFix); return !parent.isSameNode(scrollDoc()); } /** * Check if the element has custom offset parent * * @param {HTMLElement} element * * @returns {boolean} */ function hasCustomOffsetParent(element) { return element.offsetParent !== document.body; } /** * Check if an element has fixed/sticky position * @param {HTMLElement|Node} el * @param {string} [type] * * @returns {boolean} */ function hasPosition(el) { var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'fixed'; if (!el || !(el instanceof HTMLElement)) { return false; } var nodeName = el.nodeName; if (nodeName === 'BODY' || nodeName === 'HTML') { return false; } if (getStyleComputedProperty(el).position === type) { return true; } return hasPosition(el.parentNode, type); } /** * Check if the element is visible * * @param {HTMLElement} element * * @returns {boolean} */ function isElementVisible(element) { if (!element) return false; var parentElement = element; while (parentElement) { if (parentElement === document.body) break; /* istanbul ignore else */ if (parentElement instanceof HTMLElement) { var _getComputedStyle = getComputedStyle(parentElement), display = _getComputedStyle.display, visibility = _getComputedStyle.visibility; if (display === 'none' || visibility === 'hidden') { return false; } } parentElement = parentElement.parentNode; } return true; } /** * 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} */ function getElementPosition(element, offset, skipFix) { var elementRect = getClientRect(element); var parent = getScrollParent(element, skipFix); var hasScrollParent = hasCustomScrollParent(element, skipFix); var parentTop = 0; /* istanbul ignore else */ if (parent instanceof HTMLElement) { parentTop = parent.scrollTop; } var top = elementRect.top + (!hasScrollParent && !hasPosition(element) ? parentTop : 0); return Math.floor(top - offset); } /** * Get the offsetTop of each element up to the body * * @param {HTMLElement} element * * @returns {number} */ function getTopOffset(element) { if (element instanceof HTMLElement) { if (element.offsetParent instanceof HTMLElement) { return getTopOffset(element.offsetParent) + element.offsetTop; } return element.offsetTop; } return 0; } /** * Get the scrollTop position * * @param {HTMLElement} element * @param {number} offset * @param {boolean} skipFix * * @returns {number} */ function getScrollTo(element, offset, skipFix) { if (!element) { return 0; } var parent = scrollParent(element); var top = getTopOffset(element); if (hasCustomScrollParent(element, skipFix) && !hasCustomOffsetParent(element)) { top -= getTopOffset(parent); } return Math.floor(top - offset); } /** * Scroll to position * @param {number} value * @param {HTMLElement} element * @param {number} scrollDuration * @returns {Promise<*>} */ function scrollTo(value) { var element = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : scrollDoc(); var scrollDuration = arguments.length > 2 ? arguments[2] : undefined; return new Promise(function (resolve, reject) { var scrollTop = element.scrollTop; var limit = value > scrollTop ? value - scrollTop : scrollTop - value; scroll.top(element, value, { duration: limit < 100 ? 50 : scrollDuration }, function (error) { if (error && error.message !== 'Element already at target scroll position') { return reject(error); } return resolve(); }); }); } function createChainableTypeChecker(validate) { function checkType(isRequired, props, propName, componentName, location, propFullName) { var componentNameSafe = componentName || '<<anonymous>>'; var propFullNameSafe = propFullName || propName; /* istanbul ignore else */ if (props[propName] == null) { if (isRequired) { return new Error("Required ".concat(location, " `").concat(propFullNameSafe, "` was not specified in `").concat(componentNameSafe, "`.")); } return null; } for (var _len = arguments.length, args = new Array(_len > 6 ? _len - 6 : 0), _key = 6; _key < _len; _key++) { args[_key - 6] = arguments[_key]; } return validate.apply(void 0, [props, propName, componentNameSafe, location, propFullNameSafe].concat(args)); } var chainedCheckType = checkType.bind(null, false); chainedCheckType.isRequired = checkType.bind(null, true); return chainedCheckType; } createChainableTypeChecker(function (props, propName, componentName, location, propFullName) { var propValue = props[propName]; var Component = propValue; if (! /*#__PURE__*/React.isValidElement(propValue) && isValidElementType(propValue)) { var ownProps = { ref: function ref() {}, step: {} }; Component = /*#__PURE__*/React.createElement(Component, ownProps); } if (is.string(propValue) || is.number(propValue) || !isValidElementType(propValue) || !([Element, ForwardRef].indexOf(typeOf(Component)) !== -1)) { return new Error("Invalid ".concat(location, " `").concat(propFullName, "` supplied to `").concat(componentName, "`. Expected a React class or forwardRef.")); } return undefined; }); var defaultOptions = { arrowColor: '#fff', backgroundColor: '#fff', beaconSize: 36, overlayColor: 'rgba(0, 0, 0, 0.5)', primaryColor: '#f04', spotlightShadow: '0 0 15px rgba(0, 0, 0, 0.5)', textColor: '#333', zIndex: 100 }; var buttonBase = { backgroundColor: 'transparent', border: 0, borderRadius: 0, color: '#555', cursor: 'pointer', fontSize: 16, lineHeight: 1, padding: 8, WebkitAppearance: 'none' }; var spotlight = { borderRadius: 4, position: 'absolute' }; function getStyles() { var stepStyles = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var options = deepmerge(defaultOptions, stepStyles.options || {}); var width = 290; if (window.innerWidth > 480) { width = 380; } if (options.width) { if (window.innerWidth < options.width) { width = window.innerWidth - 30; } else { width = options.width; //eslint-disable-line prefer-destructuring } } var overlay = { bottom: 0, left: 0, overflow: 'hidden', position: 'absolute', right: 0, top: 0, zIndex: options.zIndex }; var defaultStyles = { beacon: _objectSpread2(_objectSpread2({}, buttonBase), {}, { display: 'inline-block', height: options.beaconSize, position: 'relative', width: options.beaconSize, zIndex: options.zIndex }), beaconInner: { animation: 'joyride-beacon-inner 1.2s infinite ease-in-out', backgroundColor: options.primaryColor, borderRadius: '50%', display: 'block', height: '50%', left: '50%', opacity: 0.7, position: 'absolute', top: '50%', transform: 'translate(-50%, -50%)', width: '50%' }, beaconOuter: { animation: 'joyride-beacon-outer 1.2s infinite ease-in-out', backgroundColor: "rgba(".concat(hexToRGB(options.primaryColor).join(','), ", 0.2)"), border: "2px solid ".concat(options.primaryColor), borderRadius: '50%', boxSizing: 'border-box', display: 'block', height: '100%', left: 0, opacity: 0.9, position: 'absolute', top: 0, transformOrigin: 'center', width: '100%' }, tooltip: { backgroundColor: options.backgroundColor, borderRadius: 5, boxSizing: 'border-box', color: options.textColor, fontSize: 16, maxWidth: '100%', padding: 15, position: 'relative', width: width }, tooltipContainer: { lineHeight: 1.4, textAlign: 'center' }, tooltipTitle: { fontSize: 18, margin: 0 }, tooltipContent: { padding: '20px 10px' }, tooltipFooter: { alignItems: 'center', display: 'flex', justifyContent: 'flex-end', marginTop: 15 }, tooltipFooterSpacer: { flex: 1 }, buttonNext: _objectSpread2(_objectSpread2({}, buttonBase), {}, { backgroundColor: options.primaryColor, borderRadius: 4, color: '#fff' }), buttonBack: _objectSpread2(_objectSpread2({}, buttonBase), {}, { color: options.primaryColor, marginLeft: 'auto', marginRight: 5 }), buttonClose: _objectSpread2(_objectSpread2({}, buttonBase), {}, { color: options.textColor, height: 14, padding: 15, position: 'absolute', right: 0, top: 0, width: 14 }), buttonSkip: _objectSpread2(_objectSpread2({}, buttonBase), {}, { color: options.textColor, fontSize: 14 }), overlay: _objectSpread2(_objectSpread2({}, overlay), {}, { backgroundColor: options.overlayColor, mixBlendMode: 'hard-light' }), overlayLegacy: _objectSpread2({}, overlay), overlayLegacyCenter: _objectSpread2(_objectSpread2({}, overlay), {}, { backgroundColor: options.overlayColor }), spotlight: _objectSpread2(_objectSpread2({}, spotlight), {}, { backgroundColor: 'gray' }), spotlightLegacy: _objectSpread2(_objectSpread2({}, spotlight), {}, { boxShadow: "0 0 0 9999px ".concat(options.overlayColor, ", ").concat(options.spotlightShadow) }), floaterStyles: { arrow: { color: options.arrowColor }, options: { zIndex: options.zIndex } }, options: options }; return deepmerge(defaultStyles, stepStyles); } var DEFAULTS = { floaterProps: { options: { preventOverflow: { boundariesElement: 'scrollParent' } }, wrapperOptions: { offset: -18, position: true } }, locale: { back: 'Back', close: 'Close', last: 'Last', next: 'Next', open: 'Open the dialog', skip: 'Skip' }, step: { event: 'click', placement: 'bottom', offset: 10 } }; function getTourProps(props) { var sharedTourProps = ['beaconComponent', 'disableCloseOnEsc', 'disableOverlay', 'disableOverlayClose', 'disableScrolling', 'disableScrollParentFix', 'floaterProps', 'hideBackButton', 'locale', 'showProgress', 'showSkipButton', 'spotlightClicks', 'spotlightPadding', 'styles', 'tooltipComponent']; return Object.keys(props).filter(function (d) { return sharedTourProps.indexOf(d) !== -1; }).reduce(function (acc, i) { acc[i] = props[i]; //eslint-disable-line react/destructuring-assignment return acc; }, {}); } function getMergedStep(step, props) { if (!step) return null; var mergedStep = deepmerge.all([getTourProps(props), DEFAULTS.step, step], { isMergeableObject: is.plainObject }); var mergedStyles = getStyles(deepmerge(props.styles || {}, step.styles || {})); var scrollParent = hasCustomScrollParent(getElement(step.target), mergedStep.disableScrollParentFix); var floaterProps = deepmerge.all([props.floaterProps || {}, DEFAULTS.floaterProps, mergedStep.floaterProps || {}]); // Set react-floater props floaterProps.offset = mergedStep.offset; floaterProps.styles = deepmerge(floaterProps.styles || {}, mergedStyles.floaterStyles || {}); delete mergedStyles.floaterStyles; floaterProps.offset += props.spotlightPadding || step.spotlightPadding || 0; if (step.placementBeacon) { floaterProps.wrapperOptions.placement = step.placementBeacon; } if (scrollParent) { floaterProps.options.preventOverflow.boundariesElement = 'window'; } return _objectSpread2(_objectSpread2({}, mergedStep), {}, { locale: deepmerge.all([DEFAULTS.locale, props.locale || {}, mergedStep.locale || {}]), floaterProps: floaterProps, styles: mergedStyles }); } /** * 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 */ function validateStep(step) { var debug = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; if (!is.plainObject(step)) { log({ title: 'validateStep', data: 'step must be an object', warn: true, debug: debug }); return false; } if (!step.target) { log({ title: 'validateStep', data: 'target is missing from the step', warn: true, debug: 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 */ function validateSteps(steps) { var debug = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; if (!is.array(steps)) { log({ title: 'validateSteps', data: 'steps must be an array', warn: true, debug: debug }); return false; } return steps.every(function (d) { return validateStep(d, debug); }); } var Scope = function Scope(_element) { var _this = this; var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classCallCheck(this, Scope); _defineProperty(this, "element", void 0); _defineProperty(this, "options", void 0); _defineProperty(this, "canBeTabbed", function (element) { var tabIndex = element.tabIndex; if (tabIndex === null || tabIndex < 0) tabIndex = undefined; var isTabIndexNaN = isNaN(tabIndex); return !isTabIndexNaN && _this.canHaveFocus(element); }); _defineProperty(this, "canHaveFocus", function (element) { var validTabNodes = /input|select|textarea|button|object/; var nodeName = element.nodeName.toLowerCase(); var res = validTabNodes.test(nodeName) && !element.getAttribute('disabled') || nodeName === 'a' && !!element.getAttribute('href'); return res && _this.isVisible(element); }); _defineProperty(this, "findValidTabElements", function () { return [].slice.call(_this.element.querySelectorAll('*'), 0).filter(_this.canBeTabbed); }); _defineProperty(this, "handleKeyDown", function (e) { var _this$options$keyCode = _this.options.keyCode, keyCode = _this$options$keyCode === void 0 ? 9 : _this$options$keyCode; /* istanbul ignore else */ if (e.keyCode === keyCode) { _this.interceptTab(e); } }); _defineProperty(this, "interceptTab", function (event) { event.preventDefault(); var elements = _this.findValidTabElements(); var shiftKey = event.shiftKey; if (!elements.length) { return; } var x = elements.indexOf(document.activeElement); if (x === -1 || !shiftKey && x + 1 === elements.length) { x = 0; } else if (shiftKey && x === 0) { x = elements.length - 1; } else { x += shiftKey ? -1 : 1; } elements[x].focus(); }); _defineProperty(this, "isHidden", function (element) { var noSize = element.offsetWidth <= 0 && element.offsetHeight <= 0; var style = window.getComputedStyle(element); if (noSize && !element.innerHTML) return true; return noSize && style.getPropertyValue('overflow') !== 'visible' || style.getPropertyValue('display') === 'none'; }); _defineProperty(this, "isVisible", function (element) { var parentElement = element; while (parentElement) { /* istanbul ignore else */ if (parentElement instanceof HTMLElement) { if (parentElement === document.body) break; /* istanbul ignore else */ if (_this.isHidden(parentElement)) return false; parentElement = parentElement.parentNode; } } return true; }); _defineProperty(this, "removeScope", function () { window.removeEventListener('keydown', _this.handleKeyDown); }); _defineProperty(this, "checkFocus", function (target) { if (document.activeElement !== target) { target.focus(); window.requestAnimationFrame(function () { return _this.checkFocus(target); }); } }); _defineProperty(this, "setFocus", function () { var selector = _this.options.selector; if (!selector) return; var target = _this.element.querySelector(selector); /* istanbul ignore else */ if (target) { window.requestAnimationFrame(function () { return _this.checkFocus(target); }); } }); if (!(_element instanceof HTMLElement)) { throw new TypeError('Invalid parameter: element must be an HTMLElement'); } this.element = _element; this.options = options; window.addEventListener('keydown', this.handleKeyDown, false); this.setFocus(); }; var JoyrideBeacon = /*#__PURE__*/function (_React$Component) { _inherits(JoyrideBeacon, _React$Component); var _super = _createSuper(JoyrideBeacon); function JoyrideBeacon(props) { var _this; _classCallCheck(this, JoyrideBeacon); _this = _super.call(this, props); _defineProperty(_assertThisInitialized(_this), "setBeaconRef", function (c) { _this.beacon = c; }); if (!props.beaconComponent) { var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); var css = "\n @keyframes joyride-beacon-inner {\n 20% {\n opacity: 0.9;\n }\n \n 90% {\n opacity: 0.7;\n }\n }\n \n @keyframes joyride-beacon-outer {\n 0% {\n transform: scale(1);\n }\n \n 45% {\n opacity: 0.7;\n transform: scale(0.75);\n }\n \n 100% {\n opacity: 0.9;\n transform: scale(1);\n }\n }\n "; style.type = 'text/css'; style.id = 'joyride-beacon-animation'; if (props.nonce !== undefined) { style.setAttribute('nonce', props.nonce); } style.appendChild(document.createTextNode(css)); head.appendChild(style); } return _this; } _createClass(JoyrideBeacon, [{ key: "componentDidMount", value: function componentDidMount() { var _this2 = this; var shouldFocus = this.props.shouldFocus; setTimeout(function () { if (is.domElement(_this2.beacon) && shouldFocus) { _this2.beacon.focus(); } }, 0); } }, { key: "componentWillUnmount", value: function componentWillUnmount() { var style = document.getElementById('joyride-beacon-animation'); if (style) { style.parentNode.removeChild(style); } } }, { key: "render", value: function render() { var _this$props = this.props, beaconComponent = _this$props.beaconComponent, locale = _this$props.locale, onClickOrHover = _this$props.onClickOrHover, styles = _this$props.styles; var props = { 'aria-label': locale.open, onClick: onClickOrHover, onMouseEnter: onClickOrHover, ref: this.setBeaconRef, title: locale.open }; var component; if (beaconComponent) { var BeaconComponent = beaconComponent; component = /*#__PURE__*/React.createElement(BeaconComponent, props); } else { component = /*#__PURE__*/React.createElement("button", _extends({ key: "JoyrideBeacon", className: "react-joyride__beacon", style: styles.beacon, type: "button" }, props), /*#__PURE__*/React.createElement("span", { style: styles.beaconInner }), /*#__PURE__*/React.createElement("span", { style: styles.beaconOuter })); } return component; } }]); return JoyrideBeacon; }(React.Component); var JoyrideSpotlight = function JoyrideSpotlight(_ref) { var styles = _ref.styles; return /*#__PURE__*/React.createElement("div", { key: "JoyrideSpotlight", className: "react-joyride__spotlight", style: styles }); }; var _excluded$2 = ["mixBlendMode", "zIndex"]; var JoyrideOverlay = /*#__PURE__*/function (_React$Component) { _inherits(JoyrideOverlay, _React$Component); var _super = _createSuper(JoyrideOverlay); function JoyrideOverlay() { var _this; _classCallCheck(this, JoyrideOverlay); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _super.call.apply(_super, [this].concat(args)); _defineProperty(_assertThisInitialized(_this), "_isMounted", false); _defineProperty(_assertThisInitialized(_this), "state", { mouseOverSpotlight: false, isScrolling: false, showSpotlight: true }); _defineProperty(_assertThisInitialized(_this), "handleMouseMove", function (e) { var mouseOverSpotlight = _this.state.mouseOverSpotlight; var _this$spotlightStyles = _this.spotlightStyles, height = _this$spotlightStyles.height, left = _this$spotlightStyles.left, position = _this$spotlightStyles.position, top = _this$spotlightStyles.top, width = _this$spotlightStyles.width; var offsetY = position === 'fixed' ? e.clientY : e.pageY; var offsetX = position === 'fixed' ? e.clientX : e.pageX; var inSpotlightHeight = offsetY >= top && offsetY <= top + height; var inSpotlightWidth = offsetX >= left && offsetX <= left + width; var inSpotlight = inSpotlightWidth && inSpotlightHeight; if (inSpotlight !== mouseOverSpotlight) { _this.updateState({ mouseOverSpotlight: inSpotlight }); } }); _defineProperty(_assertThisInitialized(_this), "handleScroll", function () { var target = _this.props.target; var element = getElement(target); if (_this.scrollParent !== document) { var isScrolling = _this.state.isScrolling; if (!isScrolling) { _this.updateState({ isScrolling: true, showSpotlight: false }); } clearTimeout(_this.scrollTimeout); _this.scrollTimeout = setTimeout(function () { _this.updateState({ isScrolling: false, showSpotlight: true }); }, 50); } else if (hasPosition(element, 'sticky')) { _this.updateState({}); } }); _defineProperty(_assertThisInitialized(_this), "handleResize", function () { clearTimeout(_this.resizeTimeout); _this.resizeTimeout = setTimeout(function () { if (!_this._isMounted) { return; } _this.forceUpdate(); }, 100); }); return _this; } _createClass(JoyrideOverlay, [{ key: "componentDidMount", value: function componentDidMount() { var _this$props = this.props; _this$props.debug; _this$props.disableScrolling; var disableScrollParentFix = _this$props.disableScrollParentFix, target = _this$props.target; var element = getElement(target); this.scrollParent = getScrollParent(element, disableScrollParentFix, true); this._isMounted = true; window.addEventListener('resize', this.handleResize); } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { var _this2 = this; var _this$props2 = this.props, lifecycle = _this$props2.lifecycle, spotlightClicks = _this$props2.spotlightClicks; var _treeChanges = treeChanges(prevProps, this.props), changed = _treeChanges.changed; /* istanbul ignore else */ if (changed('lifecycle', LIFECYCLE.TOOLTIP)) { this.scrollParent.addEventListener('scroll', this.handleScroll, { passive: true }); setTimeout(function () { var isScrolling = _this2.state.isScrolling; if (!isScrolling) { _this2.updateState({ showSpotlight: true }); } }, 100); } if (changed('spotlightClicks') || changed('disableOverlay') || changed('lifecycle')) { if (spotlightClicks && lifecycle === LIFECYCLE.TOOLTIP) { window.addEventListener('mousemove', this.handleMouseMove, false); } else if (lifecycle !== LIFECYCLE.TOOLTIP) { window.removeEventListener('mousemove', this.handleMouseMove); } } } }, { key: "componentWillUnmount", value: function componentWillUnmount() { this._isMounted = false; window.removeEventListener('mousemove', this.handleMouseMove); window.removeEventListener('resize', this.handleResize); clearTimeout(this.resizeTimeout); clearTimeout(this.scrollTimeout); this.scrollParent.removeEventListener('scroll', this.handleScroll); } }, { key: "spotlightStyles", get: function get() { var showSpotlight = this.state.showSpotlight; var _this$props3 = this.props, disableScrollParentFix = _this$props3.disableScrollParentFix, spotlightClicks = _this$props3.spotlightClicks, spotlightPadding = _this$props3.spotlightPadding, styles = _this$props3.styles, target = _this$props3.target; var element = getElement(target); var elementRect = getClientRect(element); var isFixedTarget = hasPosition(element); var top = getElementPosition(element, spotlightPadding, disableScrollParentFix); return _objectSpread2(_objectSpread2({}, isLegacy() ? styles.spotlightLegacy : styles.spotlight), {}, { height: Math.round(elementRect.height + spotlightPadding * 2), left: Math.round(elementRect.left - spotlightPadding), opacity: showSpotlight ? 1 : 0, pointerEvents: spotl