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