@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
495 lines (494 loc) • 20.6 kB
JavaScript
"use strict";
"use client";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _classnames = _interopRequireDefault(require("classnames"));
var _Context = _interopRequireDefault(require("../../shared/Context.js"));
var _componentHelper = require("../../shared/component-helper.js");
var _HeightAnimation = _interopRequireDefault(require("../height-animation/HeightAnimation.js"));
var _SkeletonHelper = require("../skeleton/SkeletonHelper.js");
var _SpacingHelper = require("../space/SpacingHelper.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 _Hr;
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 }; }
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
class GlobalStatus extends _react.default.PureComponent {
static getIcon({
state,
icon,
icon_size
}) {
if (typeof icon === 'string') {
let IconToLoad = icon;
switch (state) {
case 'info':
case 'information':
case 'success':
IconToLoad = _FormStatus.InfoIcon;
break;
case 'warning':
case 'warn':
IconToLoad = _FormStatus.WarnIcon;
break;
case 'error':
default:
IconToLoad = _FormStatus.ErrorIcon;
}
icon = _react.default.createElement(_Icon.default, {
icon: _react.default.createElement(IconToLoad, {
state: state
}),
size: icon_size,
inheritColor: false
});
}
return icon;
}
static getDerivedStateFromProps(props, state) {
if (state._items !== props.items) {
state.globalStatus = _GlobalStatusProvider.default.combineMessages([state.globalStatus, props]);
}
state._items = props.items;
return state;
}
constructor(props) {
super(props);
_defineProperty(this, "state", {
globalStatus: null,
isActive: false
});
_defineProperty(this, "isPassive", () => {
return this.props.show !== 'auto' && (0, _componentHelper.isTrue)(this.props.show) === false;
});
_defineProperty(this, "setVisible", () => {
if (this.isPassive()) {
return;
}
this.setState({
isActive: true
});
});
_defineProperty(this, "setHidden", () => {
this.setState({
isActive: false
});
});
_defineProperty(this, "onKeyDownHandler", e => {
switch ((0, _componentHelper.keycode)(e)) {
case 'escape':
case 'esc':
e.preventDefault();
this.closeHandler();
break;
}
});
_defineProperty(this, "closeHandler", () => {
this.provider.add({
status_id: 'internal-close',
show: false
});
if (this.initialActiveElement) {
try {
this.initialActiveElement.focus();
this.initialActiveElement = null;
} catch (e) {
(0, _componentHelper.warn)(e);
}
}
(0, _componentHelper.dispatchCustomElementEvent)(this._globalStatus, 'on_hide', this._globalStatus);
});
_defineProperty(this, "gotoItem", (event, item) => {
event.persist();
const keyCode = (0, _componentHelper.keycode)(event);
if (item.item_id && typeof document !== 'undefined' && typeof window !== 'undefined' && keyCode === 'space' || keyCode === 'enter' || typeof keyCode === 'undefined') {
event.preventDefault();
try {
const element = document.getElementById(item.item_id);
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);
}
}
});
_defineProperty(this, "itemsRenderHandler", ({
status_anchor_text,
lang
}) => (item, i) => {
const text = item !== null && item !== void 0 && item.text ? item.text : typeof item === 'string' ? item : null;
if (!text) {
return null;
}
const id = item.id || item.item_id ? `${item.item_id}-${i}` : (0, _componentHelper.makeUniqueId)();
let anchorText = status_anchor_text;
if (_react.default.isValidElement(item.status_anchor_label)) {
anchorText = _react.default.createElement(_react.default.Fragment, null, typeof status_anchor_text === 'string' ? status_anchor_text.replace('%s', '').trim() : status_anchor_text, ' ', item.status_anchor_label);
} else {
anchorText = String(item.status_anchor_text || status_anchor_text).replace('%s', item.status_anchor_label || '').replace(/[: ]$/g, '');
}
const useAutolink = item.item_id && (0, _componentHelper.isTrue)(item.status_anchor_url);
return _react.default.createElement("li", {
key: i
}, _react.default.createElement("p", {
id: id,
className: "dnb-p"
}, text), item && (useAutolink || item.status_anchor_url) && _react.default.createElement("a", {
className: "dnb-anchor",
"aria-describedby": id,
lang: lang,
href: useAutolink ? `#${item.item_id}` : item.status_anchor_url,
onClick: e => this.gotoItem(e, item),
onKeyDown: e => this.gotoItem(e, item)
}, anchorText));
});
_defineProperty(this, "onAnimationStart", state => {
this.setState({
isAnimating: true
});
switch (state) {
case 'opening':
this.scrollToStatus();
}
});
_defineProperty(this, "onAnimationEnd", state => {
switch (state) {
case 'opened':
this.setFocus();
(0, _componentHelper.dispatchCustomElementEvent)(this._globalStatus, 'on_open', this._globalStatus);
break;
case 'adjusted':
if (!(0, _componentHelper.isTrue)(this.props.omit_set_focus_on_update)) {
this.setFocus();
}
(0, _componentHelper.dispatchCustomElementEvent)(this._globalStatus, 'on_adjust', this._globalStatus);
break;
case 'closed':
(0, _componentHelper.dispatchCustomElementEvent)(this._globalStatus, 'on_close', this._globalStatus);
break;
}
});
_defineProperty(this, "onOpen", isOpened => {
if (isOpened) {
(0, _componentHelper.dispatchCustomElementEvent)(this._globalStatus, 'on_show', this._globalStatus);
}
});
this._wrapperRef = _react.default.createRef();
this.provider = _GlobalStatusProvider.default.create(props.id);
this.state.globalStatus = this._globalStatus = this.provider.init(props);
if ((0, _componentHelper.isTrue)(props.show)) {
this.state.isActive = true;
}
this.provider.onUpdate(globalStatus => {
if (globalStatus.on_close) {
this._globalStatus = globalStatus;
}
this.setState({
globalStatus
});
if ((0, _componentHelper.isTrue)(this.props.autoclose) && this._hadContent && !this.hasContent(globalStatus) && !(0, _componentHelper.isTrue)(this.props.show) || typeof globalStatus.show !== 'undefined' && !(0, _componentHelper.isTrue)(globalStatus.show)) {
this.setHidden();
} else if ((0, _componentHelper.isTrue)(this.props.show) || typeof globalStatus.show !== 'undefined' && (0, _componentHelper.isTrue)(globalStatus.show)) {
this._hadContent = this.hasContent(globalStatus);
this.setVisible();
}
});
this.initialActiveElement = null;
}
componentWillUnmount() {
clearTimeout(this._scrollToStatusTimeout);
this.provider.empty();
}
componentDidUpdate(prevProps) {
if (prevProps !== this.props) {
const globalStatus = (0, _componentHelper.extendPropsWithContextInClassComponent)(this.props, GlobalStatus.defaultProps, this.context.globalStatus);
this.setState({
globalStatus
});
}
if (prevProps.show !== this.props.show) {
if ((0, _componentHelper.isTrue)(this.props.show)) {
this.setVisible();
} else {
this.setHidden();
}
}
}
hasContent(globalStatus) {
var _globalStatus$items;
return Boolean(((_globalStatus$items = globalStatus.items) === null || _globalStatus$items === void 0 ? void 0 : _globalStatus$items.length) > 0 || globalStatus.text);
}
correctStatus(state) {
switch (state) {
case 'information':
state = 'info';
break;
}
return state;
}
setFocus() {
if (typeof document !== 'undefined' && document.activeElement !== this._wrapperRef.current) {
this.initialActiveElement = document.activeElement;
}
if (this._wrapperRef.current && !(0, _componentHelper.isTrue)(this.props.omit_set_focus)) {
this._wrapperRef.current.focus({
preventScroll: true
});
}
}
async scrollToStatus(isDone = null) {
if (typeof window === 'undefined' || (0, _componentHelper.isTrue)(this.state.globalStatus.autoscroll) === false) {
return;
}
try {
const element = this._wrapperRef.current;
this._scrollToStatusTimeout = isElementVisible(element, isDone);
if (element && typeof element.scrollIntoView === 'function') {
await wait(1);
element.scrollIntoView({
block: 'center',
behavior: 'smooth'
});
} else {
const top = element.offsetTop;
if (window.scrollTo) {
window.scrollTo({
top,
behavior: 'smooth'
});
} else {
window.scrollTop = top;
}
}
} catch (e) {
(0, _componentHelper.warn)('GlobalStatus: Could not scroll into view!', e);
}
}
render() {
var _this$context;
const {
isActive
} = this.state;
const fallbackProps = (0, _componentHelper.extendPropsWithContextInClassComponent)(this.props, GlobalStatus.defaultProps, this.context.getTranslation(this.props).GlobalStatus);
const props = (0, _componentHelper.extendPropsWithContextInClassComponent)(_GlobalStatusProvider.default.combineMessages([this.context.globalStatus, this.state.globalStatus]), GlobalStatus.defaultProps, fallbackProps);
const lang = this.context.locale;
const {
title,
default_title,
state: rawState,
className,
no_animation,
hide_close_button,
close_text,
status_anchor_text,
skeleton,
id,
item,
items,
autoclose,
show,
delay,
autoscroll,
text,
icon,
icon_size,
children,
...attributes
} = props;
const wrapperParams = {
id,
key: 'global-status',
className: (0, _classnames.default)("dnb-global-status__wrapper dnb-no-focus", (0, _SkeletonHelper.createSkeletonClass)('font', skeleton, this.context), (0, _SpacingHelper.createSpacingClasses)(props), className),
'aria-live': isActive ? 'assertive' : 'off',
onKeyDown: this.onKeyDownHandler,
tabIndex: '-1'
};
const state = this.correctStatus(rawState);
const iconToRender = GlobalStatus.getIcon({
state,
icon: icon || fallbackProps.icon,
icon_size: icon_size || fallbackProps.icon_size,
theme: ((_this$context = this.context) === null || _this$context === void 0 || (_this$context = _this$context.theme) === null || _this$context === void 0 ? void 0 : _this$context.name) || 'ui'
});
const titleToRender = title || fallbackProps.title || fallbackProps.default_title;
const noAnimation = (0, _componentHelper.isTrue)(no_animation);
const itemsToRender = props.items || [];
const contentToRender = props.text || props.children;
const params = {
className: `dnb-global-status dnb-global-status--${state}`,
...attributes
};
(0, _SkeletonHelper.skeletonDOMAttributes)(params, skeleton, this.context);
(0, _componentHelper.validateDOMAttributes)(this.props, params);
const renderedItems = itemsToRender.length > 0 && _react.default.createElement("ul", {
className: "dnb-ul"
}, itemsToRender.map(this.itemsRenderHandler({
status_anchor_text,
lang
})));
const hasContent = renderedItems || contentToRender;
const renderedContent = _react.default.createElement(_react.default.Fragment, null, title !== false && _react.default.createElement(_react.default.Fragment, null, _react.default.createElement("div", {
className: "dnb-global-status__title",
role: titleToRender !== null && titleToRender !== void 0 && titleToRender.type ? undefined : 'paragraph',
lang: lang
}, _react.default.createElement("span", {
className: "dnb-global-status__icon"
}, iconToRender), titleToRender, !(0, _componentHelper.isTrue)(hide_close_button) && _react.default.createElement(_Button.default, {
text: close_text,
title: close_text,
variant: state === 'success' ? 'secondary' : 'tertiary',
className: "dnb-global-status__close-button",
icon: "close",
on_click: this.closeHandler,
size: "medium",
icon_position: "left"
})), hasContent && _react.default.createElement("div", {
className: "dnb-global-status__message"
}, _react.default.createElement("div", {
className: 'dnb-global-status__message__content' + (!renderedItems ? " dnb-space__bottom--small" : "")
}, typeof contentToRender === 'string' ? _react.default.createElement("p", {
className: "dnb-p"
}, contentToRender) : contentToRender, renderedItems)), _Hr || (_Hr = _react.default.createElement(_Hr2.default, {
breakout: true
}))));
return _react.default.createElement("div", _extends({}, wrapperParams, {
ref: this._wrapperRef
}), _react.default.createElement("section", params, _react.default.createElement(_HeightAnimation.default, {
className: "dnb-global-status__shell",
duration: 800,
delay: delay,
open: isActive,
animate: !noAnimation,
onAnimationEnd: this.onAnimationEnd,
onAnimationStart: this.onAnimationStart,
onOpen: this.onOpen
}, _react.default.createElement(_Section.default, {
element: "div",
variant: state,
className: "dnb-global-status__content"
}, renderedContent))));
}
}
exports.default = GlobalStatus;
_defineProperty(GlobalStatus, "contextType", _Context.default);
_defineProperty(GlobalStatus, "defaultProps", {
id: 'main',
status_id: 'status-main',
title: null,
default_title: null,
text: null,
items: [],
icon: 'error',
icon_size: 'medium',
state: 'error',
show: 'auto',
autoscroll: true,
autoclose: true,
no_animation: false,
close_text: 'Lukk',
hide_close_button: false,
omit_set_focus: false,
omit_set_focus_on_update: true,
delay: null,
status_anchor_text: null,
skeleton: null,
className: null,
children: null,
on_adjust: null,
on_open: null,
on_show: null,
on_close: null,
on_hide: null
});
process.env.NODE_ENV !== "production" ? GlobalStatus.propTypes = {
id: _propTypes.default.string,
status_id: _propTypes.default.string,
title: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.bool]),
default_title: _propTypes.default.string,
text: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func, _propTypes.default.node]),
items: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func, _propTypes.default.array]),
icon: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func, _propTypes.default.node]),
icon_size: _propTypes.default.string,
state: _propTypes.default.oneOf(['error', 'info', 'warning', 'success']),
show: _propTypes.default.oneOf(['auto', true, false, 'true', 'false']),
autoscroll: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
autoclose: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
no_animation: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
delay: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]),
close_text: _propTypes.default.node,
hide_close_button: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
omit_set_focus: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
omit_set_focus_on_update: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
status_anchor_text: _propTypes.default.node,
skeleton: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
..._SpacingHelper.spacingPropTypes,
className: _propTypes.default.string,
children: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func, _propTypes.default.node]),
on_adjust: _propTypes.default.func,
on_open: _propTypes.default.func,
on_show: _propTypes.default.func,
on_close: _propTypes.default.func,
on_hide: _propTypes.default.func
} : void 0;
GlobalStatus.create = (...args) => new _GlobalStatusController.GlobalStatusInterceptor(...args);
GlobalStatus.Update = GlobalStatus.create;
GlobalStatus.Add = _GlobalStatusController.default;
GlobalStatus.Remove = _GlobalStatusController.default.Remove;
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));
GlobalStatus._supportsSpacingProps = true;
//# sourceMappingURL=GlobalStatus.js.map