Tour.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
  2. import _extends from "@babel/runtime/helpers/esm/extends";
  3. import _typeof from "@babel/runtime/helpers/esm/typeof";
  4. import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
  5. import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
  6. var _excluded = ["prefixCls", "steps", "defaultCurrent", "current", "onChange", "onClose", "onFinish", "open", "mask", "arrow", "rootClassName", "placement", "renderPanel", "gap", "animated", "scrollIntoViewOptions", "zIndex", "closeIcon", "closable", "builtinPlacements", "disabledInteraction"];
  7. import * as React from 'react';
  8. import Portal from '@rc-component/portal';
  9. import Trigger from '@rc-component/trigger';
  10. import classNames from 'classnames';
  11. import useLayoutEffect from "rc-util/es/hooks/useLayoutEffect";
  12. import useMergedState from "rc-util/es/hooks/useMergedState";
  13. import { useMemo } from 'react';
  14. import { useClosable } from "./hooks/useClosable";
  15. import useTarget from "./hooks/useTarget";
  16. import Mask from "./Mask";
  17. import { getPlacements } from "./placements";
  18. import TourStep from "./TourStep";
  19. import { getPlacement } from "./util";
  20. var CENTER_PLACEHOLDER = {
  21. left: '50%',
  22. top: '50%',
  23. width: 1,
  24. height: 1
  25. };
  26. var defaultScrollIntoViewOptions = {
  27. block: 'center',
  28. inline: 'center'
  29. };
  30. var Tour = function Tour(props) {
  31. var _props$prefixCls = props.prefixCls,
  32. prefixCls = _props$prefixCls === void 0 ? 'rc-tour' : _props$prefixCls,
  33. _props$steps = props.steps,
  34. steps = _props$steps === void 0 ? [] : _props$steps,
  35. defaultCurrent = props.defaultCurrent,
  36. current = props.current,
  37. onChange = props.onChange,
  38. onClose = props.onClose,
  39. _onFinish = props.onFinish,
  40. open = props.open,
  41. _props$mask = props.mask,
  42. mask = _props$mask === void 0 ? true : _props$mask,
  43. _props$arrow = props.arrow,
  44. arrow = _props$arrow === void 0 ? true : _props$arrow,
  45. rootClassName = props.rootClassName,
  46. placement = props.placement,
  47. renderPanel = props.renderPanel,
  48. gap = props.gap,
  49. animated = props.animated,
  50. _props$scrollIntoView = props.scrollIntoViewOptions,
  51. scrollIntoViewOptions = _props$scrollIntoView === void 0 ? defaultScrollIntoViewOptions : _props$scrollIntoView,
  52. _props$zIndex = props.zIndex,
  53. zIndex = _props$zIndex === void 0 ? 1001 : _props$zIndex,
  54. closeIcon = props.closeIcon,
  55. closable = props.closable,
  56. builtinPlacements = props.builtinPlacements,
  57. disabledInteraction = props.disabledInteraction,
  58. restProps = _objectWithoutProperties(props, _excluded);
  59. var triggerRef = React.useRef();
  60. var _useMergedState = useMergedState(0, {
  61. value: current,
  62. defaultValue: defaultCurrent
  63. }),
  64. _useMergedState2 = _slicedToArray(_useMergedState, 2),
  65. mergedCurrent = _useMergedState2[0],
  66. setMergedCurrent = _useMergedState2[1];
  67. var _useMergedState3 = useMergedState(undefined, {
  68. value: open,
  69. postState: function postState(origin) {
  70. return mergedCurrent < 0 || mergedCurrent >= steps.length ? false : origin !== null && origin !== void 0 ? origin : true;
  71. }
  72. }),
  73. _useMergedState4 = _slicedToArray(_useMergedState3, 2),
  74. mergedOpen = _useMergedState4[0],
  75. setMergedOpen = _useMergedState4[1];
  76. // Record if already rended in the DOM to avoid `findDOMNode` issue
  77. var _React$useState = React.useState(mergedOpen),
  78. _React$useState2 = _slicedToArray(_React$useState, 2),
  79. hasOpened = _React$useState2[0],
  80. setHasOpened = _React$useState2[1];
  81. var openRef = React.useRef(mergedOpen);
  82. useLayoutEffect(function () {
  83. if (mergedOpen) {
  84. if (!openRef.current) {
  85. setMergedCurrent(0);
  86. }
  87. setHasOpened(true);
  88. }
  89. openRef.current = mergedOpen;
  90. }, [mergedOpen]);
  91. var _ref = steps[mergedCurrent] || {},
  92. target = _ref.target,
  93. stepPlacement = _ref.placement,
  94. stepStyle = _ref.style,
  95. stepArrow = _ref.arrow,
  96. stepClassName = _ref.className,
  97. stepMask = _ref.mask,
  98. _ref$scrollIntoViewOp = _ref.scrollIntoViewOptions,
  99. stepScrollIntoViewOptions = _ref$scrollIntoViewOp === void 0 ? defaultScrollIntoViewOptions : _ref$scrollIntoViewOp,
  100. stepCloseIcon = _ref.closeIcon,
  101. stepClosable = _ref.closable;
  102. var mergedClosable = useClosable(stepClosable, stepCloseIcon, closable, closeIcon);
  103. var mergedMask = mergedOpen && (stepMask !== null && stepMask !== void 0 ? stepMask : mask);
  104. var mergedScrollIntoViewOptions = stepScrollIntoViewOptions !== null && stepScrollIntoViewOptions !== void 0 ? stepScrollIntoViewOptions : scrollIntoViewOptions;
  105. var _useTarget = useTarget(target, open, gap, mergedScrollIntoViewOptions),
  106. _useTarget2 = _slicedToArray(_useTarget, 2),
  107. posInfo = _useTarget2[0],
  108. targetElement = _useTarget2[1];
  109. var mergedPlacement = getPlacement(targetElement, placement, stepPlacement);
  110. // ========================= arrow =========================
  111. var mergedArrow = targetElement ? typeof stepArrow === 'undefined' ? arrow : stepArrow : false;
  112. var arrowPointAtCenter = _typeof(mergedArrow) === 'object' ? mergedArrow.pointAtCenter : false;
  113. useLayoutEffect(function () {
  114. var _triggerRef$current;
  115. (_triggerRef$current = triggerRef.current) === null || _triggerRef$current === void 0 ? void 0 : _triggerRef$current.forceAlign();
  116. }, [arrowPointAtCenter, mergedCurrent]);
  117. // ========================= Change =========================
  118. var onInternalChange = function onInternalChange(nextCurrent) {
  119. setMergedCurrent(nextCurrent);
  120. onChange === null || onChange === void 0 ? void 0 : onChange(nextCurrent);
  121. };
  122. var mergedBuiltinPlacements = useMemo(function () {
  123. if (builtinPlacements) {
  124. return typeof builtinPlacements === 'function' ? builtinPlacements({
  125. arrowPointAtCenter: arrowPointAtCenter
  126. }) : builtinPlacements;
  127. }
  128. return getPlacements(arrowPointAtCenter);
  129. }, [builtinPlacements, arrowPointAtCenter]);
  130. // ========================= Render =========================
  131. // Skip if not init yet
  132. if (targetElement === undefined || !hasOpened) {
  133. return null;
  134. }
  135. var handleClose = function handleClose() {
  136. setMergedOpen(false);
  137. onClose === null || onClose === void 0 ? void 0 : onClose(mergedCurrent);
  138. };
  139. var getPopupElement = function getPopupElement() {
  140. return /*#__PURE__*/React.createElement(TourStep, _extends({
  141. arrow: mergedArrow,
  142. key: "content",
  143. prefixCls: prefixCls,
  144. total: steps.length,
  145. renderPanel: renderPanel,
  146. onPrev: function onPrev() {
  147. onInternalChange(mergedCurrent - 1);
  148. },
  149. onNext: function onNext() {
  150. onInternalChange(mergedCurrent + 1);
  151. },
  152. onClose: handleClose,
  153. current: mergedCurrent,
  154. onFinish: function onFinish() {
  155. handleClose();
  156. _onFinish === null || _onFinish === void 0 ? void 0 : _onFinish();
  157. }
  158. }, steps[mergedCurrent], {
  159. closable: mergedClosable
  160. }));
  161. };
  162. var mergedShowMask = typeof mergedMask === 'boolean' ? mergedMask : !!mergedMask;
  163. var mergedMaskStyle = typeof mergedMask === 'boolean' ? undefined : mergedMask;
  164. // when targetElement is not exist, use body as triggerDOMNode
  165. var getTriggerDOMNode = function getTriggerDOMNode(node) {
  166. return node || targetElement || document.body;
  167. };
  168. return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Mask, {
  169. zIndex: zIndex,
  170. prefixCls: prefixCls,
  171. pos: posInfo,
  172. showMask: mergedShowMask,
  173. style: mergedMaskStyle === null || mergedMaskStyle === void 0 ? void 0 : mergedMaskStyle.style,
  174. fill: mergedMaskStyle === null || mergedMaskStyle === void 0 ? void 0 : mergedMaskStyle.color,
  175. open: mergedOpen,
  176. animated: animated,
  177. rootClassName: rootClassName,
  178. disabledInteraction: disabledInteraction
  179. }), /*#__PURE__*/React.createElement(Trigger, _extends({}, restProps, {
  180. builtinPlacements: mergedBuiltinPlacements,
  181. ref: triggerRef,
  182. popupStyle: stepStyle,
  183. popupPlacement: mergedPlacement,
  184. popupVisible: mergedOpen,
  185. popupClassName: classNames(rootClassName, stepClassName),
  186. prefixCls: prefixCls,
  187. popup: getPopupElement,
  188. forceRender: false,
  189. destroyPopupOnHide: true,
  190. zIndex: zIndex,
  191. getTriggerDOMNode: getTriggerDOMNode,
  192. arrow: !!mergedArrow
  193. }), /*#__PURE__*/React.createElement(Portal, {
  194. open: mergedOpen,
  195. autoLock: true
  196. }, /*#__PURE__*/React.createElement("div", {
  197. className: classNames(rootClassName, "".concat(prefixCls, "-target-placeholder")),
  198. style: _objectSpread(_objectSpread({}, posInfo || CENTER_PLACEHOLDER), {}, {
  199. position: 'fixed',
  200. pointerEvents: 'none'
  201. })
  202. }))));
  203. };
  204. export default Tour;