UNPKG

@zohodesk/components

Version:

Dot UI is a customizable React component library built to deliver a clean, accessible, and developer-friendly UI experience. It offers a growing set of reusable components designed to align with modern design systems and streamline application development

1,172 lines (1,076 loc) 39.4 kB
/**** Libraries ****/ import React from 'react'; import { MultiSelect_propTypes } from "./props/propTypes"; import { MultiSelect_defaultProps } from "./props/defaultProps"; import { defaultProps as MobileHeader_defaultProps } from "./MobileHeader/props/defaultProps"; import { MULTISELECT_I18N_KEYS } from "./constants"; /**** Components ****/ import Popup from "../Popup/Popup"; import TextBoxIcon from "../TextBoxIcon/TextBoxIcon"; import { Container, Box } from "../Layout"; import Card, { CardContent, CardFooter, CardHeader } from "../Card/Card"; import SelectedOptions from "./SelectedOptions"; import Suggestions from "./Suggestions"; import EmptyState from "./EmptyState"; import CssProvider from "../Provider/CssProvider"; import { getUniqueId } from "../Provider/IdProvider"; import ResponsiveDropBox from "../ResponsiveDropBox/ResponsiveDropBox"; // import { ResponsiveReceiver } from '../Responsive/CustomResponsive'; import MultiSelectHeader from "./MultiSelectHeader"; import Loader from '@zohodesk/svg/lib/Loader/Loader'; import isMobilePopover from "../DropBox/utils/isMobilePopover"; /**** Icons ****/ import { Icon } from '@zohodesk/icons'; /**** CSS ****/ import style from "./MultiSelect.module.css"; /**** Methods ****/ import { debounce, scrollTo, bind, getIsEmptyValue, getSearchString, findScrollEnd } from "../utils/Common.js"; import { makeFormatOptions, makeGetMultiSelectFilterSuggestions as makeGetFilterSuggestions, makeGetMultiSelectSelectedOptions as makeGetSelectedOptions, makeObjectConcat, filterSelectedOptions, makeGetIsShowClearIcon } from "../utils/dropDownUtils"; import MobileHeader from "./MobileHeader/MobileHeader"; /* eslint-disable react/forbid-component-props */ /* eslint-disable react/no-unused-prop-types */ const dummyArray = []; export class MultiSelectComponent extends React.Component { constructor(props) { super(props); this.getNextAriaId = getUniqueId(this); this.getFilterSuggestions = makeGetFilterSuggestions(); this.formatOptions = makeFormatOptions(); this.getSelectedOptions = makeGetSelectedOptions(); this.getIsShowClearIcon = makeGetIsShowClearIcon(); //Use in AdvancedMultiSelect component this.objectConcat = makeObjectConcat(); this.formatSelectedOptions = makeFormatOptions(); const { selectedOptions, searchDebounceTime = 500 } = this.props; const { allOptions, normalizedAllOptions, normalizedFormatOptions } = this.handleFormatOptions(this.props); const { formatSelectedOptions, normalizedSelectedOptions, selectedOptionIds } = this.handleGetSelectedOptions(selectedOptions, normalizedFormatOptions, this.props); this.state = { options: allOptions, optionsNormalize: normalizedAllOptions, selectedOptions: formatSelectedOptions, selectedOptionIds, searchStr: '', hoverOption: 0, isFetchingOptions: false, highLightedSelectOptions: [], lastHighLightedSelectOption: '', shiftKeyPressHighLighted: 0, isActive: false }; this.allSelectedOptionsDetails = normalizedSelectedOptions; this.suggestionsOrder = []; this._isMounted = false; bind.apply(this, ['handleInputCick', 'handleFilterSuggestions', 'handleKeyDown', 'handleSelectAll', 'handleDeselectAll', 'handleSelectOption', 'handleRemoveOption', 'handleSearch', 'handleClickSelectedOption', 'handleChange', 'handlePopupClose', 'togglePopup', 'selectedOptionRef', 'searchInputRef', 'suggestionContainerRef', 'suggestionItemRef', 'selectedOptionContainerRef', 'handleActive', 'handleInactive', 'handleMouseEnter', 'handleFetchOptions', 'handleFormatOptions', 'handleGetSelectedOptions', 'handleComponentDidUpdate', 'handleInputFocus', 'handleExposedPublicMethods', 'getSelectionUI', 'moveFocusToTextbox']); this.handleSearchOptions = debounce(this.handleSearchOptions.bind(this), searchDebounceTime); this.handleScroll = this.handleScroll.bind(this); this.handleScrollFuncCall = debounce(this.handleScrollFuncCall.bind(this), 500); this.setSuggestionsVirtualizerContainerRefFunction = this.setSuggestionsVirtualizerContainerRefFunction.bind(this); } componentDidMount() { // let { suggestionContainer } = this; this._isMounted = true; this.handleExposedPublicMethods(); // suggestionContainer && // suggestionContainer.addEventListener('scroll', this.handleScroll); } UNSAFE_componentWillReceiveProps(nextProps) { const { selectedOptions, options, valueField, textField, prefixText } = nextProps; const oldProps = this.props; if (selectedOptions !== oldProps.selectedOptions || options !== oldProps.options || valueField !== oldProps.valueField || textField !== oldProps.textField || prefixText !== oldProps.prefixText //For GroupMultiSelect component ) { const { allOptions, normalizedAllOptions, normalizedFormatOptions } = this.handleFormatOptions(nextProps); const { allSelectedOptionsDetails: oldAllSelectedOptionsDetails } = this; const optionsDetails = Object.assign({}, oldAllSelectedOptionsDetails, normalizedFormatOptions); const { formatSelectedOptions, normalizedSelectedOptions, selectedOptionIds } = this.handleGetSelectedOptions(selectedOptions, optionsDetails, nextProps); this.allSelectedOptionsDetails = Object.assign(oldAllSelectedOptionsDetails, normalizedSelectedOptions); this.setState({ options: allOptions, optionsNormalize: normalizedAllOptions, selectedOptions: formatSelectedOptions, selectedOptionIds }, () => { const { hoverOption } = this.state; const suggestions = this.handleFilterSuggestions(); const suggestionsLen = suggestions.length; const { id } = suggestions[hoverOption] || {}; const newHoverOption = !getIsEmptyValue(id) ? hoverOption : suggestionsLen ? suggestionsLen - 1 : 0; this.setState({ hoverOption: newHoverOption }); }); } } componentDidUpdate(prevProps, prevState) { const { suggestionContainer, selectedOptionContainer, suggestionsOrder } = this; const { hoverOption, highLightedSelectOptions, selectedOptions, searchStr } = this.state; const { needLocalSearch, isPopupOpen, onDropBoxClose, onDropBoxOpen, isSearchClearOnClose } = this.props; //handle dropbox open & close if (prevProps.isPopupOpen !== isPopupOpen) { isPopupOpen && onDropBoxOpen && this.handleFetchOptions(onDropBoxOpen, searchStr); if (!isPopupOpen) { this.setState({ hoverOption: 0 }); isSearchClearOnClose && searchStr && this.handleSearch(''); onDropBoxClose && onDropBoxClose(); } } //scrollTo handling const hoverId = suggestionsOrder[hoverOption] || ''; const selectedSuggestion = this[`suggestion_${hoverId}`]; const lastHighLightedSelectOption = highLightedSelectOptions.slice(-1).length ? highLightedSelectOptions.slice(-1)[0] : null; const selectedOption = this[`selectedOption_${lastHighLightedSelectOption}`]; isPopupOpen && scrollTo(suggestionContainer, selectedSuggestion); selectedOptions.length && selectedOption && scrollTo(selectedOptionContainer, selectedOption); //When suggestions length less than 5, getNextOptions function call const { isNextOptions, getNextOptions } = this.props; // let { searchStr } = this.state; const suggestions = this.handleFilterSuggestions(); const suggestionsLen = suggestions.length; if (isPopupOpen && suggestionsLen <= 5 && isNextOptions && getNextOptions && !needLocalSearch) { this.handleFetchOptions(getNextOptions, searchStr); } //Need To MultiselectNew Component this.handleComponentDidUpdate(prevProps, prevState); // if (isPopupOpen && isNextOptions && prevProps.selectedOptions.length !== selectedOptions.length) { // let { scrollHeight, clientHeight } = this.suggestionContainer || {}; // let isElementScrollable = scrollHeight > clientHeight; // if (!isElementScrollable) { // this.handleScrollFuncCall(); // } // } } componentWillUnmount() { // let { suggestionContainer } = this; this._isMounted = false; // suggestionContainer && // suggestionContainer.removeEventListener('scroll', this.handleScroll); } handleComponentDidUpdate() { return; } handleFormatOptions(props) { const { options, valueField, textField, prefixText, disabledOptions, allowValueFallback, searchFields } = props; return this.formatOptions({ options, valueField, textField, prefixText, optionType: 'default', disabledOptions, allowValueFallback, searchFields }); } handleGetSelectedOptions(selectedOptions, normalizedFormatOptions, props) { const { allowValueFallback, limit } = props; return this.getSelectedOptions({ selectedOptions, normalizedFormatOptions, allowValueFallback, limit }); } handleInputCick(e) { const { removeClose } = this.props; const { highLightedSelectOptions, searchStr = '' } = this.state; if (highLightedSelectOptions.length) { this.setState({ highLightedSelectOptions: [], shiftKeyPressHighLighted: 0, lastHighLightedSelectOption: '' }); removeClose(e); } else if (searchStr.length) { removeClose(e); } else { this.togglePopup(e); } } handleFilterSuggestions() { const { options = dummyArray, searchStr = '' } = this.state; const { selectedOptions, needLocalSearch, keepSelectedOptions, searchFields } = this.props; const { suggestions, suggestionIds } = this.getFilterSuggestions({ options, selectedOptions, searchStr: getSearchString(searchStr), needSearch: needLocalSearch, keepSelectedOptions, searchFields }); this.suggestionsOrder = suggestionIds; return suggestions; } handleKeyDown(e) { const { keyCode, ctrlKey, metaKey, shiftKey } = e; let suggestions = []; let { hoverOption, searchStr, highLightedSelectOptions, lastHighLightedSelectOption, shiftKeyPressHighLighted, selectedOptionIds: selectedOptions } = this.state; const { isNextOptions, getNextOptions, isPopupOpen, isPopupOpenOnEnter, onKeyDown, limit } = this.props; const allowKeyboardActions = !limit || limit && selectedOptions.length < limit; const highLightedSelectOptionsLen = highLightedSelectOptions.length; if (isPopupOpen && (keyCode === 38 || keyCode === 40 || keyCode === 13 || keyCode === 27 || keyCode === 9)) { suggestions = this.handleFilterSuggestions(); } if (!isPopupOpen && !isPopupOpenOnEnter) { onKeyDown && onKeyDown(e); } if (!isPopupOpen && keyCode === 40) { //down arrow press popup open e.preventDefault(); //prevent body scroll this.togglePopup(e); } const suggestionsLen = suggestions.length; if (suggestionsLen && isPopupOpen && keyCode === 38 && allowKeyboardActions) { //up arrow /*if (hoverOption === 0) { //disable first to last option higlight !isNextOptions && this.setState({ hoverOption: suggestionsLen - 1 }); }*/ if (hoverOption) { this.setState({ hoverOption: hoverOption - 1 }); } } else if (suggestionsLen && isPopupOpen && keyCode === 40 && allowKeyboardActions) { //down arrow /*else if (hoverOption === suggestionsLen - 1 || hoverOption === null) { //disable last to first option higlight !isNextOptions && this.setState({ hoverOption: 0 }); }*/ if (isNextOptions && suggestionsLen >= 5 && hoverOption === suggestionsLen - 3) { getNextOptions && this.handleFetchOptions(getNextOptions, searchStr); this.setState({ hoverOption: hoverOption + 1 }); } else if (suggestionsLen - 1 > hoverOption) { this.setState({ hoverOption: hoverOption + 1 }); } } else if (keyCode === 13 && allowKeyboardActions) { //enter ke const selectedOption = suggestions[hoverOption] || {}; const { id } = selectedOption; isPopupOpen && !getIsEmptyValue(id) && this.handleSelectOption(id, e); !isPopupOpen && isPopupOpenOnEnter && this.togglePopup(e); } else if (selectedOptions.length && keyCode === 8 && !searchStr.length) { //backspace key if (highLightedSelectOptionsLen) { this.handleRemoveOption(highLightedSelectOptions); } else { this.handleRemoveOption(selectedOptions.slice(-1)); // this.setState({ // highLightedSelectOptions: selectedOptions.slice(-1) // }); } } else if (selectedOptions && keyCode === 65 && (ctrlKey || metaKey) && !searchStr.length) { //ctrl+a key this.setState({ highLightedSelectOptions: selectedOptions, shiftKeyPressHighLighted: 0 }); } else if (keyCode === 39 && shiftKey && selectedOptions.length && !searchStr.length) { //shift+right arrow=39 const lastHighLightedSelectOptionIndex = lastHighLightedSelectOption && selectedOptions.indexOf(lastHighLightedSelectOption) >= 0 ? selectedOptions.indexOf(lastHighLightedSelectOption) : 0; const newShiftKeyPressHighLighted = shiftKeyPressHighLighted ? shiftKeyPressHighLighted : shiftKeyPressHighLighted + 1; const newHighLightedSelectOption = lastHighLightedSelectOptionIndex !== null ? selectedOptions[lastHighLightedSelectOptionIndex + newShiftKeyPressHighLighted] : selectedOptions[0]; if (!getIsEmptyValue(newHighLightedSelectOption)) { const newLastHighLightedSelectOption = lastHighLightedSelectOption ? lastHighLightedSelectOption : selectedOptions[0]; highLightedSelectOptions = !shiftKeyPressHighLighted ? [newLastHighLightedSelectOption] : highLightedSelectOptions; const isRemove = highLightedSelectOptions.indexOf(newHighLightedSelectOption) >= 0 && newHighLightedSelectOption !== lastHighLightedSelectOption ? true : false; const newHighLightedSelectOptions = isRemove ? highLightedSelectOptions.filter(option => option !== newHighLightedSelectOption) : [...highLightedSelectOptions, newHighLightedSelectOption]; this.setState({ highLightedSelectOptions: newHighLightedSelectOptions, shiftKeyPressHighLighted: newShiftKeyPressHighLighted + 1, lastHighLightedSelectOption: newLastHighLightedSelectOption }); } } else if (keyCode === 37 && shiftKey && selectedOptions.length && !searchStr.length) { // shift+left arrow=37 const lastHighLightedSelectOptionIndex = lastHighLightedSelectOption ? selectedOptions.indexOf(lastHighLightedSelectOption) : selectedOptions.length - 1; const newShiftKeyPressHighLighted = shiftKeyPressHighLighted !== 1 ? shiftKeyPressHighLighted : shiftKeyPressHighLighted - 1; const newHighLightedSelectOption = selectedOptions[lastHighLightedSelectOptionIndex + newShiftKeyPressHighLighted - 1]; if (!getIsEmptyValue(newHighLightedSelectOption)) { const newLastHighLightedSelectOption = lastHighLightedSelectOption ? lastHighLightedSelectOption : selectedOptions.slice(-1)[0]; highLightedSelectOptions = !shiftKeyPressHighLighted ? [newLastHighLightedSelectOption] : highLightedSelectOptions; const isRemove = highLightedSelectOptions.indexOf(newHighLightedSelectOption) >= 0 && newHighLightedSelectOption !== lastHighLightedSelectOption ? true : false; const newHighLightedSelectOptions = isRemove ? highLightedSelectOptions.filter(option => option !== newHighLightedSelectOption) : [...highLightedSelectOptions, newHighLightedSelectOption]; this.setState({ highLightedSelectOptions: newHighLightedSelectOptions, shiftKeyPressHighLighted: newShiftKeyPressHighLighted - 1, lastHighLightedSelectOption: newLastHighLightedSelectOption }); } } else if ((keyCode === 39 || keyCode === 37) && selectedOptions.length && !searchStr.length) { const isRightArrow = keyCode === 39 ? true : false; // let isLefttArrow = keyCode === 37 ? true : false; if (highLightedSelectOptions.length) { const [lastHighLightedSelectOption] = highLightedSelectOptions.slice(-1); const lastHighLightedSelectOptionIndex = selectedOptions.indexOf(lastHighLightedSelectOption); const newLastHighLightedSelectOptionIndex = isRightArrow ? lastHighLightedSelectOptionIndex === selectedOptions.length - 1 ? lastHighLightedSelectOptionIndex : lastHighLightedSelectOptionIndex + 1 : lastHighLightedSelectOptionIndex - 1; const newLastHighLightedSelectOption = selectedOptions[newLastHighLightedSelectOptionIndex]; const isEmptyHighlighted = isRightArrow && highLightedSelectOptions.length === 1 && selectedOptions.slice(-1)[0] === lastHighLightedSelectOption ? true : false; if (!getIsEmptyValue(newLastHighLightedSelectOption)) { this.setState({ lastHighLightedSelectOption: isEmptyHighlighted ? '' : newLastHighLightedSelectOption, highLightedSelectOptions: isEmptyHighlighted ? [] : [newLastHighLightedSelectOption], shiftKeyPressHighLighted: 0 }); } } else { const [newLastHighLightedSelectOption] = isRightArrow ? selectedOptions : selectedOptions.slice(-1); this.setState({ lastHighLightedSelectOption: newLastHighLightedSelectOption, highLightedSelectOptions: [newLastHighLightedSelectOption], shiftKeyPressHighLighted: 0 }); } } else if (keyCode === 27) {// this.handlePopupClose(e); } else if (keyCode === 9) { this.handlePopupClose(e); } } handleSelectAll(e) { e && e.preventDefault(); const suggestions = this.handleFilterSuggestions(); const { selectedOptions } = this.props; const newSelectedOptions = []; suggestions.forEach(option => { const { id } = option; if (selectedOptions.indexOf(id) === -1) { newSelectedOptions.push(id); } }); this.handleChange([...selectedOptions, ...newSelectedOptions]); // this.handlePopupClose(e); } handleDeselectAll(e) { e && e.preventDefault(); const { removeClose } = this.props; const { highLightedSelectOptions } = this.state; if (highLightedSelectOptions.length) { this.setState({ highLightedSelectOptions: [], lastHighLightedSelectOption: '' }); } removeClose(e); this.handleChange([]); } handleSelectOption(option, value, index, e) { const { selectedOptions, isSearchClearOnSelect, keepSelectedOptions } = this.props; const { searchStr } = this.state; if (searchStr.trim() != '' && isSearchClearOnSelect) { this.handleSearch(''); } if (keepSelectedOptions && selectedOptions.indexOf(option) != -1) { let newSelectedOptions = selectedOptions.filter(id => { return id != option; }); this.handleChange(newSelectedOptions, e); } else { this.handleChange([...selectedOptions, option], e); } } handleRemoveOption(options) { const newOptions = !getIsEmptyValue(options) && !Array.isArray(options) ? [options] : options; const { selectedOptions, isReadOnly } = this.props; const { highLightedSelectOptions, lastHighLightedSelectOption, shiftKeyPressHighLighted } = this.state; if (newOptions.length && !isReadOnly) { const newSelectedOptions = selectedOptions.filter(option => newOptions.indexOf(option) === -1); const newHighLightedSelectOptions = highLightedSelectOptions.filter(option => newSelectedOptions.indexOf(option) >= 0); let isHighlightedRemoved = false; const newOptionsLen = newOptions.length; for (let i = 0; i < newOptionsLen; i++) { const removedOption = newOptions[i]; if (highLightedSelectOptions.indexOf(removedOption) >= 0) { isHighlightedRemoved = true; break; } } this.setState({ lastHighLightedSelectOption: newSelectedOptions.indexOf(lastHighLightedSelectOption) >= 0 && !isHighlightedRemoved ? lastHighLightedSelectOption : '', highLightedSelectOptions: isHighlightedRemoved ? [] : newHighLightedSelectOptions, shiftKeyPressHighLighted: isHighlightedRemoved ? 0 : shiftKeyPressHighLighted }); this.handleChange(newSelectedOptions); } this.moveFocusToTextbox(); } handleMouseEnter(id, val, hoverOptionIndex, e) { e && e.preventDefault(); const { hoverOption } = this.state; const { suggestionsOrder } = this; const newHoverIndex = suggestionsOrder.indexOf(id); if (newHoverIndex !== hoverOption) { this.setState({ hoverOption: newHoverIndex }); } } handleFetchOptions() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } const [APICall, searchStr] = args; const { isFetchingOptions } = this.state; const { _isMounted } = this; const isForce = isFetchingOptions && searchStr ? true : false; if (!isFetchingOptions && APICall || isForce) { this.setState({ isFetchingOptions: true }); try { return APICall(searchStr).then(() => { _isMounted && this.setState({ isFetchingOptions: false }); }, () => { _isMounted && this.setState({ isFetchingOptions: false }); }); } catch (e) { _isMounted && this.setState({ isFetchingOptions: false }); } } } handleSearchOptions() { const { onSearch } = this.props; const { searchStr } = this.state; searchStr && this.handleFetchOptions(onSearch, searchStr); } handleSearch(value, e) { const { onSearch, isPopupOpen } = this.props; !isPopupOpen && e && this.togglePopup(e); const { searchStr = '' } = this.state; const searchStrRegex = getSearchString(searchStr); const valueStrRegex = getSearchString(value); const isSearch = searchStrRegex !== valueStrRegex ? true : false; this.setState({ searchStr: value }, () => { if (!value) { onSearch && onSearch(''); } else if (isSearch && onSearch) { this.handleSearchOptions(); } }); } handleClickSelectedOption() { let id = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; let e = arguments.length > 1 ? arguments[1] : undefined; const { selectedOptions } = this.props; let { highLightedSelectOptions, lastHighLightedSelectOption } = this.state; const { metaKey, ctrlKey, shiftKey } = e; if (e && shiftKey) { //shift+click let from = selectedOptions.indexOf(lastHighLightedSelectOption) >= 0 ? selectedOptions.indexOf(lastHighLightedSelectOption) : 0; let to = id && selectedOptions.indexOf(id) >= 0 ? selectedOptions.indexOf(id) : null; if (to >= 0 && to < from) { [to] = [from, from = to]; } to += 1; const newSelectedHighlights = to ? selectedOptions.slice(from, to) : []; to && this.setState({ highLightedSelectOptions: newSelectedHighlights, lastHighLightedSelectOption: id }); } else if (e && (ctrlKey || metaKey)) { //ctrl+click const isRemove = highLightedSelectOptions.indexOf(id) >= 0; let newSelectedHighlights = []; if (isRemove) { lastHighLightedSelectOption = id === lastHighLightedSelectOption ? '' : lastHighLightedSelectOption; newSelectedHighlights = highLightedSelectOptions.filter(option => option !== id); } else { lastHighLightedSelectOption = id; newSelectedHighlights = [...highLightedSelectOptions, id]; } this.setState({ highLightedSelectOptions: newSelectedHighlights, lastHighLightedSelectOption }); } else { this.setState({ highLightedSelectOptions: [id], lastHighLightedSelectOption: id }); } this.setState({ shiftKeyPressHighLighted: 0 }); this.moveFocusToTextbox(); } handleScroll(e) { let ele = e.target; let isScrollReachedBottom = findScrollEnd(ele); isScrollReachedBottom && this.handleScrollFuncCall(); } handleScrollFuncCall() { const { getNextOptions, isNextOptions } = this.props; const { searchStr } = this.state; isNextOptions && getNextOptions && this.handleFetchOptions(getNextOptions, searchStr); } handleChange() { let selectedOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; let e = arguments.length > 1 ? arguments[1] : undefined; const { optionsNormalize } = this.state; const { onChange, needToCloseOnSelect, togglePopup, selectedOptions: propSelectedOptions, disabledOptions = dummyArray, limit } = this.props; const { newSelectedOptions } = filterSelectedOptions({ selectedOptions, propSelectedOptions, disabledOptions, limit }); const selectedOptionsLen = newSelectedOptions.length; const allSelectedOptionsDetails = []; for (let i = 0; i < selectedOptionsLen; i++) { const id = newSelectedOptions[i]; allSelectedOptionsDetails.push(optionsNormalize[id]); } onChange && onChange(newSelectedOptions, allSelectedOptionsDetails); // this.setState({ searchStr: '' }); this.moveFocusToTextbox(); if (needToCloseOnSelect) { togglePopup(e); } } togglePopup(e) { const { togglePopup, defaultDropBoxPosition, isReadOnly } = this.props; !isReadOnly && togglePopup(e, defaultDropBoxPosition ? `${defaultDropBoxPosition}` : null); } handlePopupClose(e) { const { closePopupOnly } = this.props; closePopupOnly(e); } searchInputRef(el) { const { getRef } = this.props; this.searchInput = el; getRef && getRef(el); } selectedOptionContainerRef(el) { const { getTargetRef } = this.props; this.selectedOptionContainer = el; getTargetRef(el); } selectedOptionRef(el, id) { this[`selectedOption_${id}`] = el; } suggestionContainerRef(el) { this.suggestionContainer = el; typeof this.setSuggestionsVirtualizerRef === 'function' && this.setSuggestionsVirtualizerRef(el); } suggestionItemRef(el, index, id) { this[`suggestion_${id}`] = el; } handleActive(e) { const { searchStr, isActive } = this.state; if (!isActive) { this.setState({ isActive: true }); } const { target } = e || {}; target && target.setSelectionRange(target, 0); const { onFocus } = this.props; onFocus && onFocus(searchStr); } handleInactive() { const { isActive } = this.state; if (isActive) { this.setState({ isActive: false }); } } handleInputFocus() { const { isDisabled, isReadOnly } = this.props; !isDisabled && !isReadOnly && this.moveFocusToTextbox(); } moveFocusToTextbox() { this.searchInput && this.searchInput.focus({ preventScroll: true }); } handleExposedPublicMethods() { const { getPublicMethods, openPopupOnly } = this.props; getPublicMethods && getPublicMethods({ openPopupOnly }); } setSuggestionsVirtualizerContainerRefFunction(refFunc) { this.setSuggestionsVirtualizerRef = refFunc; this.suggestionContainer && refFunc(this.suggestionContainer); } getSelectionUI() { let isResponsive = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; let { size, needBorder, disableAction, borderColor, placeHolder, textBoxSize, variant, textBoxClass, needAutoFocus, htmlId, children, customChildrenClass, autoComplete, a11y, disabledOptions, i18nKeys, isReadOnly, isDisabled, palette, dataId, setAriaId, isPopupOpen, ariaErrorId, customProps, isFocus, isPopupReady, renderCustomClearComponent, renderCustomToggleIndicator } = this.props; let { isActive, selectedOptions, highLightedSelectOptions, searchStr } = this.state; const { clearText = MULTISELECT_I18N_KEYS.clearText } = i18nKeys; const { clearLabel = MULTISELECT_I18N_KEYS.clearLabel, ariaLabelledby } = a11y; let { isShowClearIcon: isShowClear } = this.getIsShowClearIcon({ selectedOptions, disabledOptions }); const isShowClearIcon = !isReadOnly && !isDisabled && !disableAction && isShowClear; const isEditable = !(isReadOnly || isDisabled || disableAction); let { TextBoxIconProps = {} } = customProps; return /*#__PURE__*/React.createElement(Container, { align: "vertical", alignBox: "row", className: `${style.container} ${style[size]} ${needBorder ? !disableAction ? style[`borderColor_${borderColor}`] : style.borderColor_transparent : ''} ${isActive && needBorder || isResponsive || isEditable && isFocus && needBorder ? style.active : ''} ${textBoxClass} ${needBorder ? style.hasBorder : ''}`, eleRef: this.selectedOptionContainerRef, wrap: "wrap" }, /*#__PURE__*/React.createElement(SelectedOptions, { selectedOptions: selectedOptions, highLightedSelectOptions: highLightedSelectOptions, isReadOnly: isReadOnly, getRef: this.selectedOptionRef, onRemove: this.handleRemoveOption, onSelect: this.handleClickSelectedOption, size: size, palette: palette, dataId: `${dataId}_selectedOptions` }), /*#__PURE__*/React.createElement(Box, { flexible: true, className: style.wrapper, adjust: true, shrink: true }, /*#__PURE__*/React.createElement("span", { className: ` ${style.custmSpan} ${textBoxSize === 'xmedium' ? style.custmSpanXmedium : style.custmSpanMedium} ${isShowClearIcon ? style.clearIconSpace : ''} ${customChildrenClass ? customChildrenClass : ''}` }, searchStr), /*#__PURE__*/React.createElement(TextBoxIcon, { isDisabled: isDisabled, inputRef: this.searchInputRef, needBorder: false, onBlur: this.handleInactive, onChange: this.handleSearch, onClick: !isResponsive ? this.handleInputCick : undefined, onFocus: this.handleActive, onKeyDown: this.handleKeyDown, autofocus: needAutoFocus, placeHolder: selectedOptions.length >= 1 ? '' : placeHolder, size: textBoxSize, value: searchStr, variant: variant, dataId: `${dataId}_textBox`, isReadOnly: isReadOnly, tabindex: isDisabled && '-1', customClass: { customTBoxWrap: style.custmInputWrapper }, htmlId: htmlId, a11y: { role: 'combobox', ariaOwns: setAriaId, ariaControls: setAriaId, ariaExpanded: !isReadOnly && !isDisabled && !disableAction && isPopupOpen ? true : false, ariaHaspopup: true, ariaRequired: true, ariaDescribedby: ariaErrorId, ariaLabelledby: ariaLabelledby }, autoComplete: autoComplete, renderRightPlaceholderNode: typeof renderCustomToggleIndicator == 'function' ? renderCustomToggleIndicator({ togglePopup: this.togglePopup, isPopupOpened: isPopupReady, isReadOnly: isReadOnly, isDisabled: isDisabled }) : renderCustomToggleIndicator, ...TextBoxIconProps }, /*#__PURE__*/React.createElement(Container, { isInline: true, isCover: false, alignBox: "row", align: "vertical", className: style.rightPlaceholder }, isShowClearIcon ? typeof renderCustomClearComponent === 'function' ? renderCustomClearComponent({ clearText, isPopupOpened: isPopupReady, handleClearAll: this.handleDeselectAll }) : /*#__PURE__*/React.createElement(Box, { className: `${style.delete} ${style[`${palette}Delete`]}`, dataId: `${dataId}_clearIcon`, "data-title": clearText, onClick: this.handleDeselectAll, tagName: "button", "aria-label": clearLabel }, /*#__PURE__*/React.createElement(Icon, { name: "ZD-delete", size: "15" })) : null, children ? /*#__PURE__*/React.createElement(Box, { dataId: `${dataId}_children` }, children) : null)))); } render() { let { isReadOnly, searchEmptyMessage, emptyMessage, noMoreOptionsMessage, dropBoxSize, isPopupOpen, isPopupReady, position, defaultDropBoxPosition, getContainerRef, removeClose, isAnimate, animationStyle, isDisabled, title, needResponsive, dataId, dataSelectorId, isSearching, borderColor, disableAction, isBoxPaddingNeed, isAbsolutePositioningNeeded, positionsOffset, targetOffset, isRestrictScroll, palette, i18nKeys, getFooter, needEffect, boxSize, isLoading, selectAllText, needSelectAll, isVirtualizerEnabled, limit } = this.props; const { selectedOptions, searchStr, hoverOption, options, isFetchingOptions, selectedOptionIds } = this.state; const { searchText = MULTISELECT_I18N_KEYS.searchText, limitReachedMessage = MULTISELECT_I18N_KEYS.limitReachedMessage } = i18nKeys; const suggestions = this.handleFilterSuggestions(); const setAriaId = this.getNextAriaId(); const ariaErrorId = this.getNextAriaId(); i18nKeys = Object.assign({}, MobileHeader_defaultProps.i18nKeys, i18nKeys, { emptyText: i18nKeys.emptyText || emptyMessage, searchEmptyText: i18nKeys.searchEmptyText || searchEmptyMessage, noMoreText: i18nKeys.noMoreText || noMoreOptionsMessage }); let isModel = isMobilePopover(needResponsive); return /*#__PURE__*/React.createElement("div", { className: `${style.wrapper} ${isDisabled ? style.disabled : ''} ${isReadOnly ? style.readOnly : ''} ${disableAction ? CssProvider('isBlock') : ''} ${borderColor === 'transparent' ? style.transparentContainer : ''} ${needEffect && !(isDisabled || isReadOnly) ? style.effect : ''}`, "data-id": `${isDisabled ? `${dataId}_disabled` : isReadOnly ? `${dataId}_readOnly` : dataId}`, "data-test-id": `${isDisabled ? `${dataId}_disabled` : isReadOnly ? `${dataId}_readOnly` : dataId}`, "data-title": isDisabled ? title : null, onClick: this.handleInputFocus, "data-selector-id": dataSelectorId }, this.getSelectionUI(), !isReadOnly && !isDisabled && !disableAction && isPopupOpen ? /*#__PURE__*/React.createElement(ResponsiveDropBox, { animationStyle: animationStyle, boxPosition: position || `${defaultDropBoxPosition}`, getRef: getContainerRef, isActive: isPopupReady, isAnimate: isAnimate, isArrow: false, onClick: removeClose, needResponsive: needResponsive, isPadding: false, isBoxPaddingNeed: isBoxPaddingNeed, isAbsolutePositioningNeeded: isAbsolutePositioningNeeded, positionsOffset: positionsOffset, targetOffset: targetOffset, isRestrictScroll: isRestrictScroll, palette: palette, htmlId: setAriaId, a11y: { role: 'listbox', ariaMultiselectable: true }, size: boxSize, alignBox: "row", isResponsivePadding: getFooter ? false : true, dataId: `${dataId}_dropbox` }, /*#__PURE__*/React.createElement(Box, { flexible: true }, /*#__PURE__*/React.createElement(Card, { customClass: `${style.box} ${style[`${palette}Box`]}`, onScroll: this.handleScroll }, isModel ? /*#__PURE__*/React.createElement(MobileHeader, { selectedOptions: selectedOptions, i18nKeys: i18nKeys, onClick: this.handlePopupClose }, /*#__PURE__*/React.createElement("div", { className: style.effect }, this.getSelectionUI(true))) : null, needSelectAll && !(limit >= 0) ? /*#__PURE__*/React.createElement(CardHeader, null, /*#__PURE__*/React.createElement(MultiSelectHeader, { onSelect: this.handleSelectAll, selectAllText: selectAllText, suggestions: suggestions, dataId: dataId })) : null, isLoading ? /*#__PURE__*/React.createElement(Container, { align: "both", className: style.loader }, /*#__PURE__*/React.createElement(Loader, null)) : /*#__PURE__*/React.createElement(CardContent, { shrink: true, customClass: !isModel && dropBoxSize ? style[dropBoxSize] : '', eleRef: this.suggestionContainerRef }, isSearching ? /*#__PURE__*/React.createElement("div", { className: style[palette] }, searchText) : suggestions.length ? /*#__PURE__*/React.createElement(Suggestions, { suggestions: suggestions, isVirtualizerEnabled: isVirtualizerEnabled, setVirtualizerContainerRefFunction: this.setSuggestionsVirtualizerContainerRefFunction, getRef: this.suggestionItemRef, hoverOption: hoverOption, onClick: this.handleSelectOption, onMouseEnter: this.handleMouseEnter, needBorder: false, dataId: `${dataId}_Options`, palette: palette, selectedOptions: selectedOptionIds, a11y: { role: 'option' }, limit: limit, limitReachedMessage: limitReachedMessage }) : /*#__PURE__*/React.createElement(EmptyState, { isLoading: isFetchingOptions, options: options, searchString: searchStr, suggestions: suggestions, dataId: dataId, palette: palette, i18nKeys: i18nKeys, htmlId: ariaErrorId }), isFetchingOptions && /*#__PURE__*/React.createElement(Container, { isCover: false, align: "both" }, /*#__PURE__*/React.createElement(Loader, null))), getFooter ? /*#__PURE__*/React.createElement(CardFooter, null, getFooter()) : null))) : null); } } MultiSelectComponent.propTypes = MultiSelect_propTypes; MultiSelectComponent.defaultProps = MultiSelect_defaultProps; MultiSelectComponent.displayName = 'MultiSelect'; const MultiSelect = Popup(MultiSelectComponent); MultiSelect.propTypes = MultiSelectComponent.propTypes; MultiSelect.defaultProps = MultiSelectComponent.defaultProps; export default MultiSelect;