@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
398 lines (397 loc) • 14.9 kB
JavaScript
;
"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