UNPKG

@tabula/ui-multi-selector

Version:

A MultiSelector allows users to select one or more items from a list of choices, or suggest own item.

1,003 lines (963 loc) 28.3 kB
// src/UiMultiSelector/UiMultiSelector.tsx import { useMemo as useMemo6 } from "react"; import { FloatingPortal } from "@floating-ui/react"; import { clsx as clsx6 } from "clsx"; // src/UiMultiSelector/assets/chevron.svg?svgr import * as React from "react"; import { memo } from "react"; import { jsx } from "react/jsx-runtime"; var SvgChevron = (props) => /* @__PURE__ */ jsx("svg", { width: 16, height: 16, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M3.126 6.168a.5.5 0 0 1 .706-.042L8 9.831l4.168-3.705a.5.5 0 0 1 .664.748l-4.5 4a.5.5 0 0 1-.664 0l-4.5-4a.5.5 0 0 1-.042-.706Z", fill: "currentColor" }) }); var Memo = memo(SvgChevron); // src/shared.css.ts var hasChevron = "tabula_ui_multi_selector__1svmv054"; var sizes = { small: "tabula_ui_multi_selector__1svmv052", medium: "tabula_ui_multi_selector__1svmv053" }; var variants = { accent: "tabula_ui_multi_selector__1svmv050", contrast: "tabula_ui_multi_selector__1svmv051" }; // src/UiMultiSelector/UiMultiSelector.css.ts var chevron = "tabula_ui_multi_selector__df9y05b"; var label = "tabula_ui_multi_selector__df9y059"; var root = "tabula_ui_multi_selector__df9y058"; var search = "tabula_ui_multi_selector__df9y05a"; var state = { isEmpty: "tabula_ui_multi_selector__df9y053", isEmptySearch: "tabula_ui_multi_selector__df9y054", isWarning: "tabula_ui_multi_selector__df9y055", isInvalid: "tabula_ui_multi_selector__df9y056", isDisabled: "tabula_ui_multi_selector__df9y057" }; // src/Dropdown/Dropdown.tsx import { forwardRef as forwardRef2 } from "react"; import { clsx as clsx2 } from "clsx/lite"; // src/Dropdown/Dropdown.css.ts var divider = "tabula_ui_multi_selector__1i1fwfx4"; var hasIcons = "tabula_ui_multi_selector__1i1fwfx1"; var highlight = "tabula_ui_multi_selector__1i1fwfx2"; var icon = "tabula_ui_multi_selector__1i1fwfx5"; var isCurrent = "tabula_ui_multi_selector__1i1fwfx8"; var item = "tabula_ui_multi_selector__1i1fwfx6"; var key = "tabula_ui_multi_selector__1i1fwfx9"; var label2 = "tabula_ui_multi_selector__1i1fwfx7"; var root2 = "tabula_ui_multi_selector__1i1fwfx0"; var search2 = "tabula_ui_multi_selector__1i1fwfx3"; // src/Dropdown/Dropdown.Item.tsx import { forwardRef } from "react"; import { clsx } from "clsx/lite"; import { jsx as jsx2, jsxs } from "react/jsx-runtime"; var DropdownItem = forwardRef( ({ children, completeKey, icon: Icon, isCurrent: isCurrent2, onClick, title }, ref) => /* @__PURE__ */ jsxs( "button", { className: clsx(item, isCurrent2 && isCurrent), onClick, ref, tabIndex: -1, title, type: "button", children: [ Icon != null && /* @__PURE__ */ jsx2(Icon, { className: icon }), /* @__PURE__ */ jsx2("span", { className: label2, children }), isCurrent2 && /* @__PURE__ */ jsx2("span", { className: key, children: completeKey }) ] } ) ); if (import.meta.env.DEV) { DropdownItem.displayName = "DropdownItem"; } // src/Dropdown/hooks/useController.ts import { useCallback, useEffect, useImperativeHandle, useRef, useState } from "react"; function useController(controllerRef, { items, search: search3, selected }) { const rootRef = useRef(null); const currentRef = useRef(null); const isHoveredRef = useRef(false); const handleMouseEnter = useCallback(() => { isHoveredRef.current = true; }, []); const handleMouseLeave = useCallback(() => { isHoveredRef.current = false; }, []); const [currentIndex, setCurrentIndex] = useState(0); useEffect(() => { setCurrentIndex(0); }, [search3, selected.size]); useEffect(() => { const { current } = currentRef; if (current == null) { return; } current.scrollIntoView({ block: "nearest" }); }, [currentIndex]); useImperativeHandle( controllerRef, () => ({ goToPrevious: () => { if (isHoveredRef.current || items.length === 0) { return; } setCurrentIndex((current) => { return current === 0 ? items.length - 1 : current - 1; }); }, goToNext: () => { if (isHoveredRef.current || items.length === 0) { return; } setCurrentIndex((current) => { return current === items.length - 1 ? 0 : current + 1; }); }, selectCurrent: () => { if (isHoveredRef.current) { return; } const item2 = items.at(currentIndex); if (item2 == null) { return; } item2.onSelect(); } }), [currentIndex, items] ); return { currentIndex, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, rootRef, currentRef }; } // src/Dropdown/hooks/useHasIcons.ts import { useMemo } from "react"; function hasIcon(item2) { return typeof item2 !== "string" && item2.icon != null; } function useHasIcons({ addFound, allowsCustomValue, options, selectAll, selectFound }) { return useMemo(() => { if (options.some((it) => hasIcon(it))) { return true; } return !allowsCustomValue && hasIcon(selectAll) || hasIcon(addFound) || hasIcon(selectFound); }, [addFound, allowsCustomValue, options, selectAll, selectFound]); } // src/Dropdown/hooks/useItems/useItems.ts import { useMemo as useMemo2 } from "react"; // src/const.ts var searchPlaceholder = "{search}"; // src/Dropdown/hooks/useItems/match.ts function match(rawTarget, rawPattern) { if (rawPattern.length === 0) { return [ true, [ { isMatches: false, substring: rawTarget } ] ]; } const target = rawTarget.toLowerCase(); const pattern = rawPattern.toLowerCase(); const parts = []; let lastIndex = 0; while (true) { const index = target.indexOf(pattern, lastIndex); if (index === -1) { break; } if (index > lastIndex) { parts.push({ isMatches: false, substring: rawTarget.slice(lastIndex, index) }); } lastIndex = index + pattern.length; parts.push({ isMatches: true, substring: rawTarget.slice(index, lastIndex) }); } if (lastIndex < target.length) { parts.push({ isMatches: false, substring: rawTarget.slice(lastIndex) }); } if (parts.length === 1) { return [parts[0].isMatches, parts]; } return [true, parts]; } // src/Dropdown/hooks/useItems/renderFound.tsx import { jsx as jsx3 } from "react/jsx-runtime"; function renderFound(label3, values) { const [isMatches, parts] = match(label3, searchPlaceholder); if (!isMatches) { return label3; } return parts.map((it, index) => { if (!it.isMatches) { return it.substring; } const found = values.reduce((acc, value, valueIndex) => { if (acc.length > 0) { acc.push(/* @__PURE__ */ jsx3("span", { children: ",\xA0" }, `separator-${valueIndex}`)); } acc.push( /* @__PURE__ */ jsx3("span", { className: search2, children: value }, `value-${valueIndex}`) ); return acc; }, []); return /* @__PURE__ */ jsx3("span", { children: found }, index); }); } // src/Dropdown/hooks/useItems/buildBulkCustomValue.ts function buildBulkCustomValue({ addFound, onUpdate, values }) { const handleClick = () => { onUpdate("add-custom", values); }; const { icon: icon2, label: label3 } = typeof addFound === "string" ? { label: addFound } : addFound; return { key: "bulk-custom-value", icon: icon2, label: renderFound(label3, values), onSelect: handleClick }; } // src/Dropdown/hooks/useItems/buildCustomValue.tsx function buildCustomValue({ addFound, onUpdate, search: search3 }) { const handleClick = () => { onUpdate("add-custom", [search3]); }; const { icon: icon2, label: label3 } = typeof addFound === "string" ? { label: addFound } : addFound; return { key: "custom-value", icon: icon2, label: renderFound(label3, [search3]), onSelect: handleClick, hasDividerAfter: true }; } // src/Dropdown/hooks/useItems/renderParts.tsx import { jsx as jsx4 } from "react/jsx-runtime"; function renderParts(parts) { if (parts.length === 0 && !parts[0].isMatches) { return parts[0].substring; } return parts.map( (it, index) => it.isMatches ? /* @__PURE__ */ jsx4("span", { className: highlight, children: it.substring }, index) : it.substring ); } // src/Dropdown/hooks/useItems/buildItems.ts function buildItems({ allowsCustomValue, onUpdate, options, search: search3, selected }) { const values = []; const items = []; if (allowsCustomValue && search3.length === 0) { return [values, items]; } for (const option of options) { const { icon: icon2, label: label3, value } = typeof option === "string" ? { label: option, value: option } : option; if (selected.has(value)) { continue; } const [isMatches, parts] = match(label3 ?? value, search3); if (!isMatches) { continue; } values.push(value); items.push({ key: `item-${value}`, icon: icon2, label: renderParts(parts), title: label3, onSelect: () => { onUpdate("add", [value]); } }); } return [values, items]; } // src/Dropdown/hooks/useItems/buildSelectAll.ts function buildSelectAll({ hasDividerAfter, onUpdate, options, selectAll, selected }) { const handleClick = () => { const ids = options.reduce((result, it) => { const value = typeof it === "string" ? it : it.value; if (!selected.has(value)) { result.push(value); } return result; }, []); onUpdate("add-all", ids); }; const { icon: icon2, label: label3 } = typeof selectAll === "string" ? { label: selectAll } : selectAll; return { key: "select-all", icon: icon2, label: label3, onSelect: handleClick, hasDividerAfter }; } // src/Dropdown/hooks/useItems/buildSelectFound.ts function buildSelectFound({ onUpdate, selectFound, search: search3, values }) { const handleClick = () => { onUpdate("add-found", values); }; const { icon: icon2, label: label3 } = typeof selectFound === "string" ? { label: selectFound } : selectFound; return { key: "select-found", icon: icon2, label: renderFound(label3, [search3]), onSelect: handleClick, hasDividerAfter: true }; } // src/Dropdown/hooks/useItems/useItems.ts function useItems({ addFound, allowsCustomValue, maxSelectedLimit, onUpdate, options, search: search3, selectAll, selectFound, selected }) { return useMemo2(() => { const [values, items] = buildItems({ allowsCustomValue, onUpdate, options, search: search3, selected }); const hasSearch = search3.length > 0; if (allowsCustomValue) { if (hasSearch) { items.unshift(buildCustomValue({ addFound, onUpdate, search: search3 })); const fromSearchValues = search3.split(/,\s|,/).filter((it) => it.trim().length > 0); if (fromSearchValues.length > 1) { items.unshift( buildBulkCustomValue({ addFound, onUpdate, values: fromSearchValues }) ); } } return items; } const isSatisfiesSelectedLimits = maxSelectedLimit == null || maxSelectedLimit > 1; if (isSatisfiesSelectedLimits && items.length > 1) { if (hasSearch) { items.unshift(buildSelectFound({ onUpdate, search: search3, selectFound, values })); } items.unshift( buildSelectAll({ hasDividerAfter: !hasSearch, onUpdate, options, selectAll, selected }) ); } return items; }, [ addFound, allowsCustomValue, maxSelectedLimit, onUpdate, options, search3, selected, selectAll, selectFound ]); } // src/Dropdown/Dropdown.tsx import { jsx as jsx5 } from "react/jsx-runtime"; var Dropdown = forwardRef2( ({ addFound, allowsCustomValue, className, completeKey, maxSelectedLimit, onUpdate, options, search: search3, selectAll, selectFound, selected }, ref) => { const items = useItems({ addFound, allowsCustomValue, maxSelectedLimit, onUpdate, options, search: search3, selectAll, selectFound, selected }); const { currentIndex, currentRef, onMouseEnter, onMouseLeave, rootRef } = useController(ref, { items, selected, search: search3 }); const hasIcons2 = useHasIcons({ addFound, allowsCustomValue, options, selectAll, selectFound }); if (items.length === 0) { return null; } const nodes = []; for (const [idx, item2] of items.entries()) { const { key: key2, icon: icon2, onSelect, label: label3, title, hasDividerAfter } = item2; nodes.push( /* @__PURE__ */ jsx5( DropdownItem, { completeKey, icon: icon2, isCurrent: idx === currentIndex, onClick: onSelect, ref: idx === currentIndex ? currentRef : void 0, title, children: label3 }, key2 ) ); if (hasDividerAfter) { nodes.push(/* @__PURE__ */ jsx5("div", { className: divider }, `${item2.key}-divider`)); } } return ( /* eslint-disable-next-line jsx-a11y/no-static-element-interactions */ /* @__PURE__ */ jsx5( "div", { className: clsx2(root2, hasIcons2 && hasIcons, className), onMouseEnter, onMouseLeave, ref: rootRef, tabIndex: -1, children: nodes } ) ); } ); if (import.meta.env.DEV) { Dropdown.displayName = "Dropdown"; } // src/Search/Search.tsx import { forwardRef as forwardRef3, useMemo as useMemo3 } from "react"; import { clsx as clsx3 } from "clsx/lite"; // src/Search/Search.css.ts var root3 = "tabula_ui_multi_selector__1ih62u60"; // src/Search/Search.hooks.ts import { useCallback as useCallback2 } from "react"; function useHandlers({ completeKey, onArrowDown, onArrowUp, onBlurByTab, onComplete, onEscape, onSearch }) { const handleChange = useCallback2( (event) => { onSearch(event.target.value); }, [onSearch] ); const handleKeyDown = useCallback2( (event) => { if (event.key === "Tab") { if (completeKey === "Tab") { event.preventDefault(); onComplete(); } else { onBlurByTab(); } return; } if (event.key === "Enter") { if (completeKey === "Enter") { event.preventDefault(); onComplete(); } return; } if (event.key !== "ArrowDown" && event.key !== "ArrowUp" && event.key !== "Escape") { return; } event.preventDefault(); switch (event.key) { case "ArrowDown": { onArrowDown(); break; } case "ArrowUp": { onArrowUp(); break; } case "Escape": { onEscape(); break; } } }, [completeKey, onArrowDown, onArrowUp, onBlurByTab, onComplete, onEscape] ); return { onChange: handleChange, onKeyDown: handleKeyDown }; } // src/Search/Search.tsx import { jsx as jsx6 } from "react/jsx-runtime"; var Search = forwardRef3( ({ className, id, isDisabled, onFocus, placeholder, value, ...handlers }, ref) => { const { onChange, onKeyDown } = useHandlers(handlers); const size2 = useMemo3(() => { if (placeholder != null) { return; } return Math.max(1, value.length); }, [placeholder, value.length]); return /* @__PURE__ */ jsx6( "input", { className: clsx3(root3, className), disabled: isDisabled, id, onChange, onFocus, onKeyDown, placeholder, ref, size: size2, value } ); } ); if (import.meta.env.DEV) { Search.displayName = "Search"; } // src/Tags/Tags.tsx import { clsx as clsx5 } from "clsx/lite"; // src/Tags/Tags.css.ts var clear = "tabula_ui_multi_selector__1m6zcss3"; var list = "tabula_ui_multi_selector__1m6zcss4"; var root4 = "tabula_ui_multi_selector__1m6zcss2"; var state2 = { isEmpty: "tabula_ui_multi_selector__1m6zcss0", isDisabled: "tabula_ui_multi_selector__1m6zcss1" }; var tag = "tabula_ui_multi_selector__1m6zcss5"; // src/Clear/Clear.tsx import { useCallback as useCallback3 } from "react"; import { clsx as clsx4 } from "clsx/lite"; // src/Clear/assets/clear.svg?svgr import * as React2 from "react"; import { memo as memo2 } from "react"; import { jsx as jsx7 } from "react/jsx-runtime"; var SvgClear = (props) => /* @__PURE__ */ jsx7("svg", { width: 16, height: 16, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: /* @__PURE__ */ jsx7("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M4.146 4.146a.5.5 0 0 1 .708 0L8 7.293l3.146-3.147a.5.5 0 0 1 .708.708L8.707 8l3.147 3.146a.5.5 0 0 1-.708.708L8 8.707l-3.146 3.147a.5.5 0 0 1-.708-.708L7.293 8 4.146 4.854a.5.5 0 0 1 0-.708Z", fill: "currentColor" }) }); var Memo2 = memo2(SvgClear); // src/Clear/Clear.css.ts var root5 = "tabula_ui_multi_selector__1op479k0"; // src/Clear/Clear.tsx import { jsx as jsx8 } from "react/jsx-runtime"; function Clear({ className, onUpdate }) { const handleClick = useCallback3(() => { onUpdate("remove-all", []); }, [onUpdate]); return /* @__PURE__ */ jsx8( "button", { className: clsx4(root5, className), onClick: handleClick, tabIndex: -1, type: "button", children: /* @__PURE__ */ jsx8(Memo2, {}) } ); } // src/Tags/Tags.hooks.ts import { useMemo as useMemo4 } from "react"; function useTags({ allowsCustomValue, options, selected }) { return useMemo4(() => { const optionsMap = /* @__PURE__ */ new Map(); for (const option of options) { const value = typeof option === "string" ? option : option.value; if (selected.has(value)) { optionsMap.set(value, option); } } const selectedOptions = []; for (const value of selected) { const option = optionsMap.get(value); if (option == null) { if (allowsCustomValue) { selectedOptions.push(value); } } else { selectedOptions.push(option); } } return selectedOptions; }, [selected, options, allowsCustomValue]); } // src/Tags/Tags.tsx import { jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime"; function Tags({ allowsCustomValue, children, isDisabled, onUpdate, options, renderTag, selected }) { const tags = useTags({ allowsCustomValue, options, selected }); return /* @__PURE__ */ jsxs2( "div", { className: clsx5( root4, isDisabled && state2.isDisabled, tags.length === 0 && state2.isEmpty ), children: [ /* @__PURE__ */ jsx9(Clear, { className: clear, onUpdate }), /* @__PURE__ */ jsxs2("div", { className: list, children: [ tags.map((it) => renderTag(tag, it)), children ] }) ] } ); } // src/UiMultiSelector/hooks/useDropdown.ts import { useCallback as useCallback4, useMemo as useMemo5, useRef as useRef2 } from "react"; import { autoUpdate, flip, offset, size, useDismiss, useFloating, useInteractions, useTransitionStyles } from "@floating-ui/react"; import { useFlag } from "@tabula/use-flag"; function useDropdown() { const dropdownRef = useRef2(null); const [open, { on: onShowDropdown, off: onHideDropdown, change: onToggleDropdown }] = useFlag(false); const handleHideDropdown = useCallback4(() => { setTimeout(onHideDropdown, 0); }, [onHideDropdown]); const handleGoNext = useCallback4(() => { dropdownRef.current?.goToNext(); }, []); const handleGoPrevious = useCallback4(() => { dropdownRef.current?.goToPrevious(); }, []); const handleSelect = useCallback4(() => { dropdownRef.current?.selectCurrent(); }, []); const { refs, context, floatingStyles } = useFloating({ placement: "bottom-start", strategy: "fixed", open, onOpenChange(state3) { onToggleDropdown(state3); }, middleware: [ offset({ mainAxis: 4 }), flip(), size({ apply({ rects, elements }) { Object.assign(elements.floating.style, { width: `${rects.reference.width}px` }); } }) ], whileElementsMounted(...args) { return autoUpdate(...args, { ancestorResize: true, ancestorScroll: true, elementResize: true }); } }); const dismiss = useDismiss(context, { escapeKey: true, outsidePress: true }); const { getReferenceProps, getFloatingProps } = useInteractions([dismiss]); const { isMounted: isOpen, styles: transitionStyles } = useTransitionStyles(context); const style = useMemo5( () => ({ ...floatingStyles, ...transitionStyles }), [floatingStyles, transitionStyles] ); return { isOpen, context, dropdownRef, floatingRef: refs.setFloating, referenceRef: refs.setReference, getReferenceProps, getFloatingProps, style, onShowDropdown, onHideDropdown: handleHideDropdown, onGoNext: handleGoNext, onGoPrevious: handleGoPrevious, onSelectCurrent: handleSelect }; } // src/UiMultiSelector/hooks/useSearch.ts import { useCallback as useCallback5, useEffect as useEffect2, useId, useRef as useRef3, useState as useState2 } from "react"; function useSearch(isDisabled) { const searchId = useId(); const searchRef = useRef3(null); const [search3, setSearch] = useState2(""); useEffect2(() => { if (isDisabled) { setSearch(""); } }, [isDisabled]); const onEscape = useCallback5(() => { searchRef.current?.blur(); }, []); return { onEscape, onSearch: setSearch, search: search3, searchId, searchRef }; } // src/UiMultiSelector/hooks/useTagRenderer.tsx import { useCallback as useCallback6 } from "react"; import { UiTag } from "@tabula/ui-tag"; import { jsx as jsx10 } from "react/jsx-runtime"; function useTagRenderer({ isDisabled, onUpdate, size: size2, variant }) { return useCallback6( (className, option) => { const { icon: icon2, label: label3, value } = typeof option === "string" ? { value: option } : option; const handleRemove = () => { onUpdate("remove", [value]); }; return /* @__PURE__ */ jsx10( UiTag, { className, icon: icon2, isDisabled, onRemove: handleRemove, removeTabIndex: -1, size: size2, variant, children: label3 ?? value }, typeof option === "string" ? option : option.value ); }, [onUpdate, isDisabled, size2, variant] ); } // src/UiMultiSelector/hooks/useUpdateHandler.ts import { useCallback as useCallback7 } from "react"; function useUpdateHandler({ maxSelectedLimit, onChange, onSearch, selected }) { return useCallback7( (type, values) => { const next = new Set(selected); const difference = /* @__PURE__ */ new Set(); switch (type) { case "add": case "add-all": case "add-found": case "add-custom": { for (const value of values) { if (maxSelectedLimit != null && next.size >= maxSelectedLimit) { break; } if (!next.has(value)) { difference.add(value); } next.add(value); } break; } case "remove": { for (const value of values) { if (next.has(value)) { difference.add(value); } next.delete(value); } break; } case "remove-all": { for (const value of selected) { difference.add(value); } next.clear(); break; } } onChange(next, type, difference); onSearch(""); }, [selected, onChange, onSearch, maxSelectedLimit] ); } // src/UiMultiSelector/UiMultiSelector.tsx import { jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime"; function UiMultiSelector({ addFound = "Add {search}", allowsCustomValue, className, completeKey = "Enter", defaultPlaceholder, disabledPlaceholder, isDisabled, isInvalid, isWarning, maxSelectedLimit, onChange, options, selectAll = "Select all", selectFound = "Select all containing {search}", selected, size: size2, variant, withDropdownChevron }) { const { onEscape, onSearch, searchId, searchRef, search: search3 } = useSearch(isDisabled); const onUpdate = useUpdateHandler({ maxSelectedLimit, onChange, onSearch, selected }); const { dropdownRef, floatingRef, isOpen, onGoNext, onGoPrevious, onSelectCurrent, onShowDropdown, onHideDropdown, referenceRef, style, getFloatingProps, getReferenceProps } = useDropdown(); const renderTag = useTagRenderer({ isDisabled, onUpdate, size: size2, variant }); const isEmpty = selected.size === 0; const isFilled = maxSelectedLimit != null && selected.size >= maxSelectedLimit || !allowsCustomValue && options.length > 0 && selected.size === options.length; const isPopupVisible = !isDisabled && !isFilled; const isSearchVisible = isPopupVisible || isDisabled && isEmpty; const searchPlaceholder2 = useMemo6(() => { if (isDisabled) { return disabledPlaceholder; } if (!isEmpty) { return; } return defaultPlaceholder; }, [defaultPlaceholder, disabledPlaceholder, isDisabled, isEmpty]); return /* @__PURE__ */ jsxs3( "div", { className: clsx6( root, variants[variant], sizes[size2], withDropdownChevron && hasChevron, isDisabled && state.isDisabled, isEmpty && state.isEmpty, isInvalid && state.isInvalid, isWarning && state.isWarning, className ), ref: referenceRef, ...getReferenceProps(), children: [ withDropdownChevron && !isDisabled && /* @__PURE__ */ jsx11(Memo, { className: chevron }), isSearchVisible && /* @__PURE__ */ jsx11("label", { className: label, "aria-label": searchPlaceholder2, htmlFor: searchId }), /* @__PURE__ */ jsx11( Tags, { allowsCustomValue, isDisabled, onUpdate, options, renderTag, selected, children: isSearchVisible && /* @__PURE__ */ jsx11( Search, { className: clsx6(search, search3 === "" && state.isEmptySearch), completeKey, id: searchId, isDisabled, onArrowDown: onGoNext, onArrowUp: onGoPrevious, onBlurByTab: onHideDropdown, onComplete: onSelectCurrent, onEscape, onFocus: onShowDropdown, onSearch, placeholder: searchPlaceholder2, ref: searchRef, value: search3 } ) } ), isPopupVisible && /* @__PURE__ */ jsx11(FloatingPortal, { preserveTabOrder: false, children: /* @__PURE__ */ jsx11("div", { ref: floatingRef, style, ...getFloatingProps(), children: isOpen && /* @__PURE__ */ jsx11( Dropdown, { addFound, allowsCustomValue, completeKey, maxSelectedLimit, onUpdate, options, ref: dropdownRef, search: search3, selectAll, selectFound, selected } ) }) }) ] } ); } if (import.meta.env.DEV) { UiMultiSelector.displayName = "ui-multi-selector(UiMultiSelector)"; } export { UiMultiSelector, searchPlaceholder }; // post-build: auto import bundled styles import "./index.css"; //# sourceMappingURL=index.js.map