@dxos/react-ui-searchlist 0.8.4-main.c4373fc → 0.8.4-main.c85a9c8dae

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +1 -1
  2. package/dist/lib/browser/index.mjs +716 -408
  3. package/dist/lib/browser/index.mjs.map +4 -4
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/node-esm/index.mjs +716 -408
  6. package/dist/lib/node-esm/index.mjs.map +4 -4
  7. package/dist/lib/node-esm/meta.json +1 -1
  8. package/dist/types/src/components/Combobox/Combobox.d.ts +85 -0
  9. package/dist/types/src/components/Combobox/Combobox.d.ts.map +1 -0
  10. package/dist/types/src/{composites/PopoverCombobox.stories.d.ts → components/Combobox/Combobox.stories.d.ts} +10 -1
  11. package/dist/types/src/components/Combobox/Combobox.stories.d.ts.map +1 -0
  12. package/dist/types/src/components/Combobox/index.d.ts +2 -0
  13. package/dist/types/src/components/Combobox/index.d.ts.map +1 -0
  14. package/dist/types/src/components/{Listbox.d.ts → Listbox/Listbox.d.ts} +6 -6
  15. package/dist/types/src/components/Listbox/Listbox.d.ts.map +1 -0
  16. package/dist/types/src/components/Listbox/Listbox.stories.d.ts +21 -0
  17. package/dist/types/src/components/Listbox/Listbox.stories.d.ts.map +1 -0
  18. package/dist/types/src/components/Listbox/index.d.ts +2 -0
  19. package/dist/types/src/components/Listbox/index.d.ts.map +1 -0
  20. package/dist/types/src/components/SearchList/SearchList.d.ts +90 -0
  21. package/dist/types/src/components/SearchList/SearchList.d.ts.map +1 -0
  22. package/dist/types/src/components/SearchList/SearchList.stories.d.ts +28 -0
  23. package/dist/types/src/components/SearchList/SearchList.stories.d.ts.map +1 -0
  24. package/dist/types/src/components/SearchList/context.d.ts +33 -0
  25. package/dist/types/src/components/SearchList/context.d.ts.map +1 -0
  26. package/dist/types/src/components/SearchList/hooks/index.d.ts +5 -0
  27. package/dist/types/src/components/SearchList/hooks/index.d.ts.map +1 -0
  28. package/dist/types/src/components/SearchList/hooks/useGlobalFilter.d.ts +34 -0
  29. package/dist/types/src/components/SearchList/hooks/useGlobalFilter.d.ts.map +1 -0
  30. package/dist/types/src/components/SearchList/hooks/useSearchListInput.d.ts +12 -0
  31. package/dist/types/src/components/SearchList/hooks/useSearchListInput.d.ts.map +1 -0
  32. package/dist/types/src/components/SearchList/hooks/useSearchListItem.d.ts +10 -0
  33. package/dist/types/src/components/SearchList/hooks/useSearchListItem.d.ts.map +1 -0
  34. package/dist/types/src/components/SearchList/hooks/useSearchListResults.d.ts +36 -0
  35. package/dist/types/src/components/SearchList/hooks/useSearchListResults.d.ts.map +1 -0
  36. package/dist/types/src/components/SearchList/index.d.ts +3 -0
  37. package/dist/types/src/components/SearchList/index.d.ts.map +1 -0
  38. package/dist/types/src/components/index.d.ts +2 -1
  39. package/dist/types/src/components/index.d.ts.map +1 -1
  40. package/dist/types/src/index.d.ts +0 -1
  41. package/dist/types/src/index.d.ts.map +1 -1
  42. package/dist/types/src/translations.d.ts +4 -2
  43. package/dist/types/src/translations.d.ts.map +1 -1
  44. package/dist/types/tsconfig.tsbuildinfo +1 -1
  45. package/package.json +21 -18
  46. package/src/components/Combobox/Combobox.stories.tsx +62 -0
  47. package/src/components/Combobox/Combobox.tsx +343 -0
  48. package/src/components/Combobox/index.ts +5 -0
  49. package/src/components/Listbox/Listbox.stories.tsx +53 -0
  50. package/src/components/{Listbox.tsx → Listbox/Listbox.tsx} +40 -11
  51. package/src/components/Listbox/index.ts +5 -0
  52. package/src/components/SearchList/SearchList.stories.tsx +532 -0
  53. package/src/components/SearchList/SearchList.tsx +554 -0
  54. package/src/components/SearchList/context.ts +43 -0
  55. package/src/components/SearchList/hooks/index.ts +8 -0
  56. package/src/components/SearchList/hooks/useGlobalFilter.tsx +61 -0
  57. package/src/components/SearchList/hooks/useSearchListInput.ts +14 -0
  58. package/src/components/SearchList/hooks/useSearchListItem.ts +14 -0
  59. package/src/components/SearchList/hooks/useSearchListResults.ts +104 -0
  60. package/src/components/SearchList/index.ts +6 -0
  61. package/src/components/index.ts +2 -1
  62. package/src/index.ts +0 -1
  63. package/src/translations.ts +4 -2
  64. package/src/types/command-score.d.ts +16 -0
  65. package/dist/types/src/components/Listbox.d.ts.map +0 -1
  66. package/dist/types/src/components/Listbox.stories.d.ts +0 -16
  67. package/dist/types/src/components/Listbox.stories.d.ts.map +0 -1
  68. package/dist/types/src/components/SearchList.d.ts +0 -47
  69. package/dist/types/src/components/SearchList.d.ts.map +0 -1
  70. package/dist/types/src/components/SearchList.stories.d.ts +0 -16
  71. package/dist/types/src/components/SearchList.stories.d.ts.map +0 -1
  72. package/dist/types/src/composites/PopoverCombobox.d.ts +0 -32
  73. package/dist/types/src/composites/PopoverCombobox.d.ts.map +0 -1
  74. package/dist/types/src/composites/PopoverCombobox.stories.d.ts.map +0 -1
  75. package/dist/types/src/composites/index.d.ts +0 -2
  76. package/dist/types/src/composites/index.d.ts.map +0 -1
  77. package/src/components/Listbox.stories.tsx +0 -73
  78. package/src/components/SearchList.stories.tsx +0 -55
  79. package/src/components/SearchList.tsx +0 -251
  80. package/src/composites/PopoverCombobox.stories.tsx +0 -47
  81. package/src/composites/PopoverCombobox.tsx +0 -209
  82. package/src/composites/index.ts +0 -5
@@ -1,183 +1,656 @@
1
- // src/components/SearchList.tsx
2
- import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
3
- import { createContext } from "@radix-ui/react-context";
1
+ // src/components/Combobox/Combobox.tsx
2
+ import { createContext as createContext3 } from "@radix-ui/react-context";
3
+ import { useControllableState as useControllableState2 } from "@radix-ui/react-use-controllable-state";
4
+ import React3, { forwardRef as forwardRef2, useCallback as useCallback3 } from "react";
5
+ import { Button, Icon as Icon2, Popover } from "@dxos/react-ui";
6
+ import { useId } from "@dxos/react-ui";
7
+ import { mx as mx2 } from "@dxos/ui-theme";
8
+
9
+ // src/components/SearchList/SearchList.tsx
4
10
  import { useControllableState } from "@radix-ui/react-use-controllable-state";
