UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

1,310 lines 59 kB
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties"; import _extends from "@babel/runtime/helpers/esm/extends"; import _defineProperty from "@babel/runtime/helpers/esm/defineProperty"; var _IconPrimary, _AlignmentHelper; const _excluded = ["fillDataIfEmpty"], _excluded2 = ["title", "placeholder", "label", "label_direction", "label_sr_only", "icon", "icon_size", "input_icon", "size", "align_autocomplete", "fixed_position", "status", "status_state", "status_props", "status_no_animation", "globalStatus", "suffix", "scrollable", "focusable", "keep_open", "keep_value", "keep_value_and_selection", "show_clear_button", "prevent_close", "no_animation", "no_scroll_animation", "show_submit_button", "submit_element", "input_element", "options_render", "prevent_selection", "max_height", "default_value", "search_numbers", "search_in_word_index", "show_options_sr", "selected_sr", "submit_button_title", "submit_button_icon", "portal_class", "drawer_class", "input_ref", "className", "disabled", "stretch", "skeleton", "triangle_position", "icon_position", "skip_portal", "independent_width", "mode", "data", "children", "direction", "id", "opened", "value", "input_value", "indicator_label", "no_options", "show_all", "aria_live_options", "disable_highlighting"]; import "core-js/modules/es.string.replace.js"; import "core-js/modules/web.dom-collections.iterator.js"; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { warn, isTrue, isTouchDevice, makeUniqueId, extendPropsWithContextInClassComponent, validateDOMAttributes, dispatchCustomElementEvent, getStatusState, combineDescribedBy, convertJsxToString, escapeRegexChars, getPreviousSibling, keycode } from '../../shared/component-helper'; import { IS_MAC, IS_WIN, IS_EDGE, debounce, hasSelectedText } from '../../shared/helpers'; import AlignmentHelper from '../../shared/AlignmentHelper'; import { spacingPropTypes, createSpacingClasses } from '../space/SpacingHelper'; import { pickFormElementProps } from '../../shared/helpers/filterValidProps'; import Suffix from '../../shared/helpers/Suffix'; import AriaLive from '../aria-live/AriaLive'; import FormLabel from '../form-label/FormLabel'; import FormStatus from '../form-status/FormStatus'; import IconPrimary from '../icon-primary/IconPrimary'; import Input, { SubmitButton } from '../input/Input'; import ProgressIndicator from '../progress-indicator/ProgressIndicator'; import DrawerList, { ItemContent } from '../../fragments/drawer-list/DrawerList'; import DrawerListContext from '../../fragments/drawer-list/DrawerListContext'; import DrawerListProvider from '../../fragments/drawer-list/DrawerListProvider'; import { drawerListPropTypes, parseContentTitle, getCurrentData, getCurrentIndex, normalizeData } from '../../fragments/drawer-list/DrawerListHelpers'; export default class Autocomplete extends React.PureComponent { constructor(props) { super(props); this._id = props.id || makeUniqueId(); } render() { return React.createElement(DrawerListProvider, _extends({}, this.props, { id: this._id, data: this.props.data || this.props.children, opened: null, tagName: "dnb-autocomplete", ignore_events: false, prevent_focus: true, skip_keysearch: true }), React.createElement(AutocompleteInstance, _extends({ id: this._id }, this.props))); } } _defineProperty(Autocomplete, "defaultProps", { id: null, mode: 'sync', title: 'Option Menu', placeholder: null, no_options: null, show_all: null, aria_live_options: null, indicator_label: null, show_options_sr: null, selected_sr: null, submit_button_title: null, submit_button_icon: 'chevron_down', input_ref: null, icon: null, icon_size: null, icon_position: 'left', triangle_position: null, input_icon: 'loupe', label: null, label_direction: null, label_sr_only: null, keep_value: null, keep_selection: null, keep_value_and_selection: null, show_clear_button: null, status: null, status_state: 'error', status_props: null, status_no_animation: null, globalStatus: null, suffix: null, disable_filter: false, disable_reorder: false, scrollable: true, focusable: false, disable_highlighting: false, max_height: null, direction: 'auto', skip_portal: null, no_animation: false, no_scroll_animation: false, show_submit_button: false, submit_element: null, prevent_selection: false, size: 'default', align_autocomplete: null, options_render: null, data: null, search_in_word_index: 3, search_numbers: null, default_value: null, value: 'initval', input_value: 'initval', open_on_focus: false, prevent_close: false, keep_open: false, opened: null, disabled: null, stretch: null, skeleton: null, portal_class: null, drawer_class: null, page_offset: null, observer_element: null, enable_body_lock: false, className: null, children: null, on_show: null, on_hide: null, on_type: null, on_focus: null, on_blur: null, on_change: null, on_select: null, on_state_update: null, input_element: null }); process.env.NODE_ENV !== "production" ? Autocomplete.propTypes = _objectSpread(_objectSpread(_objectSpread({}, spacingPropTypes), drawerListPropTypes), {}, { id: PropTypes.string, mode: PropTypes.oneOf(['sync', 'async']), title: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), placeholder: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), no_options: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), show_all: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), aria_live_options: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), indicator_label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), show_options_sr: PropTypes.string, selected_sr: PropTypes.string, submit_button_title: PropTypes.string, submit_button_icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.func]), input_ref: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), icon_size: PropTypes.string, icon_position: PropTypes.oneOf(['left', 'right']), triangle_position: PropTypes.oneOf(['left', 'right']), input_icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.func]), label: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.node]), label_direction: PropTypes.oneOf(['horizontal', 'vertical']), label_sr_only: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), keep_value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), keep_selection: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), keep_value_and_selection: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), show_clear_button: 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]), globalStatus: PropTypes.shape({ id: PropTypes.string, message: PropTypes.oneOfType([PropTypes.string, PropTypes.node]) }), suffix: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.node]), disable_filter: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), disable_reorder: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), scrollable: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), focusable: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), disable_highlighting: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), direction: PropTypes.oneOf(['auto', 'top', 'bottom']), max_height: PropTypes.number, skip_portal: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), no_animation: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), no_scroll_animation: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), show_submit_button: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), submit_element: PropTypes.node, prevent_selection: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), size: PropTypes.oneOf(['default', 'small', 'medium', 'large']), align_autocomplete: PropTypes.oneOf(['left', 'right']), options_render: PropTypes.oneOfType([PropTypes.object, PropTypes.func, PropTypes.node]), input_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]), suffix_value: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), content: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.arrayOf(PropTypes.string)]) })]))]), search_in_word_index: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), search_numbers: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), default_value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), input_value: PropTypes.string, 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]), portal_class: PropTypes.string, drawer_class: PropTypes.string, page_offset: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), observer_element: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), enable_body_lock: PropTypes.bool, class: PropTypes.string, className: PropTypes.string, children: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.node, PropTypes.object, PropTypes.array]), on_show: PropTypes.func, on_type: PropTypes.func, on_focus: PropTypes.func, on_blur: PropTypes.func, on_hide: PropTypes.func, on_change: PropTypes.func, on_select: PropTypes.func, on_state_update: PropTypes.func }) : void 0; class AutocompleteInstance extends React.PureComponent { static parseDataItem(dataItem) { const searchWord = parseContentTitle(dataItem.search_content || dataItem, { separator: ' ' }); if (typeof searchWord !== 'string' && Array.isArray(searchWord)) { return AutocompleteInstance.parseDataItem(searchWord); } return searchWord; } static createSearchIndex(data) { return data.map(dataItem => { const contentChunk = AutocompleteInstance.parseDataItem(dataItem); return { dataItem, contentChunk }; }); } static getCurrentDataTitle(selected_item, data) { const currentData = getCurrentData(selected_item, data); return parseContentTitle(currentData, { separator: ' ', preferSelectedValue: true }); } static getDerivedStateFromProps(props, state) { if (state._listenForPropChanges) { var _props$input_value, _props$data, _state$prevData; state.disableHighlighting = isTrue(props.disable_highlighting); if (props.input_value !== 'initval' && ((_props$input_value = props.input_value) === null || _props$input_value === void 0 ? void 0 : _props$input_value.length) > 0) { state.inputValue = props.input_value; } if ((props === null || props === void 0 ? void 0 : (_props$data = props.data) === null || _props$data === void 0 ? void 0 : _props$data.length) > 0 && (state === null || state === void 0 ? void 0 : (_state$prevData = state.prevData) === null || _state$prevData === void 0 ? void 0 : _state$prevData.length) === 0) { let selectedItem = state.selected_item; if (props.default_value) { selectedItem = props.default_value; } if (!props.default_value && props.value && props.value !== 'initval') { selectedItem = props.value; } const currentData = getCurrentData(selectedItem, normalizeData(props.data)); state.inputValue = parseContentTitle(currentData, { separator: ' ', preferSelectedValue: true }); } if (props.data !== state.prevData) { state.updateData(props.data); state.prevData = props.data; } } state._listenForPropChanges = true; return state; } constructor(_props, context) { var _this; super(_props); _this = this; _defineProperty(this, "setVisible", function () { let args = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; let onStateComplete = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; _this.context.drawerList.setWrapperElement(_this._ref.current).setVisible(args, onStateComplete); }); _defineProperty(this, "setHidden", function () { let args = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; let onStateComplete = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; _this.context.drawerList.setHidden(args, onStateComplete); _this.setState({ hasFocus: false, hasBlur: false }); }); _defineProperty(this, "toggleVisible", function () { let args = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; let onStateComplete = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; args = args || {}; if (typeof args.hasFilter === 'undefined') { args.hasFilter = false; } if (isTrue(_this.props.disabled)) { return; } if (!args.hasFilter && !isTrue(_this.props.prevent_close) && !_this.context.drawerList.hidden && _this.context.drawerList.isOpen) { _this.setHidden(null, onStateComplete); } else { _this.setVisibleByContext(null, onStateComplete); } }); _defineProperty(this, "toggleVisibleAndFocusOptions", () => { this.context.drawerList.toggleVisible(null, isVisible => { if (isVisible) { this.focusDrawerList(); } }); }); _defineProperty(this, "setVisibleByContext", function () { let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; let onStateComplete = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; const skipFilter = _this.state.showAllNextTime; if (skipFilter) { _this.setState({ showAllNextTime: false, _listenForPropChanges: false }); } _this.runFilterToHighlight(_objectSpread({ fillDataIfEmpty: true, skipFilter }, options)); _this.setVisible(null, onStateComplete); }); _defineProperty(this, "onInputChangeHandler", _ref => { let { value, event } = _ref; this.setState({ typedInputValue: value, inputValue: value, _listenForPropChanges: false }); dispatchCustomElementEvent(this, 'on_type', _objectSpread({ value, event }, this.getEventObjects('on_type'))); value = String(value).trim(); if (value !== this.state.inputValue) { this.runFilterWithSideEffects(value); } }); _defineProperty(this, "runFilterWithSideEffects", function (value) { let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; const data = _this.runFilter(value, options); const count = _this.countData(data); const { keep_value, keep_selection, keep_value_and_selection } = _this.props; if ((value === null || value === void 0 ? void 0 : value.length) > 0) { if (count === 0) { _this.showNoOptionsItem(); } else if (count > 0) { _this.context.drawerList.setData(_this.wrapWithShowAll(data)); _this.context.drawerList.setState({ cache_hash: value + count }); if (count === 1) { _this.context.drawerList.setState({ active_item: data[0].__id }); } } } else { if (!isTrue(keep_value) && !isTrue(keep_selection) && !isTrue(keep_value_and_selection)) { _this.totalReset(); } else if (isTrue(keep_value)) { _this.resetSelectedItem(); } _this.showAllItems(); } if (_this.state.hasFocus) { _this.setVisible(); } return data; }); _defineProperty(this, "runFilterToHighlight", function () { let _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; let value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _this.state.inputValue; let { fillDataIfEmpty = false } = _ref2, options = _objectWithoutProperties(_ref2, _excluded); const possibleTitle = AutocompleteInstance.getCurrentDataTitle(_this.context.drawerList.selected_item, _this.context.drawerList.original_data); if (value === possibleTitle) { return; } value = String(value || '').trim(); _this.setState({ disableHighlighting: false, _listenForPropChanges: false }); let data = _this.runFilter(value, options); if (fillDataIfEmpty && data.length === 0 && value === '') { data = _this.context.drawerList.original_data; } _this.context.drawerList.setData(_this.wrapWithShowAll(data)); _this.context.drawerList.setState({ cache_hash: value + _this.countData(data) }); return data; }); _defineProperty(this, "wrapWithShowAll", data => { if (!data || !this.hasFilterActive(data)) { return data; } const lastItem = this.context.drawerList.original_data.slice(-1)[0]; if (lastItem && !lastItem.show_all) { const lastActiveItem = data.slice(-1)[0]; if (lastActiveItem) { data.push({ __id: lastItem.__id + 1, lastActiveItem: lastActiveItem.__id, class_name: 'dnb-autocomplete__show-all', show_all: true, active_item: false, selected_item: false, content: React.createElement(React.Fragment, null, _IconPrimary || (_IconPrimary = React.createElement(IconPrimary, { icon: "arrow_down" })), this._props.show_all) }); } } return data; }); _defineProperty(this, "setInputValue", inputValue => { this.setState({ inputValue, _listenForPropChanges: false }); }); _defineProperty(this, "emptyData", () => { this._cacheMemory = {}; this.clearInputValue(); this.context.drawerList.setData(() => [], () => { this.setSearchIndex({ overwriteSearchIndex: true }); this.resetActiveItem(); this.totalReset(); }, { overwriteOriginalData: true }); }); _defineProperty(this, "clearInputValue", () => { this.setState({ inputValue: '', typedInputValue: null, _listenForPropChanges: false }); }); _defineProperty(this, "resetInputValue", () => { const { input_value, keep_value, keep_value_and_selection } = this.props; if (isTrue(keep_value) || isTrue(keep_value_and_selection) || input_value !== 'initval' && input_value.length > 0) { return; } clearTimeout(this._selectTimeout); this._selectTimeout = setTimeout(() => { if (this.hasSelectedItem()) { const inputValue = AutocompleteInstance.getCurrentDataTitle(this.context.drawerList.selected_item, this.context.drawerList.original_data); this.setInputValue(inputValue); } else { this.clearInputValue(); } }, 1); }); _defineProperty(this, "showNoOptionsItem", () => { if (this.state.mode === 'async') { return; } this.resetActiveItem(); this.ignoreEvents(); this.context.drawerList.setData([{ class_name: 'dnb-autocomplete__no-options', content: this._props.no_options, ignore_events: true, __id: 'no_options' }]); this.context.drawerList.setState({ cache_hash: 'no_options' }); this.setVisible(); }); _defineProperty(this, "showIndicatorItem", () => { this.resetActiveItem(); this.ignoreEvents(); this.context.drawerList.setData([{ class_name: 'dnb-autocomplete__indicator', content: React.createElement(ProgressIndicator, { label: this._props.indicator_label }), ignore_events: true, __id: 'indicator' }]); this.context.drawerList.setState({ cache_hash: 'indicator' }); this.setVisible(); }); _defineProperty(this, "showIndicator", () => { if (!this.state.visibleIndicator) { this.setState({ visibleIndicator: true, _listenForPropChanges: false }); } }); _defineProperty(this, "hideIndicator", () => { this.setState({ visibleIndicator: false, _listenForPropChanges: false }); }); _defineProperty(this, "setMode", mode => { this.setState({ mode, _listenForPropChanges: false }); }); _defineProperty(this, "revalidateInputValue", () => { const { input_value, value } = this.props; if (input_value && input_value !== 'initval') { return; } const selected_item = getCurrentIndex(value, this.context.drawerList.original_data); const inputValue = AutocompleteInstance.getCurrentDataTitle(selected_item, this.context.drawerList.original_data); this.setInputValue(inputValue); }); _defineProperty(this, "revalidateSelectedItem", () => { const selected_item = getCurrentIndex(this.props.value, this.context.drawerList.original_data); this.context.drawerList.setState({ selected_item }); }); _defineProperty(this, "hasDatasetChanged", rawData => { const { selected_item } = this.context.drawerList; if (parseFloat(selected_item) > -1) { const newItem = rawData === null || rawData === void 0 ? void 0 : rawData[selected_item]; const oldItem = this.context.drawerList.original_data[selected_item]; if (typeof (newItem === null || newItem === void 0 ? void 0 : newItem.selectedKey) !== 'undefined' ? (newItem === null || newItem === void 0 ? void 0 : newItem.selectedKey) !== (oldItem === null || oldItem === void 0 ? void 0 : oldItem.selectedKey) : (newItem === null || newItem === void 0 ? void 0 : newItem.selected_key) !== (oldItem === null || oldItem === void 0 ? void 0 : oldItem.selected_key)) { return true; } } return false; }); _defineProperty(this, "updateData", rawData => { const hasChanged = this.hasDatasetChanged(rawData); this.context.drawerList.setState({ cache_hash: 'updateData' }, () => { if (hasChanged) { const { value } = this.props; if (value && value !== 'initval') { this.revalidateSelectedItem(); this.revalidateInputValue(); } else { this.resetSelectedItem(); } } }); this.context.drawerList.setData(() => rawData, newData => { this.setSearchIndex({ overwriteSearchIndex: true, data: newData }, () => { const { typedInputValue } = this.state; if ((typedInputValue === null || typedInputValue === void 0 ? void 0 : typedInputValue.length) > 0) { const filteredData = this.runFilterWithSideEffects(typedInputValue); if (this.countData(filteredData) === 0) { this.showNoOptionsItem(); } } else { this.resetActiveItem(); if (this.context.drawerList.opened) { this.showAllItems(); } } }); }, { overwriteOriginalData: true }); return this; }); _defineProperty(this, "onInputKeyDownHandler", _ref3 => { let { event: e } = _ref3; const key = keycode(e); switch (key) { case 'page up': case 'page down': case 'home': case 'end': case 'down': case 'up': e.preventDefault(); break; } switch (key) { case 'up': case 'down': if (!this.context.drawerList.opened) { this.setVisible(); } break; case 'esc': this.setState({ showAllNextTime: true, _listenForPropChanges: false }); break; case 'enter': e.preventDefault(); if (!this.context.drawerList.opened && this.hasFilterActive()) { this.ignoreEvents(); this.showAll(); } if ((!this.hasValidData() || !this.hasSelectedItem()) && !this.hasActiveItem()) { this.toggleVisible(); } else { this.setVisible(); } break; } }); _defineProperty(this, "onInputClickHandler", e => { if (!this.context.drawerList.opened && this.hasFilterActive()) { this.ignoreEvents(); this.showAll(); } const { value } = e.target; this.setVisibleByContext({ value }); }); _defineProperty(this, "onInputFocusHandler", event => { if (this.state.skipFocusDuringChange) { return; } const { open_on_focus, keep_value_and_selection } = this.props; if (!this.state.hasFocus) { if (isTrue(open_on_focus) && this.hasValidData()) { const { value } = event.target; this.setVisibleByContext({ value }); } else { this.setSearchIndex(); } if (isTrue(keep_value_and_selection)) { this.showAll(); } dispatchCustomElementEvent(this, 'on_focus', _objectSpread({ event }, this.getEventObjects('on_focus'))); this.setState({ hasFocus: true, hasBlur: false }); } }); _defineProperty(this, "reserveActivityHandler", function () { let event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; _this.__preventFiringBlurEvent = Boolean(event.key === 'enter' || (event !== null && event !== void 0 && event.currentTarget ? getPreviousSibling('dnb-drawer-list', event.currentTarget) || getPreviousSibling('dnb-input__submit-button__button', event.currentTarget) : false)); if (_this.__preventFiringBlurEvent) { setTimeout(() => { _this.__preventFiringBlurEvent = false; }, isTrue(_this.props.no_animation) ? 1 : DrawerList.blurDelay); } }); _defineProperty(this, "onBlurHandler", event => { if (this.__preventFiringBlurEvent || this.context.drawerList.hasFocusOnElement || this.state.hasBlur) { this.__preventFiringBlurEvent = null; return false; } const { open_on_focus, keep_value, keep_value_and_selection, prevent_selection, no_animation } = this.props; this.setState({ hasBlur: true, hasFocus: false }); if (!isTrue(keep_value) && !isTrue(keep_value_and_selection)) { this.setState({ typedInputValue: null, _listenForPropChanges: false }); } if (!isTrue(prevent_selection)) { const existingValue = this.state.inputValue; this.resetInputValue(); const resetAfterClose = () => { if (!isTrue(keep_value) || !existingValue || this.hasSelectedItem()) { this.resetActiveItem(); } this.resetFilter(); }; if (isTrue(no_animation)) { resetAfterClose(); } else { clearTimeout(this._blurTimeout); this._blurTimeout = setTimeout(resetAfterClose, DrawerList.blurDelay); } } if (isTrue(open_on_focus)) { this.setHidden(); } dispatchCustomElementEvent(this, 'on_blur', _objectSpread({ event }, this.getEventObjects('on_blur'))); }); _defineProperty(this, "onTriggerKeyDownHandler", e => { const key = keycode(e); switch (key) { case 'space': case 'enter': { this.setVisible(); } break; } switch (key) { case 'space': case 'enter': case 'page up': case 'page down': case 'down': case 'up': { e.preventDefault(); this.focusInput(); } break; } }); _defineProperty(this, "focusDrawerList", () => { try { this.context.drawerList._refUl.current.focus({ preventScroll: true }); } catch (e) {} }); _defineProperty(this, "focusInput", () => { try { this._refInput.current._ref.current.focus({ preventScroll: true }); } catch (e) { warn(e); } }); _defineProperty(this, "getEventObjects", key => { const attributes = this.attributes; return { attributes, dataList: this.context.drawerList.data, updateData: this.updateData, revalidateSelectedItem: this.revalidateSelectedItem, revalidateInputValue: this.revalidateInputValue, resetSelectedItem: this.resetSelectedItem, clearInputValue: this.clearInputValue, showAllItems: this.showAllItems, setVisible: this.setVisible, resetInputValue: this.resetInputValue, setHidden: this.setHidden, emptyData: this.emptyData, focusInput: this.focusInput, setInputValue: this.setInputValue, showNoOptionsItem: this.showNoOptionsItem, showIndicatorItem: this.showIndicatorItem, showIndicator: this.showIndicator, hideIndicator: this.hideIndicator, setMode: this.setMode, debounce: function (func) { let props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; let wait = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 250; _this.dbf = _this.dbf || {}; return (_this.dbf[key] || (_this.dbf[key] = debounce(func, wait, { context: _this })))(props); } }; }); _defineProperty(this, "hasInjectedDataItem", function () { let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _this.context.drawerList.data; const lastItem = data.slice(-1)[0]; return lastItem ? lastItem.show_all || lastItem.__id === 'no_options' : false; }); _defineProperty(this, "countData", function () { let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _this.context.drawerList.data; const count = data.length; return count > 0 && _this.hasInjectedDataItem(data) ? count - 1 : count; }); _defineProperty(this, "hasValidData", function () { let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _this.context.drawerList.data; if (_this.countData(data) > 0) { const first = data[0]; if (!first.show_all && !['no_options', 'indicator'].includes(first.__id)) { return true; } } return false; }); _defineProperty(this, "hasSelectedItem", () => { return parseFloat(this.context.drawerList.selected_item) > -1; }); _defineProperty(this, "hasActiveItem", () => { return parseFloat(this.context.drawerList.active_item) > -1; }); _defineProperty(this, "hasFilterActive", function () { let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _this.context.drawerList.data; return !(_this.context.drawerList.original_data && _this.context.drawerList.original_data.length === _this.countData(data)); }); _defineProperty(this, "ignoreEvents", () => { clearTimeout(this.showAllTimeout); this.context.drawerList.setState({ ignore_events: true }, () => { this.showAllTimeout = setTimeout(() => { this.context && this.context.drawerList && this.context.drawerList.setState({ ignore_events: false }); }, 10); }); }); _defineProperty(this, "showAll", () => { this.resetFilter(); this.context.drawerList.setState({ cache_hash: 'all' }); this.runFilterToHighlight({ skipFilter: true, fillDataIfEmpty: true }); }); _defineProperty(this, "showAllItems", () => { this.resetFilter(); this.context.drawerList.setState({ cache_hash: 'all' }); this.context.drawerList.setActiveItemAndScrollToIt(this.context.drawerList.selected_item, { scrollTo: false }); }); _defineProperty(this, "totalReset", () => { this.setState({ inputValue: null, typedInputValue: null, _listenForPropChanges: false }); this.resetActiveItem(); this.resetSelectedItem(); }); _defineProperty(this, "resetActiveItem", () => { this.context.drawerList.setState({ active_item: null }); }); _defineProperty(this, "resetSelectedItem", () => { const hasHadValue = this.hasSelectedItem(); this.context.drawerList.setState({ selected_item: null }, () => { if (hasHadValue) { dispatchCustomElementEvent(this, 'on_change', _objectSpread({}, this.getEventObjects('on_change'))); } }); }); _defineProperty(this, "resetFilter", () => { this.context.drawerList.setData(this.context.drawerList.original_data); }); _defineProperty(this, "runFilter", function (value) { let { data = null, searchIndex = _this.state.searchIndex, searchNumbers = isTrue(_this.props.search_numbers), inWordIndex = (parseFloat(_this.props.search_in_word_index) || 3) - 2, disableHighlighting = false, skipFilter = false, skipReorder = false } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; if (data) { searchIndex = _this.setSearchIndex({ data }); } else if (!searchIndex) { searchIndex = _this.setSearchIndex(); } if (typeof searchIndex === 'undefined') { return []; } const searchWords = (value === null || value === void 0 ? void 0 : value.split(/\s+/g).filter(Boolean)) || []; const wordCond = '^|\\s'; const findSearchWords = contentChunk => { if (typeof contentChunk !== 'string') { return []; } return searchWords.map((word, wordIndex) => ({ word, wordIndex })).filter(_ref4 => { let { word, wordIndex } = _ref4; if (searchNumbers) { word = word.replace(/[^\p{L}\p{N}]+/gu, ''); } else { word = escapeRegexChars(word); } if (searchNumbers) { word = word.replace(/(\d)/g, '$1+'); } const regexWord = new RegExp(wordIndex > inWordIndex ? `${word}` : `(${wordCond})${word}`, 'i'); if (regexWord.test(contentChunk)) { return true; } if (searchNumbers && regexWord.test(contentChunk.replace(/[^0-9]/g, ''))) { return true; } return false; }).map(_ref5 => { let { word, wordIndex } = _ref5; let wordScore = 0; wordScore += (contentChunk.match(new RegExp(`(${wordCond})${escapeRegexChars(word)}`, 'ig')) || []).length; if (wordIndex === 0) { const isFirstWord = new RegExp(`^${escapeRegexChars(searchWords[0])}`, 'i').test(contentChunk.split(' ')[0]); if (isFirstWord) { wordScore += searchWords.length + 1; } } return { word, wordIndex, wordScore }; }); }; const strS = '\uFFFE'; const strE = '\uFFFF'; const tagS = '<span class="dnb-drawer-list__option__item--highlight">'; const tagE = '</span>'; searchIndex = searchIndex.map((item, i) => { const listOfFoundWords = findSearchWords(item.contentChunk, i); if (typeof item.dataItem === 'string') { item.dataItem = { content: item.dataItem }; } if (!item.dataItem.render) { item.dataItem = _objectSpread({}, item.dataItem); } item.dataItem.render = (children, id) => { var _children2, _children2$props; if (disableHighlighting || _this.state.disableHighlighting) { return children; } const cacheHash = id + value; _this._cacheMemory = _this._cacheMemory || {}; if (_this._cacheMemory[cacheHash]) { return _this._cacheMemory[cacheHash]; } const isComponent = typeof children !== 'string' && React.isValidElement(children); if (isComponent && Array.isArray((_children2 = children) === null || _children2 === void 0 ? void 0 : (_children2$props = _children2.props) === null || _children2$props === void 0 ? void 0 : _children2$props.children)) { children = children.props.children; } else if (!Array.isArray(children)) { children = [children]; } children = children.map(originalChild => ({ originalChild, segment: convertJsxToString(originalChild, ' ') })); children = children.map((_ref6, idx) => { let { originalChild, segment } = _ref6; searchWords.forEach((word, wordIndex) => { if (segment) { word = escapeRegexChars(word); if (searchNumbers) { word.split('').forEach(char => { if (/[\p{L}\p{N}]/u.test(char)) { segment = segment.replace(new RegExp(`(${char})`, 'gi'), `${strS}$1${strE}`); } }); } else { if (wordIndex > inWordIndex) { segment = segment.replace(new RegExp(`(${word})`, 'gi'), `${strS}$1${strE}`); } else { segment = segment.replace(new RegExp(`(${wordCond})(${word})`, 'gi'), `$1${strS}$2${strE}`); } } } }); let result = segment; if (segment.includes(strS)) { const __html = segment.replace(new RegExp(`(${strS})+`, 'g'), strS).replace(new RegExp(`(${strE})+`, 'g'), strE).replace(new RegExp(`(${strE}${strS})`, 'g'), '').replace(new RegExp(strS, 'g'), tagS).replace(new RegExp(strE, 'g'), tagE); result = React.createElement("span", { key: cacheHash + idx, dangerouslySetInnerHTML: { __html } }); } else { result = React.createElement("span", { key: cacheHash + idx }, segment); } if (isComponent) { var _originalChild$props; if (Array.isArray(originalChild === null || originalChild === void 0 ? void 0 : (_originalChild$props = originalChild.props) === null || _originalChild$props === void 0 ? void 0 : _originalChild$props.children)) { result = originalChild.props.children.map(Comp => { return Comp === originalChild || Comp.props && Comp.props.children === originalChild ? result : Comp; }); } else if (typeof originalChild === 'string') { result = originalChild; } if (React.isValidElement(originalChild)) { result = React.cloneElement(originalChild, { key: 'clone' + cacheHash + idx }, result); } } return result; }); return _this._cacheMemory[cacheHash] = children; }; if (_this.skipFilter || skipFilter) { return item.dataItem; } let totalScore = listOfFoundWords.length; for (const { wordScore } of listOfFoundWords) { totalScore += wordScore; } return { totalScore, item }; }); if (!_this.skipFilter && !skipFilter) { searchIndex = searchIndex.filter(_ref7 => { let { totalScore } = _ref7; return totalScore; }); if (!_this.skipReorder && !skipReorder) { searchIndex = searchIndex.sort((_ref8, _ref9) => { let { totalScore: a } = _ref8; let { totalScore: b } = _ref9; return b - a; }); } searchIndex = searchIndex.map(_ref10 => { let { item } = _ref10; return item.dataItem; }); } return searchIndex; }); _defineProperty(this, "onHideHandler", function () { let args = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; const res = dispatchCustomElementEvent(_this, 'on_hide', _objectSpread(_objectSpread({}, args), _this.getEventObjects('on_hide'))); if (res !== false) { _this.setFocusOnInput(); } return res; }); _defineProperty(this, "setVisibleAndFocusOnInput", () => { if (!this.state.hasFocus && !hasSelectedText()) { this.setFocusOnInput(); this.setVisible(); } }); _defineProperty(this, "onSelectHandler", args => { if (parseFloat(args.active_item) > -1) { dispatchCustomElementEvent(this, 'on_select', _objectSpread(_objectSpread({}, args), this.getEventObjects('on_select'))); } }); _defineProperty(this, "onPreChangeHandler", _ref11 => { let { data } = _ref11; if (data && data.show_all) { this.showAll(); const active_item = data.lastActiveItem; if (parseFloat(active_item) > -1) { this.context.drawerList.setActiveItemAndScrollToIt(active_item, { scrollTo: false }); } this.setFocusOnInput(); return false; } }); _defineProperty(this, "onChangeHandler", args => { var _args$data; const selected_item = args.selected_item; const { prevent_selection, keep_open } = this.props; if (!isTrue(prevent_selection)) { if (!isTrue(keep_open)) { this.setState({ skipFocusDuringChange: true, disableHighlighting: true, _listenForPropChanges: false }); this.setHidden(); this.focusDrawerList(); this.setState({ skipFocusDuringChange: false, _listenForPropChanges: false }, () => this.setFocusOnInput()); } const inputValue = AutocompleteInstance.getCurrentDataTitle(selected_item, this.context.drawerList.data); this.setInputValue(inputValue); } if (typeof ((_args$data = args.data) === null || _args$data === void 0 ? void 0 : _args$data.render) === 'function') { delete args.data.render; } dispatchCustomElementEvent(this, 'on_change', _objectSpread(_objectSpread({}, args), this.getEventObjects('on_change'))); }); this._id = _props.id || makeUniqueId(); this.attributes = {}; this.state = this.state || {}; this.state._listenForPropChanges = true; this.state.mode = _props.mode; this.state.prevData = _props.data; this.state.updateData = this.updateData; if (context.drawerList && context.drawerList.current_title) { this.state.inputValue = context.drawerList.current_title; } this._ref = React.createRef(); this._refShell = React.createRef(); this._refInput = React.createRef(); this.isTouchDevice = isTouchDevice(); this.skipFilter = isTrue(_props.disable_filter); this.skipReorder = isTrue(_props.disable_reorder); } componentDidMount() { if (isTrue(this.props.opened)) { this.runFilterToHighlight({ fillDataIfEmpty: true }); this.setVisible(); } } componentDidUpdate(prevProps) { if (prevProps.data !== this.props.data) { this.setSearchIndex({ overwriteSearchIndex: true }, () => { this.runFilterWithSideEffects(this.state.inputValue); }); } if (prevProps.value !== this.props.value) { this.revalidateSelectedItem(); this.revalidateInputValue(); } } componentWillUnmount() { clearTimeout(this._selectTimeout); clearTimeout(this._focusTimeout); clearTimeout(this._blurTimeout); } setSearchIndex() { let { overwriteSearchIndex = false, data = this.context.drawerList.original_data } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; let cb = arguments.length > 1 ? arguments[1] : undefined; this._cacheMemory = {}; if (!overwriteSearchIndex && this.state.searchIndex) { return this.state.searchIndex; } const searchIndex = AutocompleteInstance.createSearchIndex(data); this.setState({ searchIndex, _listenForPropChanges: false }, cb); return searchIndex; } setFocusOnInput() { this.setState({ hasFocus: true }, () => { this.focusInput(); this.setState({ hasFocus: false }); }); } getAriaLiveUpdate() { const { opened } = this.context.drawerList; if (opened) { const { aria_live_options, no_options } = this._props; const count = this.countData(); let newString = null; if (count > 0) { newString = String(aria_live_options).replace('%s', count); } else { newString = no_options; } return newString; } return ''; } getVoiceOverActiveItem(selected_sr) { const { active_item, selected_item } = this.context.drawerList; const currentDataItem = getCurrentData(active_item, this.context.drawerList.data); return React.createElement(AriaLive, { hidden: !IS_MAC, priority: "high", delay: 0 }, currentDataItem && React.createElement(React.Fragment, null, active_item === selected_item ? React.createElement(React.Fragment, null, selected_sr, " ") : null, React.createElement(ItemContent, null, currentDataItem))); } render() { var _this$context, _this$context2; const props = this._props = extendPropsWithContextInClassComponent(this.props, Autocomplete.defaultProps, this.context.getTranslation(this.props).Autocomplete, pickFormElementProps((_this$context = this.context) === null || _this$context === void 0 ? void 0 : _this$context.FormRow), pickFormElementProps((_this$context2 = this.context) === null || _this$context2 === void 0 ? void 0 : _this$context2.formElement), this.context.Autocomplete); const { title, placeholder, label, label_direction, label_sr_only, icon, icon_size, input_icon, size, align_autocomplete, fixed_position, status, status_state, status_props, status_no_animation, globalStatus, suffix, scrollable, focusable, keep_open, keep_value, keep_value_and_selection, show_clear_button, prevent_close, no_animation, no_scroll_animation, show_submit_button, submit_element, input_element: CustomInput, options_render, prevent_selection, max_height, default_value, search_numbers, search_in_word_index, show_options_sr, selected_sr, submit_button_title, submit_butt