UNPKG

@atlaskit/modal-dialog

Version:

A modal dialog displays content that requires user interaction, in a layer above the page.

96 lines (92 loc) 4.16 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = useModalStack; var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _react = require("react"); var _useLazyCallback = _interopRequireDefault(require("@atlaskit/ds-lib/use-lazy-callback")); var _usePreviousValue = _interopRequireDefault(require("@atlaskit/ds-lib/use-previous-value")); var _useStateRef3 = _interopRequireDefault(require("@atlaskit/ds-lib/use-state-ref")); var _exitingPersistence = require("@atlaskit/motion/exiting-persistence"); /** * ________________________________________________ * | MAJOR VERSIONS WILL NOT KNOW ABOUT EACH OTHER! | * ------------------------------------------------ * * An array which holds references to all currently open modal dialogs. * This will only work for modal dialogs of the same major version, * as the reference will be different between them. * * E.g. V11 won't know about any from V12. */ var modalStackRegister = []; /** * Returns the position of the calling modal dialog in the modal dialog stack. * Stack index of `0` is the highest position in the stack, * with every higher number being behind in the stack. */ function useModalStack(_ref) { var onStackChange = _ref.onStackChange; var _useExitingPersistenc = (0, _exitingPersistence.useExitingPersistence)(), isExiting = _useExitingPersistenc.isExiting; var _useStateRef = (0, _useStateRef3.default)(0), _useStateRef2 = (0, _slicedToArray2.default)(_useStateRef, 2), stackIndexRef = _useStateRef2[0], setStackIndex = _useStateRef2[1]; var currentStackIndex = stackIndexRef.current; var previousStackIndex = (0, _usePreviousValue.default)(stackIndexRef.current); // We want to ensure this function **never changes** during the lifecycle of this component. // This is why it's assigned to a ref and not in a useMemo/useCallback. var updateStack = (0, _useLazyCallback.default)(function () { var newStackIndex = modalStackRegister.indexOf(updateStack); // We access the stack index ref instead of state because this closure will always only // have the initial state and not any of the later values. if (stackIndexRef.current !== newStackIndex) { setStackIndex(newStackIndex); stackIndexRef.current = newStackIndex; } }); (0, _react.useEffect)(function () { var currentStackIndex = modalStackRegister.indexOf(updateStack); if (!isExiting && currentStackIndex === -1) { // We are opening the modal dialog. // Add ourselves to the modal stack register! modalStackRegister.unshift(updateStack); } if (isExiting && currentStackIndex !== -1) { // We are closing the modal dialog using a wrapping modal transition component. // Remove ourselves from the modal stack register! // NOTE: Modal dialogs that don't have a wrapping modal transition component won't flow through here! // For that scenario we cleanup when the component unmounts. modalStackRegister.splice(currentStackIndex, 1); } // Fire all registered modal dialogs to update their position in the stack. modalStackRegister.forEach(function (cb) { return cb(); }); }, [updateStack, isExiting]); (0, _react.useEffect)(function () { return function () { // Final cleanup just in case this modal dialog did not have a wrapping modal transition. var currentStackIndex = modalStackRegister.indexOf(updateStack); if (currentStackIndex !== -1) { modalStackRegister.splice(currentStackIndex, 1); modalStackRegister.forEach(function (cb) { return cb(); }); } }; }, [updateStack]); (0, _react.useEffect)(function () { if (previousStackIndex === undefined) { // Initial case that we don't need to notify about. return; } if (previousStackIndex !== currentStackIndex) { onStackChange(currentStackIndex); } }, [onStackChange, previousStackIndex, currentStackIndex]); return currentStackIndex; }