5
- import { CommandEmpty, CommandInput, CommandItem, CommandList, CommandRoot } from "cmdk";
6
- import React, { forwardRef, useCallback } from "react";
7
- import { Button, Icon, useDensityContext, useElevationContext, useId, useThemeContext } from "@dxos/react-ui";
8
- import { mx, staticPlaceholderText } from "@dxos/react-ui-theme";
9
- var COMBOBOX_NAME = "Combobox";
10
- var COMBOBOX_TRIGGER_NAME = "ComboboxTrigger";
11
- var SEARCHLIST_NAME = "SearchList";
12
- var SEARCHLIST_ITEM_NAME = "SearchListItem";
13
- var [ComboboxProvider, useComboboxContext] = createContext(COMBOBOX_NAME, {});
14
- var SearchListRoot = /* @__PURE__ */ forwardRef(({ children, classNames, ...props }, forwardedRef) => {
15
- var _effect = _useSignals();
16
- try {
17
- return /* @__PURE__ */ React.createElement(CommandRoot, {
18
- ...props,
19
- className: mx("", classNames),
20
- ref: forwardedRef
21
- }, children);
22
- } finally {
23
- _effect.f();
24
- }
25
- });
26
- SearchListRoot.displayName = SEARCHLIST_NAME;
27
- var SearchListInput = /* @__PURE__ */ forwardRef(({ classNames, density: propsDensity, elevation: propsElevation, variant, ...props }, forwardedRef) => {
28
- var _effect = _useSignals();
29
- try {
30
- const { hasIosKeyboard } = useThemeContext();
31
- const { tx } = useThemeContext();
32
- const density = useDensityContext(propsDensity);
33
- const elevation = useElevationContext(propsElevation);
34
- return /* @__PURE__ */ React.createElement(CommandInput, {
35
- ...props,
36
- className: tx("input.input", "input", {
37
- variant,
38
- disabled: props.disabled,
39
- density,
40
- elevation
41
- }, "mbe-cardSpacingBlock", classNames),
42
- ...props.autoFocus && !hasIosKeyboard && {
43
- autoFocus: true
44
- },
45
- ref: forwardedRef
46
- });
47
- } finally {
48
- _effect.f();
11
+ import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
12
+ import { Icon, ScrollArea, useDensityContext, useElevationContext, useThemeContext, useTranslation } from "@dxos/react-ui";
13
+ import { mx } from "@dxos/ui-theme";
14
+
15
+ // src/translations.ts
16
+ var translationKey = "@dxos/react-ui-searchlist";
17
+ var translations = [
18
+ {
19
+ "en-US": {
20
+ [translationKey]: {
21
+ "search.placeholder": "Search..."
22
+ }
23
+ }
49
24
  }
25
+ ];
26
+
27
+ // src/components/SearchList/context.ts
28
+ import { createContext } from "@radix-ui/react-context";
29
+ var [SearchListItemContextProvider, useSearchListItemContext] = createContext("SearchListItem");
30
+ var [SearchListInputContextProvider, useSearchListInputContext] = createContext("SearchListInput");
31
+
32
+ // src/components/SearchList/SearchList.tsx
33
+ var SearchListRoot = ({ children, value: valueProp, defaultValue = "", debounceMs = 200, onSearch }) => {
34
+ const [query = "", setQuery] = useControllableState({
35
+ prop: valueProp,
36
+ defaultProp: defaultValue,
37
+ onChange: void 0
38
+ });
39
+ const [selectedValue, setSelectedValue] = useState(void 0);
40
+ const itemsRef = useRef(/* @__PURE__ */ new Map());
41
+ const debounceRef = useRef(null);
42
+ const handleQueryChange = useCallback((newQuery) => {
43
+ setQuery(newQuery);
44
+ if (debounceRef.current) {
45
+ clearTimeout(debounceRef.current);
46
+ }
47
+ debounceRef.current = setTimeout(() => {
48
+ onSearch?.(newQuery);
49
+ }, debounceMs);
50
+ }, [
51
+ setQuery,
52
+ onSearch,
53
+ debounceMs
54
+ ]);
55
+ const [itemVersion, setItemVersion] = useState(0);
56
+ useEffect(() => {
57
+ return () => {
58
+ if (debounceRef.current) {
59
+ clearTimeout(debounceRef.current);
60
+ }
61
+ };
62
+ }, []);
63
+ useEffect(() => {
64
+ const currentItem = selectedValue !== void 0 ? itemsRef.current.get(selectedValue) : void 0;
65
+ const isSelectionValid = currentItem !== void 0 && !currentItem.disabled;
66
+ if (!isSelectionValid && itemsRef.current.size > 0) {
67
+ const entries = Array.from(itemsRef.current.entries()).filter(([, data]) => !data.disabled);
68
+ if (entries.length > 0) {
69
+ entries.sort(([, a], [, b]) => {
70
+ const position = a.element.compareDocumentPosition(b.element);
71
+ if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
72
+ return -1;
73
+ }
74
+ if (position & Node.DOCUMENT_POSITION_PRECEDING) {
75
+ return 1;
76
+ }
77
+ return 0;
78
+ });
79
+ const firstValue = entries[0]?.[0];
80
+ if (firstValue !== void 0 && firstValue !== selectedValue) {
81
+ setSelectedValue(firstValue);
82
+ }
83
+ } else if (selectedValue !== void 0) {
84
+ setSelectedValue(void 0);
85
+ }
86
+ }
87
+ }, [
88
+ itemVersion,
89
+ selectedValue
90
+ ]);
91
+ const registerItem = useCallback((value, element, onSelect, disabled) => {
92
+ if (element) {
93
+ itemsRef.current.set(value, {
94
+ element,
95
+ onSelect,
96
+ disabled
97
+ });
98
+ setItemVersion((v) => v + 1);
99
+ }
100
+ }, []);
101
+ const unregisterItem = useCallback((value) => {
102
+ itemsRef.current.delete(value);
103
+ setItemVersion((v) => v + 1);
104
+ }, []);
105
+ const getItemValues = useCallback(() => {
106
+ return Array.from(itemsRef.current.entries()).filter(([, data]) => !data.disabled).sort(([, a], [, b]) => {
107
+ const position = a.element.compareDocumentPosition(b.element);
108
+ return position & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : position & Node.DOCUMENT_POSITION_PRECEDING ? 1 : 0;
109
+ }).map(([value]) => value);
110
+ }, []);
111
+ const triggerSelect = useCallback(() => {
112
+ if (selectedValue !== void 0) {
113
+ const item = itemsRef.current.get(selectedValue);
114
+ item?.onSelect?.();
115
+ }
116
+ }, [
117
+ selectedValue
118
+ ]);
119
+ const itemContextValue = useMemo(() => ({
120
+ selectedValue,
121
+ onSelectedValueChange: setSelectedValue,
122
+ registerItem,
123
+ unregisterItem
124
+ }), [
125
+ selectedValue,
126
+ registerItem,
127
+ unregisterItem
128
+ ]);
129
+ const inputContextValue = useMemo(() => ({
130
+ query,
131
+ onQueryChange: handleQueryChange,
132
+ selectedValue,
133
+ onSelectedValueChange: setSelectedValue,
134
+ getItemValues,
135
+ triggerSelect
136
+ }), [
137
+ query,
138
+ handleQueryChange,
139
+ selectedValue,
140
+ getItemValues,
141
+ triggerSelect
142
+ ]);
143
+ return /* @__PURE__ */ React.createElement(SearchListInputContextProvider, {
144
+ query: inputContextValue.query,
145
+ onQueryChange: inputContextValue.onQueryChange,
146
+ selectedValue: inputContextValue.selectedValue,
147
+ onSelectedValueChange: inputContextValue.onSelectedValueChange,
148
+ getItemValues: inputContextValue.getItemValues,
149
+ triggerSelect: inputContextValue.triggerSelect
150
+ }, /* @__PURE__ */ React.createElement(SearchListItemContextProvider, {
151
+ selectedValue: itemContextValue.selectedValue,
152
+ onSelectedValueChange: itemContextValue.onSelectedValueChange,
153
+ registerItem: itemContextValue.registerItem,
154
+ unregisterItem: itemContextValue.unregisterItem
155
+ }, children));
156
+ };
157
+ SearchListRoot.displayName = "SearchList.Root";
158
+ var SearchListContent = /* @__PURE__ */ forwardRef(({ classNames, children, ...props }, forwardedRef) => {
159
+ return /* @__PURE__ */ React.createElement("div", {
160
+ role: "none",
161
+ ...props,
162
+ className: mx("dx-container flex flex-col gap-3", classNames),
163
+ ref: forwardedRef
164
+ }, children);
50
165
  });
51
- var SearchListContent = /* @__PURE__ */ forwardRef(({ children, classNames, ...props }, forwardedRef) => {
52
- var _effect = _useSignals();
53
- try {
54
- return /* @__PURE__ */ React.createElement(CommandList, {
55
- ...props,
56
- className: mx(classNames),
57
- ref: forwardedRef
58
- }, children);
59
- } finally {
60
- _effect.f();
61
- }
166
+ SearchListContent.displayName = "SearchList.Content";
167
+ var SearchListInput = /* @__PURE__ */ forwardRef(({ classNames, density: propsDensity, elevation: propsElevation, variant, placeholder, onChange, ...props }, forwardedRef) => {
168
+ const { query, onQueryChange, selectedValue, onSelectedValueChange, getItemValues, triggerSelect } = useSearchListInputContext("SearchList.Input");
169
+ const { t } = useTranslation(translationKey);
170
+ const { hasIosKeyboard, tx } = useThemeContext();
171
+ const density = useDensityContext(propsDensity);
172
+ const elevation = useElevationContext(propsElevation);
173
+ const defaultPlaceholder = t("search.placeholder");
174
+ const handleChange = useCallback((event) => {
175
+ onQueryChange(event.target.value);
176
+ onChange?.(event);
177
+ }, [
178
+ onQueryChange,
179
+ onChange
180
+ ]);
181
+ const handleKeyDown = useCallback((event) => {
182
+ const values = getItemValues();
183
+ if (values.length === 0) {
184
+ if (event.key === "Escape") {
185
+ onQueryChange("");
186
+ }
187
+ return;
188
+ }
189
+ const currentIndex = selectedValue !== void 0 ? values.indexOf(selectedValue) : -1;
190
+ switch (event.key) {
191
+ case "ArrowDown": {
192
+ event.preventDefault();
193
+ const nextIndex = currentIndex === -1 ? 0 : Math.min(currentIndex + 1, values.length - 1);
194
+ const nextValue = values[nextIndex];
195
+ if (nextValue !== void 0) {
196
+ onSelectedValueChange(nextValue);
197
+ }
198
+ break;
199
+ }
200
+ case "ArrowUp": {
201
+ event.preventDefault();
202
+ const prevIndex = currentIndex === -1 ? values.length - 1 : Math.max(currentIndex - 1, 0);
203
+ const prevValue = values[prevIndex];
204
+ if (prevValue !== void 0) {
205
+ onSelectedValueChange(prevValue);
206
+ }
207
+ break;
208
+ }
209
+ case "Enter": {
210
+ if (selectedValue !== void 0) {
211
+ event.preventDefault();
212
+ triggerSelect();
213
+ }
214
+ break;
215
+ }
216
+ case "Home": {
217
+ event.preventDefault();
218
+ const firstValue = values[0];
219
+ if (firstValue !== void 0) {
220
+ onSelectedValueChange(firstValue);
221
+ }
222
+ break;
223
+ }
224
+ case "End": {
225
+ event.preventDefault();
226
+ const lastValue = values[values.length - 1];
227
+ if (lastValue !== void 0) {
228
+ onSelectedValueChange(lastValue);
229
+ }
230
+ break;
231
+ }
232
+ case "Escape": {
233
+ event.preventDefault();
234
+ if (selectedValue !== void 0) {
235
+ onSelectedValueChange(void 0);
236
+ } else {
237
+ onQueryChange("");
238
+ }
239
+ break;
240
+ }
241
+ }
242
+ }, [
243
+ selectedValue,
244
+ onSelectedValueChange,
245
+ getItemValues,
246
+ triggerSelect,
247
+ onQueryChange
248
+ ]);
249
+ return /* @__PURE__ */ React.createElement("input", {
250
+ ...props,
251
+ ...props.autoFocus && !hasIosKeyboard && {
252
+ autoFocus: true
253
+ },
254
+ type: "text",
255
+ placeholder: placeholder ?? defaultPlaceholder,
256
+ className: tx("input.input", {
257
+ variant,
258
+ disabled: props.disabled,
259
+ density,
260
+ elevation
261
+ }, classNames),
262
+ value: query,
263
+ onChange: handleChange,
264
+ onKeyDown: handleKeyDown,
265
+ ref: forwardedRef
266
+ });
62
267
  });
63
- var SearchListEmpty = /* @__PURE__ */ forwardRef(({ children, classNames, ...props }, forwardedRef) => {
64
- var _effect = _useSignals();
65
- try {
66
- return /* @__PURE__ */ React.createElement(CommandEmpty, {
67
- ...props,
68
- className: mx(classNames),
69
- ref: forwardedRef
70
- }, children);
71
- } finally {
72
- _effect.f();
73
- }
268
+ SearchListInput.displayName = "SearchList.Input";
269
+ var SearchListViewport = /* @__PURE__ */ forwardRef(({ classNames, children }, forwardedRef) => {
270
+ return /* @__PURE__ */ React.createElement(ScrollArea.Root, {
271
+ role: "listbox",
272
+ classNames: mx(classNames),
273
+ ref: forwardedRef,
274
+ thin: true
275
+ }, /* @__PURE__ */ React.createElement(ScrollArea.Viewport, null, children));
74
276
  });
75
- var commandItem = "flex items-center overflow-hidden";
76
- var searchListItem = "plb-1 pli-2 rounded-sm select-none cursor-pointer data-[selected]:bg-hoverOverlay hover:bg-hoverOverlay";
77
- var SearchListItem = /* @__PURE__ */ forwardRef(({ children, classNames, onSelect, ...props }, forwardedRef) => {
78
- var _effect = _useSignals();
79
- try {
80
- const { onValueChange, onOpenChange } = useComboboxContext(SEARCHLIST_ITEM_NAME);
81
- const handleSelect = useCallback((nextValue) => {
82
- onValueChange?.(nextValue);
83
- onOpenChange?.(false);
84
- onSelect?.(nextValue);
85
- }, [
86
- onValueChange,
87
- onOpenChange,
88
- onSelect
89
- ]);
90
- return /* @__PURE__ */ React.createElement(CommandItem, {
91
- ...props,
92
- onSelect: handleSelect,
93
- className: mx(searchListItem, classNames),
94
- ref: forwardedRef
95
- }, children);
96
- } finally {
97
- _effect.f();
98
- }
277
+ SearchListViewport.displayName = "SearchList.Viewport";
278
+ var SearchListItem = /* @__PURE__ */ forwardRef(({ classNames, value, label, icon, iconClassNames, checked, suffix, onSelect, disabled }, forwardedRef) => {
279
+ const { selectedValue, registerItem, unregisterItem } = useSearchListItemContext("SearchList.Item");
280
+ const internalRef = useRef(null);
281
+ const isSelected = selectedValue === value && !disabled;
282
+ useEffect(() => {
283
+ const element = internalRef.current;
284
+ if (element) {
285
+ registerItem(value, element, onSelect, disabled);
286
+ }
287
+ return () => unregisterItem(value);
288
+ }, [
289
+ value,
290
+ onSelect,
291
+ disabled,
292
+ registerItem,
293
+ unregisterItem
294
+ ]);
295
+ useEffect(() => {
296
+ if (isSelected && internalRef.current) {
297
+ internalRef.current.scrollIntoView({
298
+ block: "nearest",
299
+ behavior: "smooth"
300
+ });
301
+ }
302
+ }, [
303
+ isSelected
304
+ ]);
305
+ const handleClick = useCallback(() => {
306
+ if (!disabled) {
307
+ onSelect?.();
308
+ }
309
+ }, [
310
+ onSelect,
311
+ disabled
312
+ ]);
313
+ return /* @__PURE__ */ React.createElement("div", {
314
+ ref: (node) => {
315
+ internalRef.current = node;
316
+ if (typeof forwardedRef === "function") {
317
+ forwardedRef(node);
318
+ } else if (forwardedRef) {
319
+ forwardedRef.current = node;
320
+ }
321
+ },
322
+ role: "option",
323
+ "aria-selected": isSelected,
324
+ "aria-disabled": disabled,
325
+ "data-selected": isSelected,
326
+ "data-disabled": disabled,
327
+ "data-value": value,
328
+ tabIndex: -1,
329
+ className: mx("flex gap-2 items-center", "py-1 px-2 rounded-xs select-none cursor-pointer data-[selected=true]:bg-hover-overlay hover:bg-hover-overlay", disabled && "opacity-50 cursor-not-allowed hover:bg-transparent data-[selected=true]:bg-transparent", classNames),
330
+ onClick: handleClick
331
+ }, icon && /* @__PURE__ */ React.createElement(Icon, {
332
+ icon,
333
+ size: 5,
334
+ classNames: iconClassNames
335
+ }), /* @__PURE__ */ React.createElement("span", {
336
+ className: "w-0 grow truncate"
337
+ }, label), suffix && /* @__PURE__ */ React.createElement("span", {
338
+ className: "shrink-0 text-description"
339
+ }, suffix), checked && /* @__PURE__ */ React.createElement(Icon, {
340
+ icon: "ph--check--regular",
341
+ size: 5
342
+ }));
99
343
  });
100
- SearchListItem.displayName = SEARCHLIST_ITEM_NAME;
101
- var ComboboxRoot = ({ modalId: propsModalId, open: propsOpen, defaultOpen, onOpenChange: propsOnOpenChange, value: propsValue, defaultValue, onValueChange: propsOnValueChange, placeholder, children }) => {
102
- var _effect = _useSignals();
103
- try {
104
- const modalId = useId(COMBOBOX_NAME, propsModalId);
105
- const [open = false, onOpenChange] = useControllableState({
106
- prop: propsOpen,
107
- onChange: propsOnOpenChange,
108
- defaultProp: defaultOpen
109
- });
110
- const [value = "", onValueChange] = useControllableState({
111
- prop: propsValue,
112
- onChange: propsOnValueChange,
113
- defaultProp: defaultValue
114
- });
115
- return /* @__PURE__ */ React.createElement(ComboboxProvider, {
116
- isCombobox: true,
117
- modalId,
118
- open,
119
- onOpenChange,
120
- value,
121
- onValueChange,
122
- placeholder
123
- }, children);
124
- } finally {
125
- _effect.f();
126
- }
344
+ SearchListItem.displayName = "SearchList.Item";
345
+ var SearchListEmpty = ({ classNames, children }) => {
346
+ return /* @__PURE__ */ React.createElement("div", {
347
+ role: "status",
348
+ className: mx("flex flex-col w-full px-2 py-1", classNames)
349
+ }, children);
127
350
  };
128
- ComboboxRoot.displayName = COMBOBOX_NAME;
129
- var ComboboxTrigger = /* @__PURE__ */ forwardRef(({ children, onClick, ...props }, forwardedRef) => {
130
- var _effect = _useSignals();
131
- try {
132
- const { modalId, open, onOpenChange, placeholder, value } = useComboboxContext(COMBOBOX_TRIGGER_NAME);
133
- const handleClick = useCallback((event) => {
134
- onClick?.(event);
135
- onOpenChange?.(true);
136
- }, [
137
- onClick,
138
- onOpenChange
139
- ]);
140
- return /* @__PURE__ */ React.createElement(Button, {
141
- ...props,
142
- role: "combobox",
143
- "aria-expanded": open,
144
- "aria-controls": modalId,
145
- "aria-haspopup": "dialog",
146
- onClick: handleClick,
147
- ref: forwardedRef
148
- }, children ?? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", {
149
- className: mx("font-normal text-start flex-1 min-is-0 truncate mie-2", !value && staticPlaceholderText)
150
- }, value || placeholder), /* @__PURE__ */ React.createElement(Icon, {
151
- icon: "ph--caret-down--bold",
152
- size: 3
153
- })));
154
- } finally {
155
- _effect.f();
156
- }
351
+ SearchListEmpty.displayName = "SearchList.Empty";
352
+ var SearchListGroup = /* @__PURE__ */ forwardRef(({ classNames, heading, children }, forwardedRef) => {
353
+ return /* @__PURE__ */ React.createElement("div", {
354
+ ref: forwardedRef,
355
+ role: "group",
356
+ className: mx("flex flex-col", classNames)
357
+ }, heading && /* @__PURE__ */ React.createElement("div", {
358
+ role: "presentation",
359
+ className: "px-2 py-1 text-xs font-medium text-description"
360
+ }, heading), children);
157
361
  });
158
- ComboboxTrigger.displayName = COMBOBOX_TRIGGER_NAME;
362
+ SearchListGroup.displayName = "SearchList.Group";
159
363
  var SearchList = {
160
364
  Root: SearchListRoot,
161
- Input: SearchListInput,
162
365
  Content: SearchListContent,
366
+ Viewport: SearchListViewport,
367
+ Input: SearchListInput,
368
+ Item: SearchListItem,
163
369
  Empty: SearchListEmpty,
164
- Item: SearchListItem
370
+ Group: SearchListGroup
371
+ };
372
+
373
+ // src/components/SearchList/hooks/useGlobalFilter.tsx
374
+ import React2, { createContext as createContext2, useContext, useMemo as useMemo2 } from "react";
375
+ var GlobalFilterContext = /* @__PURE__ */ createContext2({});
376
+ var GlobalFilterProvider = ({ children, filter }) => {
377
+ const value = useMemo2(() => ({
378
+ filter
379
+ }), [
380
+ filter
381
+ ]);
382
+ return /* @__PURE__ */ React2.createElement(GlobalFilterContext.Provider, {
383
+ value
384
+ }, children);
385
+ };
386
+ var useGlobalFilter = () => {
387
+ return useContext(GlobalFilterContext);
388
+ };
389
+ var useGlobalFilteredObjects = (objects) => {
390
+ const { filter } = useGlobalFilter();
391
+ return useMemo2(() => {
392
+ if (!objects) {
393
+ return [];
394
+ }
395
+ if (!filter) {
396
+ return objects;
397
+ }
398
+ return filter(objects);
399
+ }, [
400
+ objects,
401
+ filter
402
+ ]);
403
+ };
404
+
405
+ // src/components/SearchList/hooks/useSearchListInput.ts
406
+ var useSearchListInput = () => {
407
+ const { query, onQueryChange, selectedValue, onSelectedValueChange, getItemValues, triggerSelect } = useSearchListInputContext("useSearchListInput");
408
+ return {
409
+ query,
410
+ onQueryChange,
411
+ selectedValue,
412
+ onSelectedValueChange,
413
+ getItemValues,
414
+ triggerSelect
415
+ };
165
416
  };
417
+
418
+ // src/components/SearchList/hooks/useSearchListItem.ts
419
+ var useSearchListItem = () => {
420
+ const { selectedValue, registerItem, unregisterItem } = useSearchListItemContext("useSearchListItem");
421
+ return {
422
+ selectedValue,
423
+ registerItem,
424
+ unregisterItem
425
+ };
426
+ };
427
+
428
+ // src/components/SearchList/hooks/useSearchListResults.ts
429
+ import commandScore from "command-score";
430
+ import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo3, useRef as useRef2, useState as useState2 } from "react";
431
+ var useSearchListResults = ({ items, filter, fuzzy = true, extract, minScore = 0 }) => {
432
+ const [query, setQuery] = useState2("");
433
+ const queryRef = useRef2("");
434
+ useEffect2(() => {
435
+ queryRef.current = "";
436
+ setQuery("");
437
+ }, [
438
+ items
439
+ ]);
440
+ const defaultExtract = useCallback2((item) => {
441
+ if (typeof item === "string") {
442
+ return item;
443
+ }
444
+ return item?.label ?? "";
445
+ }, []);
446
+ const extractFn = extract ?? defaultExtract;
447
+ const defaultFilter = useCallback2((item, query2) => {
448
+ const searchable = extractFn(item);
449
+ return searchable.toLowerCase().includes(query2.toLowerCase());
450
+ }, [
451
+ extractFn
452
+ ]);
453
+ const filterFn = filter ?? defaultFilter;
454
+ const handleSearch = useCallback2((searchQuery) => {
455
+ queryRef.current = searchQuery;
456
+ setQuery(searchQuery);
457
+ }, []);
458
+ const results = useMemo3(() => {
459
+ const currentQuery = queryRef.current;
460
+ if (!currentQuery) {
461
+ return items;
462
+ }
463
+ if (fuzzy) {
464
+ const scored = items.map((item) => ({
465
+ item,
466
+ score: commandScore(extractFn(item), currentQuery)
467
+ })).filter(({ score }) => score > minScore).sort((a, b) => b.score - a.score);
468
+ return scored.map(({ item }) => item);
469
+ } else {
470
+ return items.filter((item) => filterFn(item, currentQuery));
471
+ }
472
+ }, [
473
+ items,
474
+ query,
475
+ filterFn,
476
+ fuzzy,
477
+ extractFn,
478
+ minScore
479
+ ]);
480
+ return {
481
+ results,
482
+ handleSearch
483
+ };
484
+ };
485
+
486
+ // src/components/Combobox/Combobox.tsx
487
+ var COMBOBOX_NAME = "Combobox";
488
+ var COMBOBOX_CONTENT_NAME = "ComboboxContent";
489
+ var COMBOBOX_ITEM_NAME = "ComboboxItem";
490
+ var COMBOBOX_TRIGGER_NAME = "ComboboxTrigger";
491
+ var [ComboboxProvider, useComboboxContext] = createContext3(COMBOBOX_NAME, {});
492
+ var ComboboxRoot = ({ modal, modalId: propsModalId, open: propsOpen, defaultOpen, onOpenChange: propsOnOpenChange, value: propsValue, defaultValue, onValueChange: propsOnValueChange, placeholder, children }) => {
493
+ const modalId = useId(COMBOBOX_NAME, propsModalId);
494
+ const [open = false, onOpenChange] = useControllableState2({
495
+ prop: propsOpen,
496
+ onChange: propsOnOpenChange,
497
+ defaultProp: defaultOpen
498
+ });
499
+ const [value = "", onValueChange] = useControllableState2({
500
+ prop: propsValue,
501
+ onChange: propsOnValueChange,
502
+ defaultProp: defaultValue
503
+ });
504
+ return /* @__PURE__ */ React3.createElement(Popover.Root, {
505
+ open,
506
+ onOpenChange,
507
+ modal
508
+ }, /* @__PURE__ */ React3.createElement(ComboboxProvider, {
509
+ isCombobox: true,
510
+ modalId,
511
+ placeholder,
512
+ open,
513
+ onOpenChange,
514
+ value,
515
+ onValueChange
516
+ }, children));
517
+ };
518
+ var ComboboxContent = /* @__PURE__ */ forwardRef2(({ side = "bottom", collisionPadding = 48, sideOffset, align, alignOffset, avoidCollisions, collisionBoundary, arrowPadding, sticky, hideWhenDetached, onOpenAutoFocus, onCloseAutoFocus, onEscapeKeyDown, onPointerDownOutside, onFocusOutside, onInteractOutside, forceMount, children, classNames, onSearch, value, defaultValue, debounceMs, label }, forwardedRef) => {
519
+ const { modalId } = useComboboxContext(COMBOBOX_CONTENT_NAME);
520
+ return /* @__PURE__ */ React3.createElement(Popover.Content, {
521
+ side,
522
+ sideOffset,
523
+ align,
524
+ alignOffset,
525
+ avoidCollisions,
526
+ collisionBoundary,
527
+ collisionPadding,
528
+ arrowPadding,
529
+ sticky,
530
+ hideWhenDetached,
531
+ onOpenAutoFocus,
532
+ onCloseAutoFocus,
533
+ onEscapeKeyDown,
534
+ onPointerDownOutside,
535
+ onFocusOutside,
536
+ onInteractOutside,
537
+ forceMount,
538
+ classNames: [
539
+ "w-(--radix-popover-trigger-width) max-h-(--radix-popover-content-available-height) grid grid-rows-[min-content_1fr]",
540
+ classNames
541
+ ],
542
+ id: modalId,
543
+ ref: forwardedRef
544
+ }, /* @__PURE__ */ React3.createElement(SearchList.Root, {
545
+ onSearch,
546
+ value,
547
+ defaultValue,
548
+ debounceMs
549
+ }, /* @__PURE__ */ React3.createElement(SearchList.Content, null, children)));
550
+ });
551
+ ComboboxContent.displayName = COMBOBOX_CONTENT_NAME;
552
+ var ComboboxTrigger = /* @__PURE__ */ forwardRef2(({ children, onClick, ...props }, forwardedRef) => {
553
+ const { modalId, open, onOpenChange, placeholder, value } = useComboboxContext(COMBOBOX_TRIGGER_NAME);
554
+ const handleClick = useCallback3((event) => {
555
+ onClick?.(event);
556
+ onOpenChange?.(true);
557
+ }, [
558
+ onClick,
559
+ onOpenChange
560
+ ]);
561
+ return /* @__PURE__ */ React3.createElement(Popover.Trigger, {
562
+ asChild: true
563
+ }, /* @__PURE__ */ React3.createElement(Button, {
564
+ ...props,
565
+ role: "combobox",
566
+ "aria-expanded": open,
567
+ "aria-controls": modalId,
568
+ "aria-haspopup": "dialog",
569
+ onClick: handleClick,
570
+ ref: forwardedRef
571
+ }, children ?? /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("span", {
572
+ className: mx2("font-normal text-start flex-1 min-w-0 truncate me-2", !value && "text-subdued")
573
+ }, value || placeholder), /* @__PURE__ */ React3.createElement(Icon2, {
574
+ icon: "ph--caret-down--bold",
575
+ size: 3
576
+ }))));
577
+ });
578
+ ComboboxTrigger.displayName = COMBOBOX_TRIGGER_NAME;
579
+ var ComboboxVirtualTrigger = Popover.VirtualTrigger;
580
+ var ComboboxInput = /* @__PURE__ */ forwardRef2(({ classNames, ...props }, forwardedRef) => {
581
+ return /* @__PURE__ */ React3.createElement(SearchList.Input, {
582
+ ...props,
583
+ classNames: [
584
+ "m-form-chrome mb-0 w-[calc(100%-2*var(--spacing-form-chrome))]",
585
+ classNames
586
+ ],
587
+ ref: forwardedRef
588
+ });
589
+ });
590
+ var ComboboxList = /* @__PURE__ */ forwardRef2(({ classNames, ...props }, forwardedRef) => {
591
+ return /* @__PURE__ */ React3.createElement(SearchList.Viewport, {
592
+ ...props,
593
+ classNames: [
594
+ "py-form-chrome",
595
+ classNames
596
+ ],
597
+ ref: forwardedRef
598
+ });
599
+ });
600
+ var ComboboxItem = /* @__PURE__ */ forwardRef2(({ classNames, onSelect, value, closeOnSelect = true, ...props }, forwardedRef) => {
601
+ const { onValueChange, onOpenChange } = useComboboxContext(COMBOBOX_ITEM_NAME);
602
+ const handleSelect = useCallback3(() => {
603
+ onSelect?.();
604
+ if (value !== void 0) {
605
+ onValueChange?.(value);
606
+ }
607
+ if (closeOnSelect) {
608
+ onOpenChange?.(false);
609
+ }
610
+ }, [
611
+ onSelect,
612
+ onValueChange,
613
+ onOpenChange,
614
+ value,
615
+ closeOnSelect
616
+ ]);
617
+ return /* @__PURE__ */ React3.createElement(SearchList.Item, {
618
+ ...props,
619
+ value,
620
+ classNames: [
621
+ "mx-form-chrome px-form-chrome",
622
+ classNames
623
+ ],
624
+ onSelect: handleSelect,
625
+ ref: forwardedRef
626
+ });
627
+ });
628
+ ComboboxItem.displayName = COMBOBOX_ITEM_NAME;
629
+ var ComboboxArrow = Popover.Arrow;
630
+ var ComboboxEmpty = SearchList.Empty;
631
+ var ComboboxPortal = Popover.Portal;
166
632
  var Combobox = {
167
633
  Root: ComboboxRoot,
634
+ Portal: ComboboxPortal,
635
+ Content: ComboboxContent,
168
636
  Trigger: ComboboxTrigger,
169
- useComboboxContext
637
+ VirtualTrigger: ComboboxVirtualTrigger,
638
+ Input: ComboboxInput,
639
+ List: ComboboxList,
640
+ Item: ComboboxItem,
641
+ Arrow: ComboboxArrow,
642
+ Empty: ComboboxEmpty
170
643
  };
171
644
 
172
- // src/components/Listbox.tsx
173
- import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
645
+ // src/components/Listbox/Listbox.tsx
174
646
  import { useArrowNavigationGroup } from "@fluentui/react-tabster";
175
647
  import { useComposedRefs } from "@radix-ui/react-compose-refs";
176
648
  import { createContextScope } from "@radix-ui/react-context";
177
- import { useControllableState as useControllableState2 } from "@radix-ui/react-use-controllable-state";
178
- import React2, { forwardRef as forwardRef2, useCallback as useCallback2, useEffect, useRef } from "react";
179
- import { Icon as Icon2 } from "@dxos/react-ui";
180
- import { mx as mx2 } from "@dxos/react-ui-theme";
649
+ import { useControllableState as useControllableState3 } from "@radix-ui/react-use-controllable-state";
650
+ import React4, { forwardRef as forwardRef3, useCallback as useCallback4, useEffect as useEffect3, useRef as useRef3 } from "react";
651
+ import { Icon as Icon3 } from "@dxos/react-ui";
652
+ import { mx as mx3 } from "@dxos/ui-theme";
653
+ var commandItem = "flex items-center overflow-hidden";
181
654
  var LISTBOX_NAME = "Listbox";
182
655
  var LISTBOX_OPTION_NAME = "ListboxOption";
183
656
  var LISTBOX_OPTION_LABEL_NAME = "ListboxOptionLabel";
@@ -188,109 +661,89 @@ var [createListboxOptionContext, createListboxOptionScope] = createContextScope(
188
661
  ]);
189
662
  var [ListboxProvider, useListboxContext] = createListboxContext(LISTBOX_NAME);
190
663
  var [ListboxOptionProvider, useListboxOptionContext] = createListboxOptionContext(LISTBOX_OPTION_NAME);
191
- var ListboxRoot = /* @__PURE__ */ forwardRef2((props, forwardedRef) => {
192
- var _effect = _useSignals2();
193
- try {
194
- const { __listboxScope, children, classNames, value: propsValue, defaultValue, onValueChange, autoFocus, ...rootProps } = props;
195
- const arrowGroup = useArrowNavigationGroup({
196
- axis: "vertical"
197
- });
198
- const ref = useRef(null);
199
- const rootRef = useComposedRefs(ref, forwardedRef);
200
- const [selectedValue, setSelectedValue] = useControllableState2({
201
- prop: propsValue,
202
- defaultProp: defaultValue,
203
- onChange: onValueChange
204
- });
205
- const handleValueChange = (value) => {
206
- setSelectedValue(value);
207
- };
208
- useEffect(() => {
209
- ref.current?.querySelector('[aria-selected="true"]')?.focus();
210
- }, [
211
- autoFocus
212
- ]);
213
- return /* @__PURE__ */ React2.createElement(ListboxProvider, {
214
- scope: __listboxScope,
215
- selectedValue,
216
- onValueChange: handleValueChange
217
- }, /* @__PURE__ */ React2.createElement("ul", {
218
- role: "listbox",
219
- ...rootProps,
220
- className: mx2("p-cardSpacingChrome", classNames),
221
- ref: rootRef,
222
- ...arrowGroup
223
- }, children));
224
- } finally {
225
- _effect.f();
226
- }
664
+ var ListboxRoot = /* @__PURE__ */ forwardRef3((props, forwardedRef) => {
665
+ const { __listboxScope, children, classNames, value: propsValue, defaultValue, onValueChange, autoFocus, ...rootProps } = props;
666
+ const arrowGroup = useArrowNavigationGroup({
667
+ axis: "vertical"
668
+ });
669
+ const ref = useRef3(null);
670
+ const rootRef = useComposedRefs(ref, forwardedRef);
671
+ const [selectedValue, setSelectedValue] = useControllableState3({
672
+ prop: propsValue,
673
+ defaultProp: defaultValue,
674
+ onChange: onValueChange
675
+ });
676
+ const handleValueChange = (value) => {
677
+ setSelectedValue(value);
678
+ };
679
+ useEffect3(() => {
680
+ ref.current?.querySelector('[aria-selected="true"]')?.focus();
681
+ }, [
682
+ autoFocus
683
+ ]);
684
+ return /* @__PURE__ */ React4.createElement(ListboxProvider, {
685
+ scope: __listboxScope,
686
+ selectedValue,
687
+ onValueChange: handleValueChange
688
+ }, /* @__PURE__ */ React4.createElement("ul", {
689
+ role: "listbox",
690
+ ...rootProps,
691
+ className: mx3("w-full p-form-chrome", classNames),
692
+ ref: rootRef,
693
+ ...arrowGroup
694
+ }, children));
227
695
  });
228
696
  ListboxRoot.displayName = LISTBOX_NAME;
229
- var ListboxOption = /* @__PURE__ */ forwardRef2((props, forwardedRef) => {
230
- var _effect = _useSignals2();
231
- try {
232
- const { __listboxScope, children, classNames, value, ...rootProps } = props;
233
- const { selectedValue, onValueChange } = useListboxContext(LISTBOX_OPTION_NAME, __listboxScope);
234
- const isSelected = selectedValue === value;
235
- const handleSelect = useCallback2(() => {
236
- onValueChange(value);
237
- }, [
238
- value,
239
- onValueChange
240
- ]);
241
- return /* @__PURE__ */ React2.createElement(ListboxOptionProvider, {
242
- scope: __listboxScope,
243
- value,
244
- isSelected
245
- }, /* @__PURE__ */ React2.createElement("li", {
246
- role: "option",
247
- ...rootProps,
248
- "aria-selected": isSelected,
249
- tabIndex: 0,
250
- className: mx2("dx-focus-ring", commandItem, searchListItem, classNames),
251
- onClick: handleSelect,
252
- onKeyDown: ({ key }) => {
253
- if ([
254
- "Enter",
255
- " "
256
- ].includes(key)) {
257
- handleSelect();
258
- }
259
- },
260
- ref: forwardedRef
261
- }, children));
262
- } finally {
263
- _effect.f();
264
- }
697
+ var ListboxOption = /* @__PURE__ */ forwardRef3((props, forwardedRef) => {
698
+ const { __listboxScope, children, classNames, value, ...rootProps } = props;
699
+ const { selectedValue, onValueChange } = useListboxContext(LISTBOX_OPTION_NAME, __listboxScope);
700
+ const isSelected = selectedValue === value;
701
+ const handleSelect = useCallback4(() => {
702
+ onValueChange(value);
703
+ }, [
704
+ value,
705
+ onValueChange
706
+ ]);
707
+ return /* @__PURE__ */ React4.createElement(ListboxOptionProvider, {
708
+ scope: __listboxScope,
709
+ value,
710
+ isSelected
711
+ }, /* @__PURE__ */ React4.createElement("li", {
712
+ role: "option",
713
+ ...rootProps,
714
+ "aria-selected": isSelected,
715
+ tabIndex: 0,
716
+ className: mx3("dx-focus-ring", "py-1 px-2 rounded-xs select-none cursor-pointer data-[selected=true]:bg-hover-overlay hover:bg-hover-overlay", commandItem, classNames),
717
+ onClick: handleSelect,
718
+ onKeyDown: ({ key }) => {
719
+ if ([
720
+ "Enter",
721
+ " "
722
+ ].includes(key)) {
723
+ handleSelect();
724
+ }
725
+ },
726
+ ref: forwardedRef
727
+ }, children));
265
728
  });
266
729
  ListboxOption.displayName = LISTBOX_OPTION_NAME;
267
- var ListboxOptionLabel = /* @__PURE__ */ forwardRef2(({ children, classNames, ...rootProps }, forwardedRef) => {
268
- var _effect = _useSignals2();
269
- try {
270
- return /* @__PURE__ */ React2.createElement("span", {
271
- ...rootProps,
272
- className: mx2("grow truncate", classNames),
273
- ref: forwardedRef
274
- }, children);
275
- } finally {
276
- _effect.f();
277
- }
730
+ var ListboxOptionLabel = /* @__PURE__ */ forwardRef3(({ children, classNames, ...rootProps }, forwardedRef) => {
731
+ return /* @__PURE__ */ React4.createElement("span", {
732
+ ...rootProps,
733
+ className: mx3("grow truncate", classNames),
734
+ ref: forwardedRef
735
+ }, children);
278
736
  });
279
737
  ListboxOptionLabel.displayName = LISTBOX_OPTION_LABEL_NAME;
280
- var ListboxOptionIndicator = /* @__PURE__ */ forwardRef2((props, forwardedRef) => {
281
- var _effect = _useSignals2();
282
- try {
283
- const { __listboxOptionScope, classNames, ...rootProps } = props;
284
- const { isSelected } = useListboxOptionContext(LISTBOX_OPTION_INDICATOR_NAME, __listboxOptionScope);
285
- return /* @__PURE__ */ React2.createElement(Icon2, {
286
- icon: "ph--check--regular",
287
- ...rootProps,
288
- classNames: mx2(!isSelected && "invisible", classNames),
289
- ref: forwardedRef
290
- });
291
- } finally {
292
- _effect.f();
293
- }
738
+ var ListboxOptionIndicator = /* @__PURE__ */ forwardRef3((props, forwardedRef) => {
739
+ const { __listboxOptionScope, classNames, ...rootProps } = props;
740
+ const { isSelected } = useListboxOptionContext(LISTBOX_OPTION_INDICATOR_NAME, __listboxOptionScope);
741
+ return /* @__PURE__ */ React4.createElement(Icon3, {
742
+ icon: "ph--check--regular",
743
+ ...rootProps,
744
+ classNames: mx3(!isSelected && "invisible", classNames),
745
+ ref: forwardedRef
746
+ });
294
747
  });
295
748
  ListboxOptionIndicator.displayName = LISTBOX_OPTION_INDICATOR_NAME;
296
749
  var Listbox = {
@@ -299,164 +752,19 @@ var Listbox = {
299
752
  OptionLabel: ListboxOptionLabel,
300
753
  OptionIndicator: ListboxOptionIndicator
301
754
  };
302
-
303
- // src/composites/PopoverCombobox.tsx
304
- import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
305
- import { useControllableState as useControllableState3 } from "@radix-ui/react-use-controllable-state";
306
- import React3, { forwardRef as forwardRef3 } from "react";
307
- import { Popover } from "@dxos/react-ui";
308
- var PopoverComboboxRoot = ({ modal, children, open: propsOpen, onOpenChange: propsOnOpenChange, defaultOpen, ...props }) => {
309
- var _effect = _useSignals3();
310
- try {
311
- const [open, onOpenChange] = useControllableState3({
312
- prop: propsOpen,
313
- onChange: propsOnOpenChange,
314
- defaultProp: defaultOpen
315
- });
316
- return /* @__PURE__ */ React3.createElement(Combobox.Root, {
317
- open,
318
- onOpenChange,
319
- ...props
320
- }, /* @__PURE__ */ React3.createElement(Popover.Root, {
321
- open,
322
- onOpenChange,
323
- modal
324
- }, children));
325
- } finally {
326
- _effect.f();
327
- }
328
- };
329
- var POPOVER_COMBOBOX_CONTENT_NAME = "PopoverComboboxContent";
330
- var PopoverComboboxContent = /* @__PURE__ */ forwardRef3(({ side = "bottom", collisionPadding = 48, sideOffset, align, alignOffset, avoidCollisions, collisionBoundary, arrowPadding, sticky, hideWhenDetached, onOpenAutoFocus, onCloseAutoFocus, onEscapeKeyDown, onPointerDownOutside, onFocusOutside, onInteractOutside, forceMount, children, classNames, ...props }, forwardedRef) => {
331
- var _effect = _useSignals3();
332
- try {
333
- const { modalId } = Combobox.useComboboxContext(POPOVER_COMBOBOX_CONTENT_NAME);
334
- return /* @__PURE__ */ React3.createElement(Popover.Content, {
335
- side,
336
- sideOffset,
337
- align,
338
- alignOffset,
339
- avoidCollisions,
340
- collisionBoundary,
341
- collisionPadding,
342
- arrowPadding,
343
- sticky,
344
- hideWhenDetached,
345
- onOpenAutoFocus,
346
- onCloseAutoFocus,
347
- onEscapeKeyDown,
348
- onPointerDownOutside,
349
- onFocusOutside,
350
- onInteractOutside,
351
- forceMount,
352
- classNames: [
353
- "is-[--radix-popover-trigger-width] max-bs-[--radix-popover-content-available-height] grid grid-rows-[min-content_1fr]",
354
- classNames
355
- ],
356
- id: modalId,
357
- ref: forwardedRef
358
- }, /* @__PURE__ */ React3.createElement(SearchList.Root, {
359
- ...props,
360
- classNames: "contents density-fine",
361
- role: "none"
362
- }, children));
363
- } finally {
364
- _effect.f();
365
- }
366
- });
367
- PopoverComboboxContent.displayName = POPOVER_COMBOBOX_CONTENT_NAME;
368
- var PopoverComboboxTrigger = /* @__PURE__ */ forwardRef3((props, forwardedRef) => {
369
- var _effect = _useSignals3();
370
- try {
371
- return /* @__PURE__ */ React3.createElement(Popover.Trigger, {
372
- asChild: true
373
- }, /* @__PURE__ */ React3.createElement(Combobox.Trigger, {
374
- ...props,
375
- ref: forwardedRef
376
- }));
377
- } finally {
378
- _effect.f();
379
- }
380
- });
381
- var PopoverComboboxVirtualTrigger = Popover.VirtualTrigger;
382
- var PopoverComboboxInput = /* @__PURE__ */ forwardRef3(({ classNames, ...props }, forwardedRef) => {
383
- var _effect = _useSignals3();
384
- try {
385
- return /* @__PURE__ */ React3.createElement(SearchList.Input, {
386
- ...props,
387
- classNames: [
388
- "mli-cardSpacingChrome mbs-cardSpacingChrome mbe-0 is-[calc(100%-2*var(--dx-cardSpacingChrome))]",
389
- classNames
390
- ],
391
- ref: forwardedRef
392
- });
393
- } finally {
394
- _effect.f();
395
- }
396
- });
397
- var PopoverComboboxList = /* @__PURE__ */ forwardRef3(({ classNames, ...props }, forwardedRef) => {
398
- var _effect = _useSignals3();
399
- try {
400
- return /* @__PURE__ */ React3.createElement(SearchList.Content, {
401
- ...props,
402
- classNames: [
403
- "min-bs-0 overflow-y-auto plb-cardSpacingChrome",
404
- classNames
405
- ],
406
- ref: forwardedRef
407
- });
408
- } finally {
409
- _effect.f();
410
- }
411
- });
412
- var PopoverComboboxItem = /* @__PURE__ */ forwardRef3(({ classNames, ...props }, forwardedRef) => {
413
- var _effect = _useSignals3();
414
- try {
415
- return /* @__PURE__ */ React3.createElement(SearchList.Item, {
416
- ...props,
417
- classNames: [
418
- "mli-cardSpacingChrome pli-cardSpacingChrome",
419
- classNames
420
- ],
421
- ref: forwardedRef
422
- });
423
- } finally {
424
- _effect.f();
425
- }
426
- });
427
- var PopoverComboboxArrow = Popover.Arrow;
428
- var PopoverComboboxEmpty = SearchList.Empty;
429
- var PopoverCombobox = {
430
- Root: PopoverComboboxRoot,
431
- Content: PopoverComboboxContent,
432
- Trigger: PopoverComboboxTrigger,
433
- VirtualTrigger: PopoverComboboxVirtualTrigger,
434
- Input: PopoverComboboxInput,
435
- List: PopoverComboboxList,
436
- Item: PopoverComboboxItem,
437
- Arrow: PopoverComboboxArrow,
438
- Empty: PopoverComboboxEmpty
439
- };
440
-
441
- // src/translations.ts
442
- var translationKey = "react-ui-searchlist";
443
- var translations = [
444
- {
445
- "en-US": {
446
- [translationKey]: {}
447
- }
448
- }
449
- ];
450
755
  export {
451
756
  Combobox,
757
+ GlobalFilterProvider,
452
758
  Listbox,
453
- PopoverCombobox,
454
759
  SearchList,
455
- commandItem,
456
760
  createListboxScope,
457
- searchListItem,
458
761
  translationKey,
459
762
  translations,
460
- useListboxContext
763
+ useGlobalFilter,
764
+ useGlobalFilteredObjects,
765
+ useListboxContext,
766
+ useSearchListInput,
767
+ useSearchListItem,
768
+ useSearchListResults
461
769
  };
462
770
  //# sourceMappingURL=index.mjs.map