UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

471 lines (470 loc) 17.7 kB
"use strict"; "use client"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _clsx = _interopRequireDefault(require("clsx")); var _withComponentMarkers = _interopRequireDefault(require("../../shared/helpers/withComponentMarkers.js")); var _useMountEffect = _interopRequireDefault(require("../../shared/helpers/useMountEffect.js")); var _useUpdateEffect = _interopRequireDefault(require("../../shared/helpers/useUpdateEffect.js")); var _Context = _interopRequireDefault(require("../../shared/Context.js")); var _componentHelper = require("../../shared/component-helper.js"); var _extendPropsWithContext = require("../../shared/helpers/extendPropsWithContext.js"); var _HeightAnimation = _interopRequireDefault(require("../height-animation/HeightAnimation.js")); var _SkeletonHelper = require("../skeleton/SkeletonHelper.js"); var _SpacingUtils = require("../space/SpacingUtils.js"); var _Hr2 = _interopRequireDefault(require("../../elements/hr/Hr.js")); var _GlobalStatusController = _interopRequireWildcard(require("./GlobalStatusController.js")); var _GlobalStatusProvider = _interopRequireDefault(require("./GlobalStatusProvider.js")); var _Icon = _interopRequireDefault(require("../icon/Icon.js")); var _FormStatus = require("../form-status/FormStatus.js"); var _Section = _interopRequireDefault(require("../section/Section.js")); var _Button = _interopRequireDefault(require("../button/Button.js")); var _Space = _interopRequireDefault(require("../space/Space.js")); var _jsxRuntime = require("react/jsx-runtime"); var _Hr; function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } 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); } const globalStatusDefaultProps = { id: 'main', statusId: 'status-main', title: null, defaultTitle: null, text: null, items: [], icon: 'error', iconSize: 'medium', state: 'error', show: 'auto', autoScroll: true, autoClose: true, noAnimation: false, closeText: 'Lukk', hideCloseButton: false, omitSetFocus: false, omitSetFocusOnUpdate: true, delay: null, statusAnchorText: null, skeleton: null, className: null, children: null, onAdjust: null, onOpen: null, onShow: null, onClose: null, onHide: null }; function getIcon({ state, icon, iconSize }) { if (typeof icon === 'string') { let IconToLoad = _FormStatus.ErrorIcon; switch (state) { case 'information': case 'success': IconToLoad = _FormStatus.InfoIcon; break; case 'warning': IconToLoad = _FormStatus.WarnIcon; break; case 'error': default: IconToLoad = _FormStatus.ErrorIcon; } icon = (0, _jsxRuntime.jsx)(_Icon.default, { icon: (0, _jsxRuntime.jsx)(IconToLoad, { state: state }), size: iconSize, inheritColor: false }); } return icon; } function hasContent(globalStatus) { var _globalStatus$items; return Boolean((globalStatus === null || globalStatus === void 0 || (_globalStatus$items = globalStatus.items) === null || _globalStatus$items === void 0 ? void 0 : _globalStatus$items.length) > 0 || (globalStatus === null || globalStatus === void 0 ? void 0 : globalStatus.text)); } function GlobalStatusComponent(ownProps) { var _derivedGlobalStatus, _context$theme; const context = (0, _react.useContext)(_Context.default); const wrapperRef = (0, _react.useRef)(null); const globalStatusRef = (0, _react.useRef)(null); const hadContentRef = (0, _react.useRef)(false); const initialActiveElementRef = (0, _react.useRef)(null); const scrollToStatusTimeoutRef = (0, _react.useRef)(null); const propsWithDefaults = { ...globalStatusDefaultProps, ...ownProps }; const propsRef = (0, _react.useRef)(propsWithDefaults); propsRef.current = propsWithDefaults; const providerRef = (0, _react.useRef)(null); const [providerGlobalStatus, setProviderGlobalStatus] = (0, _react.useState)(() => { var _ownProps$show; const provider = _GlobalStatusProvider.default.create(ownProps.id); providerRef.current = provider; const status = provider.init({ ...ownProps, show: (_ownProps$show = ownProps.show) !== null && _ownProps$show !== void 0 ? _ownProps$show : 'auto' }); globalStatusRef.current = status; return status; }); const [isActive, setIsActive] = (0, _react.useState)(ownProps.show === true); const [prevItems, setPrevItems] = (0, _react.useState)(ownProps.items); let derivedGlobalStatus = providerGlobalStatus; if (prevItems !== ownProps.items) { setPrevItems(ownProps.items); derivedGlobalStatus = _GlobalStatusProvider.default.combineMessages([providerGlobalStatus, ownProps]); setProviderGlobalStatus(derivedGlobalStatus); } if (ownProps.state !== ((_derivedGlobalStatus = derivedGlobalStatus) === null || _derivedGlobalStatus === void 0 ? void 0 : _derivedGlobalStatus.state)) { derivedGlobalStatus = { ...derivedGlobalStatus, state: ownProps.state }; } (0, _useMountEffect.default)(() => { const provider = providerRef.current; provider.onUpdate(status => { if (status.onClose) { globalStatusRef.current = status; } setProviderGlobalStatus(status); const props = propsRef.current; if (props.autoClose && hadContentRef.current && !hasContent(status) && props.show !== true || typeof status.show !== 'undefined' && status.show !== true) { setIsActive(false); } else if (props.show === true || typeof status.show !== 'undefined' && status.show === true) { hadContentRef.current = hasContent(status); if (props.show === 'auto' || props.show === true) { setIsActive(true); } } }); return () => { clearTimeout(scrollToStatusTimeoutRef.current); provider.empty(); }; }); (0, _useUpdateEffect.default)(() => { if (ownProps.show === true) { setIsActive(true); } else { setIsActive(false); } }, [ownProps.show]); const setFocus = (0, _react.useCallback)(() => { if (typeof document !== 'undefined' && document.activeElement !== wrapperRef.current) { initialActiveElementRef.current = document.activeElement; } if (wrapperRef.current && !propsRef.current.omitSetFocus) { wrapperRef.current.focus({ preventScroll: true }); } }, []); const closeHandler = (0, _react.useCallback)(() => { providerRef.current.add({ statusId: 'internal-close', show: false }); if (initialActiveElementRef.current) { try { ; initialActiveElementRef.current.focus(); initialActiveElementRef.current = null; } catch (e) { (0, _componentHelper.warn)(e); } } (0, _componentHelper.dispatchCustomElementEvent)(globalStatusRef.current, 'onHide', globalStatusRef.current); }, []); const scrollToStatus = (0, _react.useCallback)(async (isDone = null) => { if (typeof window === 'undefined' || propsRef.current.autoScroll === false) { return; } try { const element = wrapperRef.current; scrollToStatusTimeoutRef.current = isElementVisible(element, isDone); if (element && typeof element.scrollIntoView === 'function') { await wait(1); element.scrollIntoView({ block: 'center', behavior: 'smooth' }); } else { const top = element.offsetTop; window.scrollTo({ top, behavior: 'smooth' }); } } catch (e) { (0, _componentHelper.warn)('GlobalStatus: Could not scroll into view!', e); } }, []); const gotoItem = (0, _react.useCallback)((event, item) => { const key = event.key; if (item.itemId && typeof document !== 'undefined' && typeof window !== 'undefined' && key === ' ' || key === 'Enter' || key === undefined) { event.preventDefault(); try { const element = document.getElementById(item.itemId); if (!element) { return; } isElementVisible(element, elem => { try { elem.addEventListener('blur', e => { if (e.target.classList) { ; e.target.removeAttribute('tabindex'); } }); elem.classList.add('dnb-no-focus'); elem.setAttribute('tabindex', '-1'); elem.focus({ preventScroll: true }); } catch (e) { (0, _componentHelper.warn)(e); } }); if (typeof element.scrollIntoView === 'function') { element.scrollIntoView({ block: 'center', behavior: 'smooth' }); } } catch (e) { (0, _componentHelper.warn)(e); } } }, []); const onAnimationStart = (0, _react.useCallback)(state => { switch (state) { case 'opening': scrollToStatus(); } }, [scrollToStatus]); const onAnimationEnd = (0, _react.useCallback)(state => { switch (state) { case 'opened': setFocus(); (0, _componentHelper.dispatchCustomElementEvent)(globalStatusRef.current, 'onOpen', globalStatusRef.current); break; case 'adjusted': if (!propsRef.current.omitSetFocusOnUpdate) { setFocus(); } (0, _componentHelper.dispatchCustomElementEvent)(globalStatusRef.current, 'onAdjust', globalStatusRef.current); break; case 'closed': (0, _componentHelper.dispatchCustomElementEvent)(globalStatusRef.current, 'onClose', globalStatusRef.current); break; } }, [setFocus]); const onOpen = (0, _react.useCallback)(isOpened => { if (isOpened) { (0, _componentHelper.dispatchCustomElementEvent)(globalStatusRef.current, 'onShow', globalStatusRef.current); } }, []); const fallbackProps = (0, _extendPropsWithContext.extendPropsWithContext)(ownProps, globalStatusDefaultProps, context.getTranslation(ownProps).GlobalStatus); const props = (0, _extendPropsWithContext.extendPropsWithContext)(_GlobalStatusProvider.default.combineMessages([context === null || context === void 0 ? void 0 : context.globalStatus, derivedGlobalStatus]), globalStatusDefaultProps, fallbackProps); const lang = context.locale; const { title, defaultTitle, state: rawState, className, noAnimation, hideCloseButton, closeText, statusAnchorText, skeleton, id, item, items, autoClose, show, delay, autoScroll, text, omitSetFocus, omitSetFocusOnUpdate, statusId, icon, iconSize, children, removeOnUnmount, onAdjust: _onAdjust, onOpen: _onOpen, onShow: _onShow, onClose: _onClose, onHide: _onHide, ...attributes } = props; const wrapperParams = (0, _SpacingUtils.applySpacing)(props, { id, className: (0, _clsx.default)("dnb-global-status__wrapper dnb-no-focus", (0, _SkeletonHelper.createSkeletonClass)('font', skeleton, context), className), 'aria-live': isActive ? 'assertive' : 'off', onKeyDown: e => { if (e.key === 'Escape') { e.preventDefault(); closeHandler(); } }, tabIndex: -1 }); const state = rawState; const iconToRender = getIcon({ state, icon: icon || fallbackProps.icon, iconSize: iconSize || fallbackProps.iconSize, theme: (context === null || context === void 0 || (_context$theme = context.theme) === null || _context$theme === void 0 ? void 0 : _context$theme.name) || 'ui' }); const titleToRender = title || fallbackProps.title || fallbackProps.defaultTitle; const noAnimationUsed = noAnimation; const itemsToRender = items || []; const contentToRender = text || children; const params = { className: `dnb-global-status dnb-global-status--${state}`, ...attributes }; (0, _SkeletonHelper.skeletonDOMAttributes)(params, skeleton, context); (0, _componentHelper.validateDOMAttributes)(ownProps, params); const itemsRenderHandler = (rawItem, i) => { const item = typeof rawItem === 'string' ? { text: rawItem } : rawItem; const text = item.text; if (!text) { return null; } const id = item.id || item.itemId ? `${item.itemId}-${i}` : (0, _componentHelper.makeUniqueId)(); let anchorText = statusAnchorText; if (_react.default.isValidElement(item.statusAnchorLabel)) { anchorText = (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [typeof statusAnchorText === 'string' ? statusAnchorText.replace('%s', '').trim() : statusAnchorText, ' ', item.statusAnchorLabel] }); } else { anchorText = String(item.statusAnchorText || statusAnchorText).replace('%s', String(item.statusAnchorLabel || '')).replace(/[: ]$/g, ''); } const useAutolink = item.itemId && item.statusAnchorUrl === true; return (0, _jsxRuntime.jsxs)("li", { children: [(0, _jsxRuntime.jsx)("p", { id: id, className: "dnb-p", children: text }), item && (useAutolink || item.statusAnchorUrl) && (0, _jsxRuntime.jsx)("a", { className: "dnb-anchor", "aria-describedby": id, lang: lang, href: useAutolink ? `#${item.itemId}` : String(item.statusAnchorUrl), onClick: e => gotoItem(e, item), onKeyDown: e => gotoItem(e, item), children: anchorText })] }, i); }; const renderedItems = itemsToRender.length > 0 && (0, _jsxRuntime.jsx)("ul", { className: "dnb-ul", children: itemsToRender.map(itemsRenderHandler) }); const hasContentToRender = renderedItems || contentToRender; const renderedContent = (0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, { children: title !== false && (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [(0, _jsxRuntime.jsxs)("div", { className: "dnb-global-status__title", role: _react.default.isValidElement(titleToRender) ? undefined : 'paragraph', lang: lang, children: [(0, _jsxRuntime.jsx)("span", { className: "dnb-global-status__icon", children: iconToRender }), titleToRender, !hideCloseButton && (0, _jsxRuntime.jsx)(_Button.default, { text: closeText, title: typeof closeText === 'string' ? closeText : undefined, variant: state === 'success' ? 'secondary' : 'tertiary', className: "dnb-global-status__close-button", icon: "close", onClick: closeHandler, size: "medium", iconPosition: "left" })] }), hasContentToRender && (0, _jsxRuntime.jsx)("div", { className: "dnb-global-status__message", children: (0, _jsxRuntime.jsxs)(_Space.default, { element: "div", bottom: !renderedItems ? 'small' : undefined, className: "dnb-global-status__message__content", children: [typeof contentToRender === 'string' ? (0, _jsxRuntime.jsx)("p", { className: "dnb-p", children: contentToRender }) : contentToRender, renderedItems] }) }), _Hr || (_Hr = (0, _jsxRuntime.jsx)(_Hr2.default, { breakout: true }))] }) }); return (0, _react.createElement)("div", { ...wrapperParams, ref: wrapperRef, key: "global-status" }, (0, _jsxRuntime.jsx)("section", { ...params, children: (0, _jsxRuntime.jsx)(_HeightAnimation.default, { className: "dnb-global-status__shell", duration: 800, delay: delay, open: isActive, animate: !noAnimationUsed, onAnimationEnd: onAnimationEnd, onAnimationStart: onAnimationStart, onOpen: onOpen, children: (0, _jsxRuntime.jsx)(_Section.default, { element: "div", variant: state, className: "dnb-global-status__content", children: renderedContent }) }) })); } GlobalStatusComponent.displayName = 'GlobalStatus'; const GlobalStatus = Object.assign(_react.default.memo(GlobalStatusComponent), { create: props => new _GlobalStatusController.GlobalStatusInterceptor(props), Update: null, Add: _GlobalStatusController.default, Remove: _GlobalStatusController.GlobalStatusRemove }); GlobalStatus.Update = GlobalStatus.create; (0, _withComponentMarkers.default)(GlobalStatus, { _supportsSpacingProps: true }); var _default = exports.default = GlobalStatus; const isElementVisible = (elem, callback, delayFallback = 1e3) => { if (typeof IntersectionObserver !== 'undefined') { const intersectionObserver = new IntersectionObserver(entries => { const [entry] = entries; if (entry.isIntersecting) { intersectionObserver.unobserve(elem); if (typeof callback === 'function') { callback(elem); } } }); intersectionObserver.observe(elem); } else { if (typeof callback === 'function') { return setTimeout(() => callback(elem), delayFallback); } } return null; }; const wait = duration => new Promise(r => setTimeout(r, duration)); //# sourceMappingURL=GlobalStatus.js.map