UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

487 lines (486 loc) 17.2 kB
"use client"; import React, { useCallback, useContext, useEffect, useRef } from 'react'; import useMountEffect from "../../shared/helpers/useMountEffect.js"; import useUpdateEffect from "../../shared/helpers/useUpdateEffect.js"; import clsx from 'clsx'; import withComponentMarkers from "../../shared/helpers/withComponentMarkers.js"; import { useTheme, Context } from "../../shared/index.js"; import useId from "../../shared/helpers/useId.js"; import { validateDOMAttributes, processChildren, extendPropsWithContext, removeUndefinedProps } from "../../shared/component-helper.js"; import HeightAnimation from "../height-animation/HeightAnimation.js"; import { applySpacing } from "../space/SpacingUtils.js"; import Icon from "../icon/Icon.js"; import GlobalStatusProvider from "../global-status/GlobalStatusProvider.js"; import { skeletonDOMAttributes, createSkeletonClass } from "../skeleton/SkeletonHelper.js"; import { pickFormElementProps } from "../../shared/helpers/filterValidProps.js"; import ui from "../../style/themes/ui/properties.js"; import sbanken from "../../style/themes/sbanken/properties.js"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; const properties = { ui, sbanken }; const formStatusDefaultProps = { show: true, icon: 'error', iconSize: 'medium', size: 'default', state: 'error' }; function getContent(props) { if (props.text) { if (props.text === true) { return null; } return props.text; } return processChildren(props); } function correctStatus(state) { return state; } function getIcon({ state, icon, iconSize }) { if (typeof icon !== 'string') { return icon; } let IconToLoad = ErrorIcon; switch (correctStatus(state)) { case 'information': case 'success': IconToLoad = InfoIcon; break; case 'warning': IconToLoad = WarnIcon; break; case 'marketing': IconToLoad = MarketingIcon; break; case 'error': default: IconToLoad = ErrorIcon; } return _jsx(Icon, { icon: _jsx(IconToLoad, { title: null, state: state }), size: iconSize, inheritColor: false }); } function FormStatusComponent(ownProps) { const { ref, ...restOwnProps } = ownProps; const context = useContext(Context); const props = extendPropsWithContext({ ...formStatusDefaultProps, ...removeUndefinedProps({ ...restOwnProps }) }, formStatusDefaultProps, { skeleton: context === null || context === void 0 ? void 0 : context.skeleton }, pickFormElementProps(context === null || context === void 0 ? void 0 : context.formElement), context === null || context === void 0 ? void 0 : context.FormStatus); const { id: idProp, text, globalStatus, label, show, noAnimation, state: rawStateProp, widthElement, widthSelector, ...restOfProps } = props; const id = useId(idProp); const statusId = `${id}-gs`; const elementRef = useRef(null); const isMountedRef = useRef(false); const contentCacheRef = useRef(null); const stateCacheRef = useRef(undefined); const ownPropsRef = useRef(restOwnProps); ownPropsRef.current = restOwnProps; useEffect(() => { if (typeof ref === 'function') { ref(elementRef.current); } else if (ref) { ref.current = elementRef.current; } }); const shouldAnimate = noAnimation === false; const fillCache = useCallback(() => { const content = shouldAnimate && getContent(ownPropsRef.current); if (content && content !== contentCacheRef.current) { contentCacheRef.current = content; } const stateVal = shouldAnimate && correctStatus(rawStateProp); if (stateVal) { stateCacheRef.current = stateVal; } }, [shouldAnimate, rawStateProp]); const isReadyToGetVisible = useCallback((p = props) => { return p.show && getContent(p) ? true : false; }, [props.show, props.text, props.children]); const updateWidth = useCallback(() => { if (elementRef.current) { var _widthElement$current; setMaxWidthToElement({ element: elementRef.current, widthElement: (_widthElement$current = widthElement === null || widthElement === void 0 ? void 0 : widthElement.current) !== null && _widthElement$current !== void 0 ? _widthElement$current : null, widthSelector: widthSelector }); } }, [widthElement, widthSelector]); const propsRef = useRef(props); propsRef.current = props; const isReadyToGetVisibleRef = useRef(isReadyToGetVisible); isReadyToGetVisibleRef.current = isReadyToGetVisible; const globalStatusRef = useRef(null); useMountEffect(() => { var _context$FormStatus, _context$formElement; globalStatusRef.current = GlobalStatusProvider.init((globalStatus === null || globalStatus === void 0 ? void 0 : globalStatus.id) || (context === null || context === void 0 || (_context$FormStatus = context.FormStatus) === null || _context$FormStatus === void 0 || (_context$FormStatus = _context$FormStatus.globalStatus) === null || _context$FormStatus === void 0 ? void 0 : _context$FormStatus.id) || (context === null || context === void 0 || (_context$formElement = context.formElement) === null || _context$formElement === void 0 || (_context$formElement = _context$formElement.globalStatus) === null || _context$formElement === void 0 ? void 0 : _context$formElement.id) || 'main', provider => { const currentProps = propsRef.current; if (currentProps.state === 'error' && isReadyToGetVisibleRef.current()) { var _currentProps$globalS; provider.add({ state: currentProps.state, statusId, item: { itemId: id, text: ((_currentProps$globalS = currentProps.globalStatus) === null || _currentProps$globalS === void 0 ? void 0 : _currentProps$globalS.message) || currentProps.text || currentProps.children, statusAnchorLabel: currentProps.label, statusAnchorUrl: true }, ...currentProps.globalStatus }); } }); return () => { var _globalStatusRef$curr; (_globalStatusRef$curr = globalStatusRef.current) === null || _globalStatusRef$curr === void 0 || _globalStatusRef$curr.remove(statusId); }; }); useMountEffect(() => { isMountedRef.current = true; const init = () => { if (isMountedRef.current) { var _globalStatusRef$curr2; (_globalStatusRef$curr2 = globalStatusRef.current) === null || _globalStatusRef$curr2 === void 0 || _globalStatusRef$curr2.isReady(); updateWidth(); fillCache(); } }; if (document.readyState === 'complete') { init(); } else if (typeof window !== 'undefined') { window.addEventListener('load', init); } if (typeof window !== 'undefined') { window.addEventListener('resize', updateWidth); } return () => { isMountedRef.current = false; if (typeof window !== 'undefined') { window.removeEventListener('load', init); window.removeEventListener('resize', updateWidth); } }; }); const prevPropsRef = useRef(restOwnProps); useUpdateEffect(() => { var _prevProps$globalStat; const prevProps = prevPropsRef.current; prevPropsRef.current = restOwnProps; const state = props.state; const { children } = props; if (prevProps.text !== text || prevProps.children !== children || prevProps.show !== show || ((_prevProps$globalStat = prevProps.globalStatus) === null || _prevProps$globalStat === void 0 ? void 0 : _prevProps$globalStat.show) !== (globalStatus === null || globalStatus === void 0 ? void 0 : globalStatus.show) || prevProps.state !== state) { fillCache(); if (state === 'error') { if (show) { var _globalStatusRef$curr3; (_globalStatusRef$curr3 = globalStatusRef.current) === null || _globalStatusRef$curr3 === void 0 || _globalStatusRef$curr3.update(statusId, { state, statusId, item: { itemId: id, text: (globalStatus === null || globalStatus === void 0 ? void 0 : globalStatus.message) || text || children, statusAnchorLabel: label, statusAnchorUrl: true }, ...globalStatus }, { preventRestack: true }); } else if (!getContent(restOwnProps)) { var _globalStatusRef$curr4; (_globalStatusRef$curr4 = globalStatusRef.current) === null || _globalStatusRef$curr4 === void 0 || _globalStatusRef$curr4.remove(statusId); } } if (isReadyToGetVisible()) { updateWidth(); } } }); const state = correctStatus(rawStateProp) || stateCacheRef.current; const iconToRender = getIcon({ state, icon: restOfProps.icon, iconSize: restOfProps.iconSize }); const contentToRender = getContent(restOwnProps); const hasStringContent = typeof contentToRender === 'string' && contentToRender.length > 0; const { title, size, variant, className, stretch, shellSpace, textId, skeleton, role, icon: _icon, iconSize: _iconSize, ...rest } = restOfProps; const params = applySpacing(props, { className: clsx(`dnb-form-status dnb-form-status__size--${size}`, className, state && `dnb-form-status--${state}`, variant && `dnb-form-status__variant--${variant}`, stretch && 'dnb-form-status--stretch', hasStringContent && 'dnb-form-status--has-content'), id: !String(idProp).startsWith('null') ? id : null, title, role, ...rest }); if (!role) { switch (state) { case 'information': params.role = 'status'; break; default: params.role = 'alert'; } } const textParams = { className: clsx('dnb-form-status__text', createSkeletonClass('font', skeleton, context)), id: !String(textId).startsWith('null') ? textId : null }; const shellParams = applySpacing({ space: shellSpace }, { className: 'dnb-form-status__shell' }); skeletonDOMAttributes(params, skeleton, context); validateDOMAttributes(restOwnProps, params); validateDOMAttributes(null, textParams); return _jsx(HeightAnimation, { element: "span", open: isReadyToGetVisible(), animate: shouldAnimate, duration: 600, ...params, ref: elementRef, children: _jsxs("span", { ...shellParams, children: [iconToRender, _jsx("span", { ...textParams, children: contentToRender || contentCacheRef.current })] }) }); } FormStatusComponent.displayName = 'FormStatus'; const FormStatus = React.memo(FormStatusComponent); withComponentMarkers(FormStatus, { _supportsSpacingProps: true }); export default FormStatus; export const ErrorIcon = props => { var _useTheme; const { title = 'error' } = props || {}; const isSbankenTheme = ((_useTheme = useTheme()) === null || _useTheme === void 0 ? void 0 : _useTheme.name) === 'sbanken'; const fill = isSbankenTheme ? properties.sbanken['--sb-color-magenta'] : properties.ui['--color-fire-red']; const line = isSbankenTheme ? properties.sbanken['--sb-color-magenta-light-2'] : properties.ui['--color-white']; return _jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", ...props, children: [_jsx("title", { children: title }), _jsx("path", { d: "M23.625 17.864A3.547 3.547 0 0120.45 23H3.548a3.546 3.546 0 01-3.172-5.136l8.45-14.902a3.548 3.548 0 016.347 0l8.452 14.902z", fill: fill }), _jsx("path", { d: "M12 16.286a1.286 1.286 0 100 2.572 1.286 1.286 0 000-2.572z", fill: line }), _jsx("path", { d: "M12 13.818v-5", stroke: line, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }); }; export const WarnIcon = props => { var _useTheme2; const { title = 'error' } = props || {}; const isSbankenTheme = ((_useTheme2 = useTheme()) === null || _useTheme2 === void 0 ? void 0 : _useTheme2.name) === 'sbanken'; const fill = isSbankenTheme ? properties.sbanken['--sb-color-yellow-dark'] : properties.ui['--color-accent-yellow']; const line = isSbankenTheme ? properties.sbanken['--sb-color-black'] : properties.ui['--color-black-80']; return _jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", ...props, children: [_jsx("title", { children: title }), _jsx("path", { d: "M23.625 17.864A3.547 3.547 0 0120.45 23H3.548a3.546 3.546 0 01-3.172-5.136l8.45-14.902a3.548 3.548 0 016.347 0l8.452 14.902z", fill: fill }), _jsx("path", { d: "M12 16.286a1.286 1.286 0 100 2.572 1.286 1.286 0 000-2.572z", fill: line }), _jsx("path", { d: "M12 13.818v-5", stroke: line, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }); }; export const InfoIcon = props => { var _useTheme3; const { title = 'information' } = props || {}; const isSbankenTheme = ((_useTheme3 = useTheme()) === null || _useTheme3 === void 0 ? void 0 : _useTheme3.name) === 'sbanken'; let fill = isSbankenTheme ? properties.sbanken['--sb-color-green-dark-2'] : properties.ui['--color-sea-green']; if (props && (props === null || props === void 0 ? void 0 : props.state) === 'success') { fill = isSbankenTheme ? properties.sbanken['--sb-color-green-dark-3'] : properties.ui['--color-summer-green']; } const line = isSbankenTheme ? properties.sbanken['--sb-color-green-light-2'] : properties.ui['--color-white']; return _jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", ...props, children: [_jsx("title", { children: title }), _jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M11.268 0a11.25 11.25 0 105.566 21.017l6.112 2.91a.75.75 0 001-1l-2.911-6.112A11.234 11.234 0 0011.268 0z", fill: fill }), _jsx("circle", { cx: "11", cy: "6.5", r: ".5", fill: "#fff", stroke: line }), _jsx("path", { d: "M13.75 16H13a1.5 1.5 0 01-1.5-1.5v-3.75a.75.75 0 00-.75-.75H10", stroke: line, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }); }; export const MarketingIcon = props => { var _useTheme4; const { title = 'marketing' } = props || {}; const isSbankenTheme = ((_useTheme4 = useTheme()) === null || _useTheme4 === void 0 ? void 0 : _useTheme4.name) === 'sbanken'; const fill = isSbankenTheme ? properties.sbanken['--sb-color-violet-light'] : properties.ui['--color-black-80']; return _jsxs("svg", { width: "24", height: "24", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: [_jsx("title", { children: title }), _jsx("path", { d: "M6 15.25H4.5c-2.042 0-3.75-1.707-3.75-3.75S2.458 7.75 4.5 7.75H6v7.5ZM7.5 15.25c4.801 0 8.846 1.897 12.75 4.5V3.25c-3.904 2.603-7.949 4.5-12.75 4.5v7.5ZM23.25 10a.75.75 0 0 0-1.5 0h1.5Zm-1.5 3a.75.75 0 0 0 1.5 0h-1.5ZM8.483 21.043a.75.75 0 1 0 1.034-1.086l-1.034 1.086ZM21.75 10v3h1.5v-3h-1.5ZM6 15.25a8.058 8.058 0 0 0 2.483 5.793l1.034-1.086A6.559 6.559 0 0 1 7.5 15.25H6Z", fill: fill })] }); }; export function setMaxWidthToElement({ element, id = null, widthElement = null, widthSelector = null }) { if (!(element && typeof window !== 'undefined')) { return; } try { var _id; if (!id && !widthSelector) { id = element.getAttribute('id'); } widthSelector = widthSelector || ((_id = id) === null || _id === void 0 ? void 0 : _id.replace('-form-status', '')) || id; let width = sumElementWidth({ widthElement, widthSelector }); if (width > 40) { const maxWidth = 30 * 16; if (width < maxWidth) { width = maxWidth; } const remWidth = `${width / 16}rem`; const style = window.getComputedStyle(element); const hasCustomWidth = element.style.maxWidth ? false : style.minWidth !== '' && style.minWidth !== 'auto' || style.maxWidth !== '' && style.maxWidth !== 'none'; if (!hasCustomWidth) { element.style.maxWidth = remWidth; } } } catch (e) {} } function sumElementWidth({ widthElement, widthSelector }) { let width = 0; if (typeof document === 'undefined') { return width; } try { const ids = widthElement ? [widthElement] : widthSelector.split(/, |,/g); width = ids.reduce((acc, cur) => { const elem = typeof cur === 'string' ? cur[0] === '.' ? document.querySelector(cur) : document.getElementById(cur) : cur; let elemWidth = elem && elem.offsetWidth || parseFloat(String(window.getComputedStyle(elem).width)) || 0; if (/em|rem/.test(String(window.getComputedStyle(elem).width))) { elemWidth = parseFloat(String(window.getComputedStyle(elem).width)) * 16; } if (elemWidth > 0) { if (acc > 0) { acc += 16; } acc += elemWidth; } return acc; }, width); } catch (e) {} return width; } //# sourceMappingURL=FormStatus.js.map