UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

398 lines (397 loc) 14.9 kB
"use strict"; "use client"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ANIMATION_DURATION = void 0; Object.defineProperty(exports, "CloseButton", { enumerable: true, get: function () { return _CloseButton.default; } }); exports.default = exports.OriginalComponent = void 0; var _push = _interopRequireDefault(require("core-js-pure/stable/instance/push.js")); var _react = _interopRequireWildcard(require("react")); var _useMountEffect = _interopRequireDefault(require("../../shared/helpers/useMountEffect.js")); var _clsx = _interopRequireDefault(require("clsx")); var _Suffix = require("../../shared/helpers/Suffix.js"); var _Context = _interopRequireDefault(require("../../shared/Context.js")); var _useId = _interopRequireDefault(require("../../shared/helpers/useId.js")); var _componentHelper = require("../../shared/component-helper.js"); var _SpacingUtils = require("../space/SpacingUtils.js"); var _HelpButtonInstance = _interopRequireDefault(require("../help-button/HelpButtonInstance.js")); var _helpers = require("./helpers.js"); var _ModalInner = _interopRequireDefault(require("./parts/ModalInner.js")); var _ModalHeader = _interopRequireDefault(require("./parts/ModalHeader.js")); var _ModalHeaderBar = _interopRequireDefault(require("./parts/ModalHeaderBar.js")); var _CloseButton = _interopRequireDefault(require("./parts/CloseButton.js")); var _ModalRoot = _interopRequireDefault(require("./ModalRoot.js")); var _P = require("../../elements/typography/P.js"); var _jsxRuntime = require("react/jsx-runtime"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const ANIMATION_DURATION = exports.ANIMATION_DURATION = 300; const modalDefaultProps = { spacing: true, dialogTitle: 'Vindu', closeTitle: 'Lukk', hideCloseButton: false, preventClose: false, preventCoreStyle: false, animationDuration: ANIMATION_DURATION, noAnimation: false, noAnimationOnMobile: false, fullscreen: 'auto', containerPlacement: null, alignContent: 'left', directDomReturn: false, omitTriggerButton: false }; function getContent(props) { if (typeof props.modalContent === 'string') { return props.modalContent; } else if (typeof props.modalContent === 'function') { return props.modalContent(props); } return (0, _componentHelper.processChildren)(props); } function ModalComponent(ownProps) { var _props$animationDurat, _props$noAnimation; const context = (0, _react.useContext)(_Context.default); const suffixContext = (0, _react.useContext)(_Suffix.SuffixContext); const visualTestsPropsOverride = typeof window !== 'undefined' && window['IS_TEST'] ? { animationDuration: 0, noAnimation: true } : {}; const props = (0, _componentHelper.extendPropsWithContext)({ ...modalDefaultProps, ...(0, _componentHelper.removeUndefinedProps)({ ...ownProps }) }, modalDefaultProps, context.getTranslation(ownProps).Modal, context.Modal, visualTestsPropsOverride); const { contentId = null, disabled = null, labelledBy = null, focusSelector = null, headerContent = null, barContent = null, bypassInvalidationSelectors = null, verticalAlignment = 'center', id: idProp, openDelay, omitTriggerButton = false, trigger = null, triggerAttributes = null, ref: _ref, ...rest } = props; const { open, openModal, closeModal, preventClose = false } = props; const fallbackId = (0, _useId.default)(idProp); const _id = (0, _react.useRef)(fallbackId); const triggerRef = (0, _react.useRef)(null); const modalContentCloseRef = (0, _react.useRef)(null); const onUnmountRef = (0, _react.useRef)([]); const activeElementRef = (0, _react.useRef)(null); const isInTransitionRef = (0, _react.useRef)(false); const openTimeoutRef = (0, _react.useRef)(null); const closeTimeoutRef = (0, _react.useRef)(null); const pendingSideEffectsRef = (0, _react.useRef)(null); const [hide, setHide] = (0, _react.useState)(false); const [modalActive, setModalActive] = (0, _react.useState)(false); const [preventAutoFocus, setPreventAutoFocus] = (0, _react.useState)(true); const animationDuration = typeof window !== 'undefined' && window['IS_TEST'] ? 0 : (_props$animationDurat = props.animationDuration) !== null && _props$animationDurat !== void 0 ? _props$animationDurat : ANIMATION_DURATION; const noAnimation = typeof window !== 'undefined' && window['IS_TEST'] ? true : (_props$noAnimation = props.noAnimation) !== null && _props$noAnimation !== void 0 ? _props$noAnimation : false; const stateRef = (0, _react.useRef)({ hide, modalActive, preventAutoFocus }); stateRef.current = { hide, modalActive, preventAutoFocus }; const propsRef = (0, _react.useRef)(props); propsRef.current = props; const removeActiveState = (0, _react.useCallback)(() => { const last = (0, _helpers.getModalRoot)(-1); if (last !== null && last !== void 0 && last._id && last._id !== _id.current) { return setActiveState(last._id); } try { document.documentElement.removeAttribute('data-dnb-modal-active'); } catch (e) { (0, _componentHelper.warn)('Modal: Error on remove "data-dnb-modal-active"', e); } }, []); const setActiveState = (0, _react.useCallback)(modalId => { if (!modalId) { (0, _componentHelper.warn)('Modal: A valid modalId is required'); } if (typeof document !== 'undefined') { try { document.documentElement.setAttribute('data-dnb-modal-active', modalId); } catch (e) { (0, _componentHelper.warn)('Modal: Error on set "data-dnb-modal-active"', e); } } }, []); const handleSideEffects = (0, _react.useCallback)((isModalActive, currentPreventAutoFocus) => { if (isModalActive) { if (typeof closeModal === 'function') { const fn = closeModal(() => { toggleOpenCloseRef.current(null, false); }, { _id: _id.current, props: propsRef.current }); if (fn) { var _context; (0, _push.default)(_context = onUnmountRef.current).call(_context, fn); } } setActiveState(_id.current); } else if (isModalActive === false && !currentPreventAutoFocus) { const focus = elem => { elem.setAttribute('data-autofocus', 'true'); elem.focus({ preventScroll: true }); return new Promise(resolve => { setTimeout(() => { elem === null || elem === void 0 || elem.removeAttribute('data-autofocus'); resolve(); }, parseFloat(String(animationDuration)) / 3); }); }; if (triggerRef !== null && triggerRef !== void 0 && triggerRef.current) { focus(triggerRef.current); } if (open === true && activeElementRef.current instanceof HTMLElement) { try { focus(activeElementRef.current).then(() => { activeElementRef.current = null; }); } catch (e) {} } removeActiveState(); } if (currentPreventAutoFocus) { setPreventAutoFocus(false); } }, [closeModal, open, animationDuration, removeActiveState, setActiveState]); const toggleOpenCloseRef = (0, _react.useRef)(null); const toggleOpenClose = (0, _react.useCallback)((event = null, showModal = null) => { if (event && 'preventDefault' in event) { event.preventDefault(); } const toggleNow = () => { const timeoutDuration = typeof animationDuration === 'string' ? parseFloat(animationDuration) : animationDuration; const newModalActive = typeof showModal === 'boolean' ? showModal : !stateRef.current.modalActive; isInTransitionRef.current = true; const doItNow = () => { setHide(false); setModalActive(newModalActive); isInTransitionRef.current = false; pendingSideEffectsRef.current = { isModalActive: newModalActive, preventAutoFocus: stateRef.current.preventAutoFocus }; }; if (newModalActive === false && !noAnimation) { setHide(true); closeTimeoutRef.current = setTimeout(doItNow, timeoutDuration); } else { doItNow(); } }; const waitBeforeOpen = () => { const delay = typeof openDelay === 'string' ? parseFloat(openDelay) : openDelay; if (delay > 0 && !noAnimation) { openTimeoutRef.current = setTimeout(toggleNow, delay); } else { toggleNow(); } }; clearTimeout(closeTimeoutRef.current); clearTimeout(openTimeoutRef.current); if (typeof openModal === 'function') { const fn = openModal(waitBeforeOpen, { _id: _id.current, props: propsRef.current }); if (fn) { var _context2; (0, _push.default)(_context2 = onUnmountRef.current).call(_context2, fn); } } else { waitBeforeOpen(); } }, [animationDuration, noAnimation, openDelay, openModal, handleSideEffects]); toggleOpenCloseRef.current = toggleOpenClose; const closeHandler = (0, _react.useCallback)((event, { ifIsLatest, triggeredBy = 'handler' } = { ifIsLatest: true }) => { var _modalContentCloseRef; (_modalContentCloseRef = modalContentCloseRef.current) === null || _modalContentCloseRef === void 0 || _modalContentCloseRef.call(modalContentCloseRef, event, { triggeredBy }); if (preventClose) { const id = _id.current; (0, _componentHelper.dispatchCustomElementEvent)(propsRef.current, 'onClosePrevent', { id, event, triggeredBy, close: e => { toggleOpenCloseRef.current(e, false); } }); } else { if (ifIsLatest) { const list = (0, _helpers.getListOfModalRoots)(); if (list.length > 1) { const last = (0, _helpers.getModalRoot)(-1); if (last !== modalStackIdentityRef.current) { return; } } } toggleOpenCloseRef.current(event, false); } }, [preventClose]); const modalStackIdentityRef = (0, _react.useRef)({ _id: _id.current }); const prevOpenRef = (0, _react.useRef)(undefined); if (open !== prevOpenRef.current) { if (open === true) { setHide(false); if (noAnimation) { setModalActive(true); } } else if (open === false) { setHide(true); if (noAnimation) { setModalActive(false); } } prevOpenRef.current = open; } const prevEffectOpenRef = (0, _react.useRef)(undefined); const prevOwnPropsRef = (0, _react.useRef)(undefined); (0, _react.useEffect)(() => { if (!activeElementRef.current && typeof document !== 'undefined') { activeElementRef.current = document.activeElement; } const isNewProps = prevOwnPropsRef.current !== undefined && prevOwnPropsRef.current !== ownProps; prevOwnPropsRef.current = ownProps; const openChanged = prevEffectOpenRef.current !== open; prevEffectOpenRef.current = open; if (!openChanged && !isNewProps) { return; } if (isInTransitionRef.current) { return; } if (!hide && open === true) { toggleOpenClose(null, true); } else if (hide && open === false) { toggleOpenClose(null, false); } }); (0, _react.useEffect)(() => { if (pendingSideEffectsRef.current) { const { isModalActive, preventAutoFocus } = pendingSideEffectsRef.current; pendingSideEffectsRef.current = null; handleSideEffects(isModalActive, preventAutoFocus); } }); (0, _useMountEffect.default)(() => { return () => { clearTimeout(openTimeoutRef.current); clearTimeout(closeTimeoutRef.current); removeActiveState(); onUnmountRef.current.forEach(fn => { if (typeof fn === 'function') { fn(); } }); }; }); const modalContent = getContent(typeof ownProps.children === 'function' ? Object.freeze({ ...ownProps, close: closeHandler }) : ownProps); const usedTriggerAttributes = { hidden: false, variant: 'secondary', iconPosition: 'left', ...triggerAttributes }; if (disabled) { usedTriggerAttributes.disabled = true; } if (usedTriggerAttributes.id) { _id.current = usedTriggerAttributes.id; } let fallbackTitle; if (usedTriggerAttributes.title) { fallbackTitle = usedTriggerAttributes.title; } else if (suffixContext) { fallbackTitle = context.translation.HelpButton.title; } const headerTitle = rest.title || fallbackTitle; const title = !(usedTriggerAttributes !== null && usedTriggerAttributes !== void 0 && usedTriggerAttributes.text) && headerTitle ? headerTitle || fallbackTitle : null; const TriggerButton = trigger ? trigger : _HelpButtonInstance.default; return (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [TriggerButton && !omitTriggerButton && (0, _jsxRuntime.jsx)(TriggerButton, { ...usedTriggerAttributes, ...(0, _SpacingUtils.applySpacing)(rest, { id: _id.current, title, onClick: event => toggleOpenClose(event.nativeEvent), ref: triggerRef, className: (0, _clsx.default)('dnb-modal__trigger', usedTriggerAttributes.className) }) }), modalActive && modalContent && (0, _jsxRuntime.jsx)(_P.ParagraphContext, { value: { isNested: false }, children: (0, _jsxRuntime.jsx)(_ModalRoot.default, { ...rest, id: _id.current, contentId: contentId || `dnb-modal-${_id.current}`, labelledBy: labelledBy, focusSelector: focusSelector, modalContent: modalContent, headerContent: headerContent, verticalAlignment: verticalAlignment, barContent: barContent, bypassInvalidationSelectors: bypassInvalidationSelectors, close: closeHandler, hide: hide, title: headerTitle, modalContentCloseRef: modalContentCloseRef }) })] }); } const Modal = exports.OriginalComponent = _react.default.memo(ModalComponent); Modal.Bar = _ModalHeaderBar.default; Modal.Header = _ModalHeader.default; Modal.Content = _ModalInner.default; var _default = exports.default = Modal; //# sourceMappingURL=Modal.js.map