UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

479 lines 18.5 kB
import _extends from "@babel/runtime-corejs3/helpers/esm/extends"; import _defineProperty from "@babel/runtime-corejs3/helpers/esm/defineProperty"; var _AlignmentHelper; import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { isTrue, makeUniqueId, extendPropsWithContextInClassComponent, validateDOMAttributes, getStatusState, combineDescribedBy, combineLabelledBy, dispatchCustomElementEvent, keycode, convertJsxToString } from "../../shared/component-helper.js"; import AlignmentHelper from "../../shared/AlignmentHelper.js"; import { spacingPropTypes, createSpacingClasses } from "../space/SpacingHelper.js"; import { pickFormElementProps } from "../../shared/helpers/filterValidProps.js"; import Suffix from "../../shared/helpers/Suffix.js"; import Icon from "../icon-primary/IconPrimary.js"; import FormLabel from "../form-label/FormLabel.js"; import FormStatus from "../form-status/FormStatus.js"; import Button, { buttonVariantPropType } from "../button/Button.js"; import DrawerList from "../../fragments/drawer-list/DrawerList.js"; import DrawerListContext from "../../fragments/drawer-list/DrawerListContext.js"; import DrawerListProvider from "../../fragments/drawer-list/DrawerListProvider.js"; import { drawerListPropTypes, drawerListProviderPropTypes, parseContentTitle, getCurrentData } from "../../fragments/drawer-list/DrawerListHelpers.js"; export default class Dropdown extends React.PureComponent { render() { const id = this.props.id || makeUniqueId(); const { more_menu, action_menu, prevent_selection, children, data } = this.props; return React.createElement(DrawerListProvider, _extends({}, this.props, { id: id, data: data || children, opened: false, tagName: "dnb-dropdown", ignore_events: false, prevent_selection: isTrue(more_menu) || isTrue(action_menu) || isTrue(prevent_selection) }), React.createElement(DropdownInstance, _extends({}, this.props, { id: id }))); } } _defineProperty(Dropdown, "defaultProps", { id: null, title: 'Option Menu', variant: 'secondary', icon: null, icon_size: null, icon_position: null, triangle_position: null, label: null, label_direction: null, label_sr_only: null, status: null, status_state: 'error', status_props: null, status_no_animation: null, globalStatus: null, innerRef: null, buttonRef: null, suffix: null, scrollable: true, focusable: false, max_height: null, direction: 'auto', skip_portal: null, portal_class: null, no_animation: false, no_scroll_animation: false, prevent_selection: false, more_menu: false, action_menu: false, independent_width: false, size: 'default', align_dropdown: null, trigger_element: null, data: null, default_value: null, value: 'initval', open_on_focus: false, prevent_close: false, keep_open: false, opened: false, disabled: null, stretch: null, skeleton: null, className: null, children: null, on_show: null, on_hide: null, on_change: null, on_select: null, on_state_update: null }); process.env.NODE_ENV !== "production" ? Dropdown.propTypes = { ...spacingPropTypes, ...drawerListPropTypes, ...drawerListProviderPropTypes, id: PropTypes.string, title: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), variant: buttonVariantPropType.variant, icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.func]), icon_size: PropTypes.string, icon_position: PropTypes.oneOf(['left', 'right']), triangle_position: PropTypes.oneOf(['left', 'right']), label: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.node]), label_direction: PropTypes.oneOf(['horizontal', 'vertical']), label_sr_only: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), status: PropTypes.oneOfType([PropTypes.string, PropTypes.bool, PropTypes.func, PropTypes.node]), status_state: PropTypes.string, status_props: PropTypes.object, status_no_animation: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), innerRef: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), buttonRef: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), globalStatus: PropTypes.shape({ id: PropTypes.string, message: PropTypes.oneOfType([PropTypes.string, PropTypes.node]) }), suffix: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.node]), scrollable: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), focusable: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), direction: PropTypes.oneOf(['auto', 'top', 'bottom']), max_height: PropTypes.number, skip_portal: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), portal_class: PropTypes.string, no_animation: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), no_scroll_animation: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), prevent_selection: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), more_menu: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), action_menu: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), independent_width: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), size: PropTypes.oneOf(['default', 'small', 'medium', 'large']), align_dropdown: PropTypes.oneOf(['left', 'right']), trigger_element: PropTypes.oneOfType([PropTypes.func, PropTypes.node]), data: PropTypes.oneOfType([PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.node, PropTypes.object]), PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.oneOfType([PropTypes.string, PropTypes.node]), PropTypes.shape({ selectedKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), selected_key: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), selected_value: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), content: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.arrayOf(PropTypes.string)]) })]))]), default_value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), open_on_focus: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), prevent_close: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), keep_open: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), opened: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), disabled: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), stretch: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), skeleton: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), className: PropTypes.string, children: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.node, PropTypes.object, PropTypes.array]), on_show: PropTypes.func, on_hide: PropTypes.func, on_change: PropTypes.func, on_select: PropTypes.func, on_state_update: PropTypes.func } : void 0; class DropdownInstance extends React.PureComponent { constructor(props) { super(props); _defineProperty(this, "setVisible", () => { this.context.drawerList.setWrapperElement(this._refWrapper.current).setVisible(); }); _defineProperty(this, "setHidden", (...args) => { this.context.drawerList.setHidden(...args); }); _defineProperty(this, "onFocusHandler", () => { if (isTrue(this.props.open_on_focus)) { this.setVisible(); } }); _defineProperty(this, "onBlurHandler", () => { if (isTrue(this.props.open_on_focus)) { this.setHidden(); } }); _defineProperty(this, "onClickHandler", () => { if (isTrue(this.props.disabled)) { return; } if (!this.context.drawerList.hidden && this.context.drawerList.isOpen) { this.setHidden(); } else { this.setVisible(); } }); _defineProperty(this, "onTriggerKeyDownHandler", e => { switch (keycode(e)) { case 'enter': case 'space': e.preventDefault(); this.setVisible(); break; case 'up': case 'down': e.preventDefault(); this.setVisible(); break; case 'escape': case 'esc': this.setHidden(); break; case 'home': case 'end': case 'page down': case 'page up': e.preventDefault(); break; } }); _defineProperty(this, "onHideHandler", (args = {}) => { const attributes = this.attributes || {}; const res = dispatchCustomElementEvent(this, 'on_hide', { ...args, attributes }); if (res !== false) { this.setFocus(args); } return res; }); _defineProperty(this, "setFocus", args => { clearTimeout(this._focusTimeout); this._focusTimeout = setTimeout(() => { try { const element = this._refButton.current; if (element && typeof element.focus === 'function') { if (args.preventHideFocus !== true) { element.focus({ preventScroll: true }); } dispatchCustomElementEvent(this, 'on_hide_focus', { element }); } } catch (e) {} }, 1); }); _defineProperty(this, "onSelectHandler", args => { if (parseFloat(args.active_item) > -1) { const attributes = this.attributes || {}; dispatchCustomElementEvent(this, 'on_select', { ...args, attributes }); } }); _defineProperty(this, "onChangeHandler", args => { const attributes = this.attributes || {}; dispatchCustomElementEvent(this, 'on_change', { ...args, attributes }); }); this.attributes = {}; this.state = this.state || {}; this._ref = props.innerRef || React.createRef(); this._refWrapper = React.createRef(); this._refButton = props.buttonRef || React.createRef(); } componentDidMount() { if (isTrue(this.props.opened)) { this.setVisible(); } } componentWillUnmount() { clearTimeout(this._focusTimeout); } getTitle(title = null) { const { data } = this.context.drawerList; if (data && data.length > 0) { const currentOptionData = getCurrentData(this.context.drawerList.selected_item, data); if (currentOptionData) { title = currentOptionData.selected_value || parseContentTitle(currentOptionData); } } return title; } render() { var _this$context, _this$context2, _this$context3; const props = extendPropsWithContextInClassComponent(this.props, Dropdown.defaultProps, { skeleton: (_this$context = this.context) === null || _this$context === void 0 ? void 0 : _this$context.skeleton }, this.context.getTranslation(this.props).Dropdown, pickFormElementProps((_this$context2 = this.context) === null || _this$context2 === void 0 ? void 0 : _this$context2.FormRow), pickFormElementProps((_this$context3 = this.context) === null || _this$context3 === void 0 ? void 0 : _this$context3.formElement), this.context.Dropdown); const { label, label_direction, label_sr_only, icon_size, size, fixed_position, enable_body_lock, status, status_state, status_props, status_no_animation, globalStatus, suffix, scrollable, focusable, keep_open, prevent_close, no_animation, no_scroll_animation, triangle_position, skip_portal, portal_class, trigger_element: CustomTrigger, more_menu, action_menu, independent_width, prevent_selection, max_height, default_value, className, disabled, stretch, skeleton, variant, title: _title, icon: _icon, align_dropdown: _align_dropdown, icon_position: _icon_position, data: _data, children: _children, direction: _direction, id: _id, opened: _opened, value: _value, buttonRef, innerRef, ...attributes } = props; let { icon, icon_position, align_dropdown } = props; const handleAsMenu = isTrue(action_menu) || isTrue(more_menu) || isTrue(prevent_selection); const title = this.getTitle(_title); const isPopupMenu = isTrue(more_menu) || !title; if (isPopupMenu) { icon = icon || (isTrue(more_menu) ? 'more' : 'chevron_down'); } if (isPopupMenu || isTrue(action_menu)) { if (icon_position !== 'right' && align_dropdown !== 'right') { icon_position = 'left'; align_dropdown = 'left'; } } if (isTrue(independent_width) && icon_position !== 'left' && !align_dropdown) { align_dropdown = 'right'; } const { id, selected_item, direction, opened } = this.context.drawerList; const showStatus = getStatusState(status); Object.assign(this.context.drawerList.attributes, validateDOMAttributes(null, attributes)); const mainParams = { className: classnames(`dnb-dropdown dnb-dropdown--${direction} dnb-dropdown--icon-position-${icon_position || 'right'} dnb-dropdown--${align_dropdown || 'right'} dnb-form-component`, (isTrue(independent_width) || isTrue(action_menu)) && 'dnb-dropdown--independent-width', createSpacingClasses(props), className, opened && 'dnb-dropdown--opened', label_direction && `dnb-dropdown--${label_direction}`, isPopupMenu && 'dnb-dropdown--is-popup', isTrue(action_menu) && `dnb-dropdown--action-menu`, size && `dnb-dropdown--${size}`, isTrue(stretch) && `dnb-dropdown--stretch`, status && `dnb-dropdown__status--${status_state}`, showStatus && 'dnb-dropdown__form-status') }; const triggerParams = { className: 'dnb-dropdown__trigger' + (opened ? " dnb-button--active" : ""), id, disabled, 'aria-haspopup': handleAsMenu ? true : 'listbox', 'aria-expanded': opened, ...attributes, onFocus: this.onFocusHandler, onBlur: this.onBlurHandler, onClick: this.onClickHandler, onKeyDown: this.onTriggerKeyDownHandler }; if (opened) { triggerParams['aria-controls'] = `${id}-ul`; } if (showStatus || suffix) { triggerParams['aria-describedby'] = combineDescribedBy(triggerParams, showStatus ? id + '-status' : null, suffix ? id + '-suffix' : null); } if (label) { triggerParams['aria-labelledby'] = combineLabelledBy(triggerParams, id + '-label', id); } validateDOMAttributes(null, mainParams); validateDOMAttributes(this.props, triggerParams); this.attributes = validateDOMAttributes(null, attributes); return React.createElement("span", _extends({ ref: this._ref }, mainParams), label && React.createElement(FormLabel, { id: id + '-label', forId: id, text: label, labelDirection: label_direction, srOnly: label_sr_only, disabled: disabled, skeleton: skeleton, onClick: this.onClickHandler }), React.createElement("span", { className: "dnb-dropdown__inner", ref: this._refWrapper }, _AlignmentHelper || (_AlignmentHelper = React.createElement(AlignmentHelper, null)), React.createElement(FormStatus, _extends({ show: showStatus, id: id + '-form-status', globalStatus: globalStatus, label: label, text_id: id + '-status', text: status, state: status_state, no_animation: status_no_animation, skeleton: skeleton }, status_props)), React.createElement("span", { className: "dnb-dropdown__row" }, React.createElement("span", { className: "dnb-dropdown__shell" }, CustomTrigger ? React.createElement(CustomTrigger, triggerParams) : React.createElement(Button, _extends({ variant: variant, icon: false, size: size === 'default' ? 'medium' : size, innerRef: this._refButton, custom_content: React.createElement(React.Fragment, null, !isPopupMenu && React.createElement("span", { className: "dnb-dropdown__text dnb-button__text" }, React.createElement("span", { className: "dnb-dropdown__text__inner" }, title)), React.createElement("span", { "aria-hidden": true, className: 'dnb-dropdown__icon' + (parseFloat(selected_item) === 0 ? " dnb-dropdown__icon--first" : "") }, icon !== false && React.createElement(Icon, { icon: icon || 'chevron_down', size: icon_size || (size === 'large' ? 'medium' : 'default') }))), role: "combobox", title: convertJsxToString(title) || undefined }, triggerParams)), React.createElement(DrawerList, { id: id, role: handleAsMenu ? 'menu' : 'listbox', portal_class: portal_class, list_class: 'dnb-dropdown__list' + (variant === 'tertiary' ? " dnb-dropdown__list--tertiary" : ""), value: selected_item, default_value: default_value, scrollable: scrollable, focusable: focusable, no_animation: no_animation, no_scroll_animation: no_scroll_animation, skip_portal: skip_portal, prevent_selection: handleAsMenu, action_menu: action_menu, triangle_position: triangle_position || icon_position || 'right', keep_open: keep_open, prevent_close: prevent_close, independent_width: isTrue(independent_width) || isPopupMenu || action_menu, is_popup: isPopupMenu || action_menu, align_drawer: align_dropdown || 'left', fixed_position: fixed_position, enable_body_lock: enable_body_lock, disabled: disabled, max_height: max_height, direction: direction, size: size, on_change: this.onChangeHandler, on_select: this.onSelectHandler, on_hide: this.onHideHandler })), suffix && React.createElement(Suffix, { className: "dnb-dropdown__suffix", id: id + '-suffix', context: props, onClick: this.setHidden }, suffix)))); } } _defineProperty(DropdownInstance, "defaultProps", Dropdown.defaultProps); _defineProperty(DropdownInstance, "contextType", DrawerListContext); process.env.NODE_ENV !== "production" ? DropdownInstance.propTypes = Dropdown.propTypes : void 0; Dropdown.HorizontalItem = DrawerList.HorizontalItem; Dropdown._formElement = true; Dropdown._supportsSpacingProps = true; //# sourceMappingURL=Dropdown.js.map