UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

492 lines (491 loc) 17.3 kB
"use strict"; "use client"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _withComponentMarkers = _interopRequireDefault(require("../../shared/helpers/withComponentMarkers.js")); var _react = _interopRequireWildcard(require("react")); var _clsx = _interopRequireDefault(require("clsx")); var _componentHelper = require("../../shared/component-helper.js"); var _extendPropsWithContext = require("../../shared/helpers/extendPropsWithContext.js"); var _useMountEffect = _interopRequireDefault(require("../../shared/helpers/useMountEffect.js")); var _useIsomorphicLayoutEffect = require("../../shared/helpers/useIsomorphicLayoutEffect.js"); var _useId = _interopRequireDefault(require("../../shared/helpers/useId.js")); var _AlignmentHelper2 = _interopRequireDefault(require("../../shared/AlignmentHelper.js")); var _SpacingUtils = require("../space/SpacingUtils.js"); var _filterValidProps = require("../../shared/helpers/filterValidProps.js"); var _Suffix = _interopRequireDefault(require("../../shared/helpers/Suffix.js")); var _IconPrimary = _interopRequireDefault(require("../icon-primary/IconPrimary.js")); var _FormLabel = _interopRequireDefault(require("../form-label/FormLabel.js")); var _FormStatus = _interopRequireDefault(require("../form-status/FormStatus.js")); var _Button = _interopRequireDefault(require("../button/Button.js")); var _DrawerList = _interopRequireDefault(require("../../fragments/drawer-list/DrawerList.js")); var _DrawerListContext = _interopRequireDefault(require("../../fragments/drawer-list/DrawerListContext.js")); var _DrawerListProvider = _interopRequireDefault(require("../../fragments/drawer-list/DrawerListProvider.js")); var _DrawerListHelpers = require("../../fragments/drawer-list/DrawerListHelpers.js"); var _jsxRuntime = require("react/jsx-runtime"); var _AlignmentHelper; 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 dropdownDefaultProps = { id: null, title: 'Option Menu', variant: 'secondary', icon: null, iconSize: null, iconPosition: null, arrowPosition: null, label: null, labelDirection: 'vertical', labelSrOnly: null, status: null, statusState: 'error', statusProps: null, statusNoAnimation: null, globalStatus: null, ref: null, buttonRef: null, suffix: null, scrollable: true, focusable: false, maxHeight: null, direction: 'auto', skipPortal: null, portalClass: null, noAnimation: false, noScrollAnimation: false, preventSelection: false, independentWidth: false, size: 'default', align: null, triggerElement: null, data: null, defaultValue: null, value: 'initval', openOnFocus: false, preventClose: false, keepOpen: false, open: false, disabled: null, stretch: null, skeleton: null, className: null, children: null, onOpen: null, onClose: null, onChange: null, onSelect: null }; const DropdownInstance = _react.default.memo(function DropdownInstance({ externalRef, externalButtonRef, ...ownProps }) { const context = (0, _react.useContext)(_DrawerListContext.default); const elRef = (0, _react.useRef)(null); const wrapperRef = (0, _react.useRef)(null); const buttonRef = (0, _react.useRef)(null); const focusTimeoutRef = (0, _react.useRef)(null); const attributesRef = (0, _react.useRef)({}); const setRootRef = (0, _react.useCallback)(el => { elRef.current = el; if (typeof externalRef === 'function') { externalRef(el); } else if (externalRef) { externalRef.current = el; } }, [externalRef]); const setButtonRef = (0, _react.useCallback)(el => { buttonRef.current = el; if (typeof externalButtonRef === 'function') { externalButtonRef(el); } else if (externalButtonRef) { externalButtonRef.current = el; } }, [externalButtonRef]); const propsWithDefaults = { ...dropdownDefaultProps, ...(0, _componentHelper.removeUndefinedProps)({ ...ownProps }) }; const propsWithDefaultsRef = (0, _react.useRef)(propsWithDefaults); propsWithDefaultsRef.current = propsWithDefaults; (0, _useIsomorphicLayoutEffect.useIsomorphicLayoutEffect)(() => { if (propsWithDefaults.open) { context.drawerList.setWrapperElement(wrapperRef.current).setVisible(); } }, []); (0, _useMountEffect.default)(() => { return () => { if (focusTimeoutRef.current) { clearTimeout(focusTimeoutRef.current); } }; }); const setVisible = (0, _react.useCallback)(() => { context.drawerList.setWrapperElement(wrapperRef.current).setVisible(); }, [context.drawerList]); const setHidden = (0, _react.useCallback)((...args) => { context.drawerList.setHidden(...args); }, [context.drawerList]); const setFocus = (0, _react.useCallback)(args => { if (focusTimeoutRef.current) { clearTimeout(focusTimeoutRef.current); } focusTimeoutRef.current = setTimeout(() => { try { const element = buttonRef.current; if (element && typeof element.focus === 'function') { if (args.preventHideFocus !== true) { element.focus({ preventScroll: true }); } (0, _componentHelper.dispatchCustomElementEvent)({ props: propsWithDefaultsRef.current }, 'onCloseFocus', { element }); } } catch (e) {} }, 1); }, []); const onFocusHandler = (0, _react.useCallback)(() => { if (propsWithDefaults.openOnFocus) { setVisible(); } }, [propsWithDefaults.openOnFocus, setVisible]); const onBlurHandler = (0, _react.useCallback)(() => { if (propsWithDefaults.openOnFocus) { setHidden(); } }, [propsWithDefaults.openOnFocus, setHidden]); const onClickHandler = (0, _react.useCallback)(() => { if (propsWithDefaults.disabled) { return; } if (!context.drawerList.hidden && context.drawerList.isOpen) { setHidden(); } else { setVisible(); } }, [propsWithDefaults.disabled, context.drawerList.hidden, context.drawerList.isOpen, setHidden, setVisible]); const onTriggerKeyDownHandler = (0, _react.useCallback)(e => { switch (e.key) { case 'Enter': case ' ': e.preventDefault(); setVisible(); break; case 'ArrowUp': case 'ArrowDown': e.preventDefault(); setVisible(); break; case 'Escape': setHidden(); break; case 'Home': case 'End': case 'PageDown': case 'PageUp': e.preventDefault(); break; } }, [setVisible, setHidden]); const onCloseHandler = (0, _react.useCallback)((args = {}) => { const attributes = attributesRef.current || {}; const res = (0, _componentHelper.dispatchCustomElementEvent)({ props: propsWithDefaultsRef.current }, 'onClose', { ...args, attributes }); if (res !== false) { setFocus(args); } return res; }, [setFocus]); const onSelectHandler = (0, _react.useCallback)(args => { if (parseFloat(args.activeItem) > -1) { const attributes = attributesRef.current || {}; (0, _componentHelper.dispatchCustomElementEvent)({ props: propsWithDefaultsRef.current }, 'onSelect', { ...args, attributes }); } }, []); const onChangeHandler = (0, _react.useCallback)(args => { const attributes = attributesRef.current || {}; (0, _componentHelper.dispatchCustomElementEvent)({ props: propsWithDefaultsRef.current }, 'onChange', { ...args, attributes }); }, []); const getTitle = (title = null) => { const { data } = context.drawerList; if (data && data.length > 0) { const currentOptionData = (0, _DrawerListHelpers.getCurrentData)(context.drawerList.selectedItem, data); if (currentOptionData) { title = currentOptionData.selectedValue || (0, _DrawerListHelpers.parseContentTitle)(currentOptionData); } } return title; }; const props = (0, _extendPropsWithContext.extendPropsWithContext)(propsWithDefaults, dropdownDefaultProps, { skeleton: context === null || context === void 0 ? void 0 : context.skeleton }, context.getTranslation(propsWithDefaults).Dropdown, (0, _filterValidProps.pickFormElementProps)(context === null || context === void 0 ? void 0 : context.formElement), context.Dropdown); const { label, labelDirection, labelSrOnly, iconSize, size, fixedPosition, enableBodyLock, status, statusState, statusProps, statusNoAnimation, globalStatus, suffix, scrollable, focusable, keepOpen, preventClose, noAnimation, noScrollAnimation, arrowPosition, skipPortal, portalClass, triggerElement: CustomTrigger, independentWidth, preventSelection, maxHeight, defaultValue, className, disabled, stretch, skeleton, variant, title: _title, icon: _icon, align: _align, iconPosition: _iconPosition, openOnFocus: _openOnFocus, data: _data, children: _children, direction: _direction, id: _id, open: _open, value: _value, pageOffset: _pageOffset, observerElement: _observerElement, enableBodyLock: _enableBodyLock, listClass: _listClass, buttonRef: _buttonRef, ref: _ref, onOpen: _onOpen, onClose: _onClose, onFocus: _onFocus, onChange: _onChange, onSelect: _onSelect, onOpenFocus: _onOpenFocus, onCloseFocus: _onCloseFocus, externalRef: _externalRef, externalButtonRef: _externalButtonRef, ...attributes } = props; let { icon, iconPosition, align } = props; const handleAsMenu = preventSelection; const title = getTitle(_title); const isPopupMenu = !title; if (isPopupMenu) { icon = icon || 'chevron_down'; } if (isPopupMenu) { if (iconPosition !== 'right' && align !== 'right') { iconPosition = 'left'; align = 'left'; } } if (independentWidth && iconPosition !== 'left' && !align) { align = 'right'; } const { id, selectedItem, direction, open } = context.drawerList; const showStatus = (0, _componentHelper.getStatusState)(status); Object.assign(context.drawerList.attributes, (0, _componentHelper.validateDOMAttributes)(null, attributes)); const mainParams = (0, _SpacingUtils.applySpacing)(props, { className: (0, _clsx.default)(`dnb-dropdown dnb-dropdown--${direction} dnb-dropdown--icon-position-${iconPosition || 'right'} dnb-dropdown--${align || 'right'} dnb-form-component`, className, open && 'dnb-dropdown--open', labelDirection && `dnb-dropdown--${labelDirection}`, isPopupMenu && 'dnb-dropdown--is-popup', independentWidth && 'dnb-dropdown--independent-width', size && `dnb-dropdown--${size}`, stretch && `dnb-dropdown--stretch`, status && `dnb-dropdown__status--${statusState}`, showStatus && 'dnb-dropdown__form-status') }); const triggerParams = { className: 'dnb-dropdown__trigger', id, disabled, 'aria-haspopup': handleAsMenu ? true : 'listbox', 'aria-expanded': open, ...attributes, onFocus: onFocusHandler, onBlur: onBlurHandler, onClick: onClickHandler, onKeyDown: onTriggerKeyDownHandler }; if (open) { triggerParams['aria-controls'] = `${id}-ul`; } if (showStatus || suffix) { triggerParams['aria-describedby'] = (0, _componentHelper.combineDescribedBy)(triggerParams, showStatus ? id + '-status' : null, suffix ? id + '-suffix' : null); } if (label) { triggerParams['aria-labelledby'] = (0, _componentHelper.combineLabelledBy)(triggerParams, id + '-label', id); } (0, _componentHelper.validateDOMAttributes)(null, mainParams); (0, _componentHelper.validateDOMAttributes)(ownProps, triggerParams); attributesRef.current = (0, _componentHelper.validateDOMAttributes)(null, attributes); return (0, _jsxRuntime.jsxs)("span", { ref: setRootRef, ...mainParams, children: [label && (0, _jsxRuntime.jsx)(_FormLabel.default, { id: id + '-label', forId: id, text: label, labelDirection: labelDirection, srOnly: labelSrOnly, disabled: disabled, skeleton: skeleton, onClick: onClickHandler }), (0, _jsxRuntime.jsxs)("span", { className: "dnb-dropdown__inner", ref: wrapperRef, children: [_AlignmentHelper || (_AlignmentHelper = (0, _jsxRuntime.jsx)(_AlignmentHelper2.default, {})), (0, _jsxRuntime.jsx)(_FormStatus.default, { show: showStatus, id: id + '-form-status', globalStatus: globalStatus, label: label, textId: id + '-status', text: status, state: statusState, noAnimation: statusNoAnimation, skeleton: skeleton, ...statusProps }), (0, _jsxRuntime.jsxs)("span", { className: "dnb-dropdown__row", children: [(0, _jsxRuntime.jsxs)("span", { className: "dnb-dropdown__shell", children: [CustomTrigger ? (_react.default.createElement(CustomTrigger, triggerParams)) : (0, _jsxRuntime.jsx)(_Button.default, { variant: variant, status: status ? statusState : null, statusState: statusState, icon: false, size: size === 'default' ? 'medium' : size, ref: setButtonRef, customContent: (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [!isPopupMenu && (0, _jsxRuntime.jsx)("span", { className: "dnb-dropdown__text dnb-button__text", children: (0, _jsxRuntime.jsx)("span", { className: "dnb-dropdown__text__inner", children: title }) }), (0, _jsxRuntime.jsx)("span", { "aria-hidden": true, className: 'dnb-dropdown__icon' + (parseFloat(String(selectedItem)) === 0 ? " dnb-dropdown__icon--first" : ""), children: icon !== false && (0, _jsxRuntime.jsx)(_IconPrimary.default, { icon: icon || 'chevron_down', size: iconSize || (size === 'large' ? 'medium' : 'default') }) })] }), role: "combobox", title: (0, _componentHelper.convertJsxToString)(title) || undefined, ...triggerParams }), (0, _jsxRuntime.jsx)(_DrawerList.default, { id: id, role: handleAsMenu ? 'menu' : 'listbox', portalClass: portalClass, listClass: 'dnb-dropdown__list' + (variant === 'tertiary' ? " dnb-dropdown__list--tertiary" : ""), value: selectedItem, defaultValue: defaultValue, scrollable: scrollable, focusable: focusable, noAnimation: noAnimation, noScrollAnimation: noScrollAnimation, skipPortal: skipPortal, preventSelection: handleAsMenu, arrowPosition: arrowPosition || iconPosition || 'right', keepOpen: keepOpen, preventClose: preventClose, independentWidth: independentWidth || isPopupMenu, isPopup: isPopupMenu, alignDrawer: align || 'left', fixedPosition: fixedPosition, enableBodyLock: enableBodyLock, disabled: disabled, maxHeight: maxHeight, direction: direction, size: size, onChange: onChangeHandler, onSelect: onSelectHandler, onClose: onCloseHandler })] }), suffix && (0, _jsxRuntime.jsx)(_Suffix.default, { className: "dnb-dropdown__suffix", id: id + '-suffix', context: props, onClick: setHidden, children: suffix })] })] })] }); }); function Dropdown({ ref, buttonRef, ...props }) { const id = (0, _useId.default)(props.id); const { preventSelection, children, data } = props; return (0, _jsxRuntime.jsx)(_DrawerListProvider.default, { ...props, id: id, data: data || children, open: false, tagName: "dnb-dropdown", ignoreEvents: false, preventSelection: preventSelection, children: (0, _jsxRuntime.jsx)(DropdownInstance, { ...props, id: id, externalRef: ref, externalButtonRef: buttonRef }) }); } Dropdown.HorizontalItem = _DrawerList.default.HorizontalItem; (0, _withComponentMarkers.default)(Dropdown, { _formElement: true, _supportsSpacingProps: true }); var _default = exports.default = Dropdown; //# sourceMappingURL=Dropdown.js.map