@dxos/react-ui-list 0.8.4-main.40e3dcdf1b → 0.8.4-main.43cb759274

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 (93) hide show
  1. package/LICENSE +102 -5
  2. package/dist/lib/browser/index.mjs +805 -128
  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 +805 -128
  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/Accordion/Accordion.d.ts +1 -1
  9. package/dist/types/src/components/Accordion/Accordion.d.ts.map +1 -1
  10. package/dist/types/src/components/Accordion/Accordion.stories.d.ts.map +1 -1
  11. package/dist/types/src/components/Accordion/AccordionItem.d.ts.map +1 -1
  12. package/dist/types/src/components/Accordion/AccordionRoot.d.ts +1 -1
  13. package/dist/types/src/components/Accordion/AccordionRoot.d.ts.map +1 -1
  14. package/dist/types/src/components/Combobox/Combobox.d.ts +105 -0
  15. package/dist/types/src/components/Combobox/Combobox.d.ts.map +1 -0
  16. package/dist/types/src/components/Combobox/Combobox.stories.d.ts +12 -0
  17. package/dist/types/src/components/Combobox/Combobox.stories.d.ts.map +1 -0
  18. package/dist/types/src/components/Combobox/index.d.ts +2 -0
  19. package/dist/types/src/components/Combobox/index.d.ts.map +1 -0
  20. package/dist/types/src/components/List/List.d.ts +15 -4
  21. package/dist/types/src/components/List/List.d.ts.map +1 -1
  22. package/dist/types/src/components/List/List.stories.d.ts +2 -2
  23. package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
  24. package/dist/types/src/components/List/ListItem.d.ts +7 -7
  25. package/dist/types/src/components/List/ListItem.d.ts.map +1 -1
  26. package/dist/types/src/components/List/ListRoot.d.ts.map +1 -1
  27. package/dist/types/src/components/List/testing.d.ts +2 -2
  28. package/dist/types/src/components/List/testing.d.ts.map +1 -1
  29. package/dist/types/src/components/Listbox/Listbox.d.ts +27 -0
  30. package/dist/types/src/components/Listbox/Listbox.d.ts.map +1 -0
  31. package/dist/types/src/components/Listbox/Listbox.stories.d.ts +12 -0
  32. package/dist/types/src/components/Listbox/Listbox.stories.d.ts.map +1 -0
  33. package/dist/types/src/components/Listbox/index.d.ts +2 -0
  34. package/dist/types/src/components/Listbox/index.d.ts.map +1 -0
  35. package/dist/types/src/components/Picker/Picker.d.ts +49 -0
  36. package/dist/types/src/components/Picker/Picker.d.ts.map +1 -0
  37. package/dist/types/src/components/Picker/Picker.stories.d.ts +28 -0
  38. package/dist/types/src/components/Picker/Picker.stories.d.ts.map +1 -0
  39. package/dist/types/src/components/Picker/context.d.ts +29 -0
  40. package/dist/types/src/components/Picker/context.d.ts.map +1 -0
  41. package/dist/types/src/components/Picker/index.d.ts +3 -0
  42. package/dist/types/src/components/Picker/index.d.ts.map +1 -0
  43. package/dist/types/src/components/RowList/RowList.d.ts +61 -0
  44. package/dist/types/src/components/RowList/RowList.d.ts.map +1 -0
  45. package/dist/types/src/components/RowList/RowList.stories.d.ts +35 -0
  46. package/dist/types/src/components/RowList/RowList.stories.d.ts.map +1 -0
  47. package/dist/types/src/components/RowList/index.d.ts +3 -0
  48. package/dist/types/src/components/RowList/index.d.ts.map +1 -0
  49. package/dist/types/src/components/Tree/Tree.d.ts +1 -1
  50. package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
  51. package/dist/types/src/components/Tree/Tree.stories.d.ts +1 -1
  52. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
  53. package/dist/types/src/components/Tree/TreeContext.d.ts +4 -0
  54. package/dist/types/src/components/Tree/TreeContext.d.ts.map +1 -1
  55. package/dist/types/src/components/Tree/TreeItem.d.ts.map +1 -1
  56. package/dist/types/src/components/Tree/TreeItemHeading.d.ts +4 -0
  57. package/dist/types/src/components/Tree/TreeItemHeading.d.ts.map +1 -1
  58. package/dist/types/src/components/Tree/helpers.d.ts.map +1 -1
  59. package/dist/types/src/components/Tree/testing.d.ts +1 -1
  60. package/dist/types/src/components/Tree/testing.d.ts.map +1 -1
  61. package/dist/types/src/components/index.d.ts +4 -0
  62. package/dist/types/src/components/index.d.ts.map +1 -1
  63. package/dist/types/src/util/path.d.ts.map +1 -1
  64. package/dist/types/tsconfig.tsbuildinfo +1 -1
  65. package/package.json +21 -21
  66. package/src/components/Accordion/Accordion.stories.tsx +3 -3
  67. package/src/components/Accordion/AccordionItem.tsx +1 -4
  68. package/src/components/Combobox/Combobox.stories.tsx +60 -0
  69. package/src/components/Combobox/Combobox.tsx +388 -0
  70. package/src/components/Combobox/index.ts +5 -0
  71. package/src/components/List/List.stories.tsx +5 -5
  72. package/src/components/List/List.tsx +12 -8
  73. package/src/components/List/ListItem.tsx +28 -28
  74. package/src/components/List/ListRoot.tsx +1 -1
  75. package/src/components/List/testing.ts +4 -4
  76. package/src/components/Listbox/Listbox.stories.tsx +48 -0
  77. package/src/components/Listbox/Listbox.tsx +201 -0
  78. package/src/components/Listbox/index.ts +5 -0
  79. package/src/components/Picker/Picker.stories.tsx +131 -0
  80. package/src/components/Picker/Picker.tsx +368 -0
  81. package/src/components/Picker/context.ts +43 -0
  82. package/src/components/Picker/index.ts +6 -0
  83. package/src/components/RowList/RowList.stories.tsx +163 -0
  84. package/src/components/RowList/RowList.tsx +350 -0
  85. package/src/components/RowList/index.ts +6 -0
  86. package/src/components/Tree/Tree.stories.tsx +7 -5
  87. package/src/components/Tree/Tree.tsx +2 -2
  88. package/src/components/Tree/TreeContext.tsx +4 -0
  89. package/src/components/Tree/TreeItem.tsx +18 -10
  90. package/src/components/Tree/TreeItemHeading.tsx +34 -8
  91. package/src/components/Tree/TreeItemToggle.tsx +4 -4
  92. package/src/components/Tree/testing.ts +5 -5
  93. package/src/components/index.ts +4 -0
@@ -57,7 +57,6 @@ var AccordionItemBody = ({ children, classNames }) => {
57
57
  return /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Content, {
58
58
  className: "overflow-hidden data-[state=closed]:animate-slide-up data-[state=open]:animate-slide-down"
59
59
  }, /* @__PURE__ */ React2.createElement("div", {
60
- role: "none",
61
60
  className: mx2("p-2", classNames)
62
61
  }, children));
63
62
  };
@@ -70,30 +69,467 @@ var Accordion = {
70
69
  ItemBody: AccordionItemBody
71
70
  };
72
71
 
72
+ // src/components/Combobox/Combobox.tsx
73
+ import { createContext as createContext4 } from "@radix-ui/react-context";
74
+ import { useControllableState } from "@radix-ui/react-use-controllable-state";
75
+ import React4, { forwardRef as forwardRef2, useCallback as useCallback2 } from "react";
76
+ import { Button, Icon as Icon2, Popover, ScrollArea, useId } from "@dxos/react-ui";
77
+ import { composable, composableProps } from "@dxos/react-ui";
78
+ import { mx as mx4 } from "@dxos/ui-theme";
79
+
80
+ // src/components/Picker/Picker.tsx
81
+ import { Slot } from "@radix-ui/react-slot";
82
+ import React3, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
83
+ import { Input, useThemeContext } from "@dxos/react-ui";
84
+ import { mx as mx3 } from "@dxos/ui-theme";
85
+
86
+ // src/components/Picker/context.ts
87
+ import { createContext as createContext3 } from "@radix-ui/react-context";
88
+ var [PickerItemContextProvider, usePickerItemContext] = createContext3("PickerItem");
89
+ var [PickerInputContextProvider, usePickerInputContext] = createContext3("PickerInput");
90
+
91
+ // src/components/Picker/Picker.tsx
92
+ var PickerRoot = ({ children }) => {
93
+ const [selectedValue, setSelectedValue] = useState(void 0);
94
+ const itemsRef = useRef(/* @__PURE__ */ new Map());
95
+ const [itemVersion, setItemVersion] = useState(0);
96
+ useEffect(() => {
97
+ const current = selectedValue !== void 0 ? itemsRef.current.get(selectedValue) : void 0;
98
+ const isValid = current !== void 0 && !current.disabled;
99
+ if (!isValid && itemsRef.current.size > 0) {
100
+ const entries = Array.from(itemsRef.current.entries()).filter(([, data]) => !data.disabled);
101
+ if (entries.length > 0) {
102
+ entries.sort(([, a], [, b]) => {
103
+ const position = a.element.compareDocumentPosition(b.element);
104
+ if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
105
+ return -1;
106
+ }
107
+ if (position & Node.DOCUMENT_POSITION_PRECEDING) {
108
+ return 1;
109
+ }
110
+ return 0;
111
+ });
112
+ const firstValue = entries[0]?.[0];
113
+ if (firstValue !== void 0 && firstValue !== selectedValue) {
114
+ setSelectedValue(firstValue);
115
+ }
116
+ } else if (selectedValue !== void 0) {
117
+ setSelectedValue(void 0);
118
+ }
119
+ }
120
+ }, [
121
+ itemVersion,
122
+ selectedValue
123
+ ]);
124
+ const registerItem = useCallback((value, element, onSelect, disabled) => {
125
+ if (element) {
126
+ itemsRef.current.set(value, {
127
+ element,
128
+ onSelect,
129
+ disabled
130
+ });
131
+ setItemVersion((v) => v + 1);
132
+ }
133
+ }, []);
134
+ const unregisterItem = useCallback((value) => {
135
+ itemsRef.current.delete(value);
136
+ setItemVersion((v) => v + 1);
137
+ }, []);
138
+ const getItemValues = useCallback(() => {
139
+ return Array.from(itemsRef.current.entries()).filter(([, data]) => !data.disabled).sort(([, a], [, b]) => {
140
+ const position = a.element.compareDocumentPosition(b.element);
141
+ return position & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : position & Node.DOCUMENT_POSITION_PRECEDING ? 1 : 0;
142
+ }).map(([value]) => value);
143
+ }, []);
144
+ const triggerSelect = useCallback(() => {
145
+ if (selectedValue !== void 0) {
146
+ const item = itemsRef.current.get(selectedValue);
147
+ item?.onSelect?.();
148
+ }
149
+ }, [
150
+ selectedValue
151
+ ]);
152
+ const itemContextValue = useMemo(() => ({
153
+ selectedValue,
154
+ onSelectedValueChange: setSelectedValue,
155
+ registerItem,
156
+ unregisterItem
157
+ }), [
158
+ selectedValue,
159
+ registerItem,
160
+ unregisterItem
161
+ ]);
162
+ const inputContextValue = useMemo(() => ({
163
+ selectedValue,
164
+ onSelectedValueChange: setSelectedValue,
165
+ getItemValues,
166
+ triggerSelect
167
+ }), [
168
+ selectedValue,
169
+ getItemValues,
170
+ triggerSelect
171
+ ]);
172
+ return /* @__PURE__ */ React3.createElement(PickerInputContextProvider, inputContextValue, /* @__PURE__ */ React3.createElement(PickerItemContextProvider, itemContextValue, children));
173
+ };
174
+ PickerRoot.displayName = "Picker.Root";
175
+ var PickerInput = /* @__PURE__ */ forwardRef(({ value, onValueChange, onChange, onKeyDown, autoFocus, ...props }, forwardedRef) => {
176
+ const { hasIosKeyboard } = useThemeContext();
177
+ const { selectedValue, onSelectedValueChange, getItemValues, triggerSelect } = usePickerInputContext("Picker.Input");
178
+ const handleChange = useCallback((event) => {
179
+ onValueChange?.(event.target.value);
180
+ onChange?.(event);
181
+ }, [
182
+ onValueChange,
183
+ onChange
184
+ ]);
185
+ const handleKeyDown = useCallback((event) => {
186
+ onKeyDown?.(event);
187
+ if (event.defaultPrevented) {
188
+ return;
189
+ }
190
+ const values = getItemValues();
191
+ if (values.length === 0) {
192
+ if (event.key === "Escape") {
193
+ onValueChange?.("");
194
+ }
195
+ return;
196
+ }
197
+ const currentIndex = selectedValue !== void 0 ? values.indexOf(selectedValue) : -1;
198
+ switch (event.key) {
199
+ case "ArrowDown": {
200
+ event.preventDefault();
201
+ const nextIndex = currentIndex === -1 ? 0 : Math.min(currentIndex + 1, values.length - 1);
202
+ const nextValue = values[nextIndex];
203
+ if (nextValue !== void 0) {
204
+ onSelectedValueChange(nextValue);
205
+ }
206
+ break;
207
+ }
208
+ case "ArrowUp": {
209
+ event.preventDefault();
210
+ const prevIndex = currentIndex === -1 ? values.length - 1 : Math.max(currentIndex - 1, 0);
211
+ const prevValue = values[prevIndex];
212
+ if (prevValue !== void 0) {
213
+ onSelectedValueChange(prevValue);
214
+ }
215
+ break;
216
+ }
217
+ case "Enter": {
218
+ if (selectedValue !== void 0) {
219
+ event.preventDefault();
220
+ triggerSelect();
221
+ }
222
+ break;
223
+ }
224
+ case "Home": {
225
+ event.preventDefault();
226
+ const firstValue = values[0];
227
+ if (firstValue !== void 0) {
228
+ onSelectedValueChange(firstValue);
229
+ }
230
+ break;
231
+ }
232
+ case "End": {
233
+ event.preventDefault();
234
+ const lastValue = values[values.length - 1];
235
+ if (lastValue !== void 0) {
236
+ onSelectedValueChange(lastValue);
237
+ }
238
+ break;
239
+ }
240
+ case "Escape": {
241
+ event.preventDefault();
242
+ if (selectedValue !== void 0) {
243
+ onSelectedValueChange(void 0);
244
+ } else {
245
+ onValueChange?.("");
246
+ }
247
+ break;
248
+ }
249
+ }
250
+ }, [
251
+ selectedValue,
252
+ onSelectedValueChange,
253
+ getItemValues,
254
+ triggerSelect,
255
+ onValueChange,
256
+ onKeyDown
257
+ ]);
258
+ return /* @__PURE__ */ React3.createElement(Input.Root, null, /* @__PURE__ */ React3.createElement(Input.TextInput, {
259
+ ...props,
260
+ autoFocus: autoFocus && !hasIosKeyboard,
261
+ ...value !== void 0 && {
262
+ value
263
+ },
264
+ onChange: handleChange,
265
+ onKeyDown: handleKeyDown,
266
+ ref: forwardedRef
267
+ }));
268
+ });
269
+ PickerInput.displayName = "Picker.Input";
270
+ var PickerItem = /* @__PURE__ */ forwardRef(({ classNames, value, onSelect, disabled, asChild, children, ...props }, forwardedRef) => {
271
+ const { selectedValue, onSelectedValueChange, registerItem, unregisterItem } = usePickerItemContext("Picker.Item");
272
+ const internalRef = useRef(null);
273
+ const isSelected = selectedValue === value && !disabled;
274
+ useEffect(() => {
275
+ const element = internalRef.current;
276
+ if (element) {
277
+ registerItem(value, element, onSelect, disabled);
278
+ }
279
+ return () => unregisterItem(value);
280
+ }, [
281
+ value,
282
+ onSelect,
283
+ disabled,
284
+ registerItem,
285
+ unregisterItem
286
+ ]);
287
+ useEffect(() => {
288
+ if (isSelected && internalRef.current) {
289
+ internalRef.current.scrollIntoView({
290
+ block: "nearest",
291
+ behavior: "smooth"
292
+ });
293
+ }
294
+ }, [
295
+ isSelected
296
+ ]);
297
+ const handleClick = useCallback(() => {
298
+ if (disabled) {
299
+ return;
300
+ }
301
+ onSelectedValueChange(value);
302
+ onSelect?.();
303
+ }, [
304
+ disabled,
305
+ value,
306
+ onSelectedValueChange,
307
+ onSelect
308
+ ]);
309
+ const handleMouseDown = useCallback((event) => {
310
+ event.preventDefault();
311
+ }, []);
312
+ const Comp = asChild ? Slot : "div";
313
+ return /* @__PURE__ */ React3.createElement(Comp, {
314
+ ...props,
315
+ ref: (node) => {
316
+ internalRef.current = node;
317
+ if (typeof forwardedRef === "function") {
318
+ forwardedRef(node);
319
+ } else if (forwardedRef) {
320
+ forwardedRef.current = node;
321
+ }
322
+ },
323
+ role: "option",
324
+ "aria-selected": isSelected,
325
+ "aria-disabled": disabled,
326
+ "data-selected": isSelected,
327
+ "data-disabled": disabled,
328
+ "data-value": value,
329
+ // Browser focus stays on the input; highlight is via `aria-selected`.
330
+ tabIndex: -1,
331
+ className: mx3("dx-hover dx-selected px-[var(--gutter,0.75rem)] py-1 cursor-pointer select-none", disabled && "opacity-50 cursor-not-allowed", classNames),
332
+ onMouseDown: handleMouseDown,
333
+ onClick: handleClick
334
+ }, children);
335
+ });
336
+ PickerItem.displayName = "Picker.Item";
337
+ var Picker = {
338
+ Root: PickerRoot,
339
+ Input: PickerInput,
340
+ Item: PickerItem
341
+ };
342
+
343
+ // src/components/Combobox/Combobox.tsx
344
+ var COMBOBOX_NAME = "Combobox";
345
+ var COMBOBOX_CONTENT_NAME = "ComboboxContent";
346
+ var COMBOBOX_ITEM_NAME = "ComboboxItem";
347
+ var COMBOBOX_TRIGGER_NAME = "ComboboxTrigger";
348
+ var [ComboboxProvider, useComboboxContext] = createContext4(COMBOBOX_NAME, {});
349
+ var ComboboxRoot = ({ children, modal, modalId: modalIdProp, open: openProp, defaultOpen, onOpenChange: propsOnOpenChange, value: valueProp, defaultValue, onValueChange: propsOnValueChange, placeholder }) => {
350
+ const modalId = useId(COMBOBOX_NAME, modalIdProp);
351
+ const [open = false, onOpenChange] = useControllableState({
352
+ prop: openProp,
353
+ defaultProp: defaultOpen,
354
+ onChange: propsOnOpenChange
355
+ });
356
+ const [value = "", onValueChange] = useControllableState({
357
+ prop: valueProp,
358
+ defaultProp: defaultValue,
359
+ onChange: propsOnValueChange
360
+ });
361
+ return /* @__PURE__ */ React4.createElement(Popover.Root, {
362
+ open,
363
+ onOpenChange,
364
+ modal
365
+ }, /* @__PURE__ */ React4.createElement(ComboboxProvider, {
366
+ isCombobox: true,
367
+ modalId,
368
+ placeholder,
369
+ open,
370
+ onOpenChange,
371
+ value,
372
+ onValueChange
373
+ }, children));
374
+ };
375
+ var ComboboxContent = composable(({ children, ...props }, forwardedRef) => {
376
+ const { modalId } = useComboboxContext(COMBOBOX_CONTENT_NAME);
377
+ return /* @__PURE__ */ React4.createElement(Popover.Content, {
378
+ ...composableProps(props, {
379
+ id: modalId
380
+ }),
381
+ ref: forwardedRef
382
+ }, /* @__PURE__ */ React4.createElement(Popover.Viewport, {
383
+ classNames: "w-(--radix-popover-trigger-width)"
384
+ }, /* @__PURE__ */ React4.createElement(Picker.Root, null, children)));
385
+ });
386
+ ComboboxContent.displayName = COMBOBOX_CONTENT_NAME;
387
+ var ComboboxTrigger = /* @__PURE__ */ forwardRef2(({ children, onClick, ...props }, forwardedRef) => {
388
+ const { modalId, open, onOpenChange, placeholder, value } = useComboboxContext(COMBOBOX_TRIGGER_NAME);
389
+ const handleClick = useCallback2((event) => {
390
+ onClick?.(event);
391
+ onOpenChange?.(true);
392
+ }, [
393
+ onClick,
394
+ onOpenChange
395
+ ]);
396
+ return /* @__PURE__ */ React4.createElement(Popover.Trigger, {
397
+ asChild: true
398
+ }, /* @__PURE__ */ React4.createElement(Button, {
399
+ ...props,
400
+ role: "combobox",
401
+ "aria-expanded": open,
402
+ "aria-controls": modalId,
403
+ "aria-haspopup": "dialog",
404
+ onClick: handleClick,
405
+ ref: forwardedRef
406
+ }, children ?? /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement("span", {
407
+ className: mx4("font-normal text-start flex-1 min-w-0 truncate me-2", !value && "text-subdued")
408
+ }, value || placeholder), /* @__PURE__ */ React4.createElement(Icon2, {
409
+ icon: "ph--caret-down--bold",
410
+ size: 3
411
+ }))));
412
+ });
413
+ ComboboxTrigger.displayName = COMBOBOX_TRIGGER_NAME;
414
+ var ComboboxVirtualTrigger = Popover.VirtualTrigger;
415
+ var ComboboxInput = /* @__PURE__ */ forwardRef2(({ classNames, ...props }, forwardedRef) => {
416
+ return /* @__PURE__ */ React4.createElement(Picker.Input, {
417
+ ...props,
418
+ classNames: [
419
+ "m-form-chrome mb-0 w-[calc(100%-2*var(--spacing-form-chrome))]",
420
+ classNames
421
+ ],
422
+ ref: forwardedRef
423
+ });
424
+ });
425
+ ComboboxInput.displayName = "Combobox.Input";
426
+ var ComboboxList = /* @__PURE__ */ forwardRef2(({ classNames, children, ...props }, forwardedRef) => {
427
+ return /* @__PURE__ */ React4.createElement(ScrollArea.Root, {
428
+ ...composableProps(props, {
429
+ classNames: [
430
+ "py-form-chrome",
431
+ classNames
432
+ ]
433
+ }),
434
+ role: "listbox",
435
+ centered: true,
436
+ padding: true,
437
+ thin: true,
438
+ ref: forwardedRef
439
+ }, /* @__PURE__ */ React4.createElement(ScrollArea.Viewport, null, children));
440
+ });
441
+ ComboboxList.displayName = "Combobox.List";
442
+ var ComboboxItem = /* @__PURE__ */ forwardRef2(({ classNames, onSelect, value, label, icon, iconClassNames, checked, suffix, disabled, closeOnSelect = true, children }, forwardedRef) => {
443
+ const { onValueChange, onOpenChange } = useComboboxContext(COMBOBOX_ITEM_NAME);
444
+ const handleSelect = useCallback2(() => {
445
+ onSelect?.();
446
+ if (value !== void 0) {
447
+ onValueChange?.(value);
448
+ }
449
+ if (closeOnSelect) {
450
+ onOpenChange?.(false);
451
+ }
452
+ }, [
453
+ onSelect,
454
+ onValueChange,
455
+ onOpenChange,
456
+ value,
457
+ closeOnSelect
458
+ ]);
459
+ return /* @__PURE__ */ React4.createElement(Picker.Item, {
460
+ value,
461
+ disabled,
462
+ onSelect: handleSelect,
463
+ ref: forwardedRef,
464
+ classNames: [
465
+ // Full width inside the viewport (no horizontal margin).
466
+ // `px-3 py-1`, `cursor-pointer`, `select-none` and the
467
+ // `dx-hover` / `dx-selected` pairing come from `Picker.Item`'s
468
+ // defaults; we only add the row-shape (flex / icons + label)
469
+ // and the disabled overrides on top.
470
+ "flex w-full gap-2 items-center",
471
+ disabled && "hover:bg-transparent data-[selected=true]:bg-transparent",
472
+ classNames
473
+ ]
474
+ }, children ?? /* @__PURE__ */ React4.createElement(React4.Fragment, null, icon && /* @__PURE__ */ React4.createElement(Icon2, {
475
+ icon,
476
+ classNames: iconClassNames
477
+ }), /* @__PURE__ */ React4.createElement("span", {
478
+ className: "w-0 grow truncate"
479
+ }, label), suffix && /* @__PURE__ */ React4.createElement("span", {
480
+ className: "shrink-0 text-description"
481
+ }, suffix), checked && /* @__PURE__ */ React4.createElement(Icon2, {
482
+ icon: "ph--check--regular"
483
+ })));
484
+ });
485
+ ComboboxItem.displayName = COMBOBOX_ITEM_NAME;
486
+ var ComboboxArrow = Popover.Arrow;
487
+ var ComboboxEmpty = /* @__PURE__ */ forwardRef2(({ classNames, children }, forwardedRef) => {
488
+ return /* @__PURE__ */ React4.createElement("div", {
489
+ ref: forwardedRef,
490
+ role: "status",
491
+ className: mx4(classNames)
492
+ }, children);
493
+ });
494
+ ComboboxEmpty.displayName = "Combobox.Empty";
495
+ var ComboboxPortal = Popover.Portal;
496
+ var Combobox = {
497
+ Root: ComboboxRoot,
498
+ Portal: ComboboxPortal,
499
+ Content: ComboboxContent,
500
+ Trigger: ComboboxTrigger,
501
+ VirtualTrigger: ComboboxVirtualTrigger,
502
+ Input: ComboboxInput,
503
+ List: ComboboxList,
504
+ Item: ComboboxItem,
505
+ Arrow: ComboboxArrow,
506
+ Empty: ComboboxEmpty
507
+ };
508
+
73
509
  // src/components/List/ListItem.tsx
510
+ import { attachClosestEdge, extractClosestEdge as extractClosestEdge2 } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
74
511
  import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
75
512
  import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
76
513
  import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview";
77
- import { attachClosestEdge, extractClosestEdge as extractClosestEdge2 } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
78
- import { createContext as createContext4 } from "@radix-ui/react-context";
79
- import { Slot } from "@radix-ui/react-slot";
80
- import React4, { useEffect as useEffect2, useRef, useState as useState2 } from "react";
514
+ import { createContext as createContext6 } from "@radix-ui/react-context";
515
+ import { Slot as Slot2 } from "@radix-ui/react-slot";
516
+ import React6, { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
81
517
  import { createPortal } from "react-dom";
82
518
  import { invariant } from "@dxos/invariant";
83
519
  import { IconButton, ListItem as NaturalListItem, useTranslation } from "@dxos/react-ui";
84
- import { mx as mx3, osTranslations } from "@dxos/ui-theme";
520
+ import { mx as mx5, osTranslations } from "@dxos/ui-theme";
85
521
 
86
522
  // src/components/List/ListRoot.tsx
87
- import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
88
523
  import { extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
89
524
  import { getReorderDestinationIndex } from "@atlaskit/pragmatic-drag-and-drop-hitbox/util/get-reorder-destination-index";
90
- import { createContext as createContext3 } from "@radix-ui/react-context";
91
- import React3, { useCallback, useEffect, useState } from "react";
525
+ import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
526
+ import { createContext as createContext5 } from "@radix-ui/react-context";
527
+ import React5, { useCallback as useCallback3, useEffect as useEffect2, useState as useState2 } from "react";
92
528
  var LIST_NAME = "List";
93
- var [ListProvider, useListContext] = createContext3(LIST_NAME);
529
+ var [ListProvider, useListContext] = createContext5(LIST_NAME);
94
530
  var defaultGetId2 = (item) => item?.id;
95
531
  var ListRoot = ({ children, items, isItem, getId = defaultGetId2, onMove, ...props }) => {
96
- const isEqual = useCallback((a, b) => {
532
+ const isEqual = useCallback3((a, b) => {
97
533
  const idA = getId?.(a);
98
534
  const idB = getId?.(b);
99
535
  if (idA !== void 0 && idB !== void 0) {
@@ -104,8 +540,8 @@ var ListRoot = ({ children, items, isItem, getId = defaultGetId2, onMove, ...pro
104
540
  }, [
105
541
  getId
106
542
  ]);
107
- const [state, setState] = useState(idle);
108
- useEffect(() => {
543
+ const [state, setState] = useState2(idle);
544
+ useEffect2(() => {
109
545
  if (!items) {
110
546
  return;
111
547
  }
@@ -141,7 +577,7 @@ var ListRoot = ({ children, items, isItem, getId = defaultGetId2, onMove, ...pro
141
577
  isEqual,
142
578
  onMove
143
579
  ]);
144
- return /* @__PURE__ */ React3.createElement(ListProvider, {
580
+ return /* @__PURE__ */ React5.createElement(ListProvider, {
145
581
  state,
146
582
  setState,
147
583
  isItem,
@@ -158,28 +594,20 @@ var idle = {
158
594
  type: "idle"
159
595
  };
160
596
  var stateStyles = {
161
- "w-dragging": "opacity-50"
597
+ "is-dragging": "opacity-50"
162
598
  };
163
599
  var defaultContext = {};
164
600
  var LIST_ITEM_NAME = "ListItem";
165
- var [ListItemProvider, useListItemContext] = createContext4(LIST_ITEM_NAME, defaultContext);
601
+ var [ListItemProvider, useListItemContext] = createContext6(LIST_ITEM_NAME, defaultContext);
166
602
  var ListItem = ({ children, classNames, item, asChild, selected, ...props }) => {
167
- const Comp = asChild ? Slot : "div";
603
+ const Comp = asChild ? Slot2 : "div";
168
604
  const { isItem, readonly, dragPreview, setState: setRootState } = useListContext(LIST_ITEM_NAME);
169
- const ref = useRef(null);
170
- const dragHandleRef = useRef(null);
171
- const [state, setState] = useState2(idle);
172
- useEffect2(() => {
173
- const element = ref.current;
174
- invariant(element, void 0, {
175
- F: __dxlog_file,
176
- L: 109,
177
- S: void 0,
178
- A: [
179
- "element",
180
- ""
181
- ]
182
- });
605
+ const rootRef = useRef2(null);
606
+ const dragHandleRef = useRef2(null);
607
+ const [state, setState] = useState3(idle);
608
+ useEffect3(() => {
609
+ const element = rootRef.current;
610
+ invariant(element, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 37, S: void 0, A: ["element", ""] });
183
611
  return combine(
184
612
  //
185
613
  // https://atlassian.design/components/pragmatic-drag-and-drop/core-package/adapters/element/about#draggable
@@ -218,10 +646,10 @@ var ListItem = ({ children, classNames, item, asChild, selected, ...props }) =>
218
646
  } : void 0,
219
647
  onDragStart: () => {
220
648
  setState({
221
- type: "w-dragging"
649
+ type: "is-dragging"
222
650
  });
223
651
  setRootState({
224
- type: "w-dragging",
652
+ type: "is-dragging",
225
653
  item
226
654
  });
227
655
  },
@@ -252,7 +680,7 @@ var ListItem = ({ children, classNames, item, asChild, selected, ...props }) =>
252
680
  onDragEnter: ({ self }) => {
253
681
  const closestEdge = extractClosestEdge2(self.data);
254
682
  setState({
255
- type: "w-dragging-over",
683
+ type: "is-dragging-over",
256
684
  closestEdge
257
685
  });
258
686
  },
@@ -262,11 +690,11 @@ var ListItem = ({ children, classNames, item, asChild, selected, ...props }) =>
262
690
  onDrag: ({ self }) => {
263
691
  const closestEdge = extractClosestEdge2(self.data);
264
692
  setState((current) => {
265
- if (current.type === "w-dragging-over" && current.closestEdge === closestEdge) {
693
+ if (current.type === "is-dragging-over" && current.closestEdge === closestEdge) {
266
694
  return current;
267
695
  }
268
696
  return {
269
- type: "w-dragging-over",
697
+ type: "is-dragging-over",
270
698
  closestEdge
271
699
  };
272
700
  });
@@ -279,23 +707,23 @@ var ListItem = ({ children, classNames, item, asChild, selected, ...props }) =>
279
707
  }, [
280
708
  item
281
709
  ]);
282
- return /* @__PURE__ */ React4.createElement(ListItemProvider, {
710
+ return /* @__PURE__ */ React6.createElement(ListItemProvider, {
283
711
  item,
284
712
  dragHandleRef
285
- }, /* @__PURE__ */ React4.createElement(Comp, {
286
- ref,
713
+ }, /* @__PURE__ */ React6.createElement(Comp, {
714
+ ...props,
287
715
  role: "listitem",
288
716
  "aria-selected": selected,
289
- className: mx3("relative dx-selected", classNames, stateStyles[state.type]),
290
- ...props
291
- }, children), state.type === "w-dragging-over" && state.closestEdge && /* @__PURE__ */ React4.createElement(NaturalListItem.DropIndicator, {
717
+ className: mx5("relative p-1 dx-selected dx-hover", classNames, stateStyles[state.type]),
718
+ ref: rootRef
719
+ }, children), state.type === "is-dragging-over" && state.closestEdge && /* @__PURE__ */ React6.createElement(NaturalListItem.DropIndicator, {
292
720
  edge: state.closestEdge
293
721
  }));
294
722
  };
295
723
  var ListItemIconButton = ({ autoHide = true, iconOnly = true, variant = "ghost", classNames, disabled, ...props }) => {
296
724
  const { state } = useListContext("ITEM_BUTTON");
297
725
  const isDisabled = state.type !== "idle" || disabled;
298
- return /* @__PURE__ */ React4.createElement(IconButton, {
726
+ return /* @__PURE__ */ React6.createElement(IconButton, {
299
727
  ...props,
300
728
  disabled: isDisabled,
301
729
  iconOnly,
@@ -310,13 +738,13 @@ var ListItemDeleteButton = ({ autoHide = true, classNames, disabled, icon = "ph-
310
738
  const { state } = useListContext("DELETE_BUTTON");
311
739
  const isDisabled = state.type !== "idle" || disabled;
312
740
  const { t } = useTranslation(osTranslations);
313
- return /* @__PURE__ */ React4.createElement(IconButton, {
314
- iconOnly: true,
315
- variant: "ghost",
741
+ return /* @__PURE__ */ React6.createElement(IconButton, {
316
742
  ...props,
317
- icon,
743
+ variant: "ghost",
318
744
  disabled: isDisabled,
319
- label: label ?? t("delete label"),
745
+ icon,
746
+ iconOnly: true,
747
+ label: label ?? t("delete.label"),
320
748
  classNames: [
321
749
  classNames,
322
750
  autoHide && disabled && "hidden"
@@ -326,13 +754,13 @@ var ListItemDeleteButton = ({ autoHide = true, classNames, disabled, icon = "ph-
326
754
  var ListItemDragHandle = ({ disabled }) => {
327
755
  const { dragHandleRef } = useListItemContext("DRAG_HANDLE");
328
756
  const { t } = useTranslation(osTranslations);
329
- return /* @__PURE__ */ React4.createElement(IconButton, {
330
- iconOnly: true,
757
+ return /* @__PURE__ */ React6.createElement(IconButton, {
331
758
  variant: "ghost",
332
- label: t("drag handle label"),
333
- ref: dragHandleRef,
759
+ disabled,
334
760
  icon: "ph--dots-six-vertical--regular",
335
- disabled
761
+ iconOnly: true,
762
+ label: t("drag-handle.label"),
763
+ ref: dragHandleRef
336
764
  });
337
765
  };
338
766
  var ListItemDragPreview = ({ children }) => {
@@ -341,11 +769,11 @@ var ListItemDragPreview = ({ children }) => {
341
769
  item: state.item
342
770
  }), state.container) : null;
343
771
  };
344
- var ListItemWrapper = ({ classNames, children }) => /* @__PURE__ */ React4.createElement("div", {
345
- className: mx3("flex w-full gap-2", classNames)
772
+ var ListItemWrapper = ({ classNames, children }) => /* @__PURE__ */ React6.createElement("div", {
773
+ className: mx5("flex w-full gap-2", classNames)
346
774
  }, children);
347
- var ListItemTitle = ({ classNames, children, ...props }) => /* @__PURE__ */ React4.createElement("div", {
348
- className: mx3("flex grow items-center truncate", classNames),
775
+ var ListItemTitle = ({ classNames, children, ...props }) => /* @__PURE__ */ React6.createElement("div", {
776
+ className: mx5("flex grow items-center truncate", classNames),
349
777
  ...props
350
778
  }, children);
351
779
 
@@ -361,28 +789,247 @@ var List = {
361
789
  ItemTitle: ListItemTitle
362
790
  };
363
791
 
792
+ // src/components/Listbox/Listbox.tsx
793
+ import { createContextScope as createContextScope2 } from "@radix-ui/react-context";
794
+ import React8, { forwardRef as forwardRef3 } from "react";
795
+ import { Icon as Icon3 } from "@dxos/react-ui";
796
+ import { mx as mx6 } from "@dxos/ui-theme";
797
+
798
+ // src/components/RowList/RowList.tsx
799
+ import { useArrowNavigationGroup } from "@fluentui/react-tabster";
800
+ import { createContextScope } from "@radix-ui/react-context";
801
+ import { useControllableState as useControllableState2 } from "@radix-ui/react-use-controllable-state";
802
+ import React7, { useCallback as useCallback4 } from "react";
803
+ import { List as List2, ListItem as ListItem2 } from "@dxos/react-list";
804
+ import { ScrollArea as ScrollArea2 } from "@dxos/react-ui";
805
+ import { composable as composable2, composableProps as composableProps2 } from "@dxos/react-ui";
806
+ var ROW_LIST_NAME = "RowList";
807
+ var ROW_LIST_ROOT_NAME = "RowList.Root";
808
+ var ROW_LIST_VIEWPORT_NAME = "RowList.Viewport";
809
+ var ROW_LIST_CONTENT_NAME = "RowList.Content";
810
+ var ROW_NAME = "List.Row";
811
+ var [createRowListContext, createRowListScope] = createContextScope(ROW_LIST_NAME, []);
812
+ var [RowListProvider, useRowListContext] = createRowListContext(ROW_LIST_NAME);
813
+ var Root2 = ({ selectedId, defaultSelectedId, onSelectChange, children }) => {
814
+ const [resolved, setResolved] = useControllableState2({
815
+ prop: selectedId,
816
+ defaultProp: defaultSelectedId,
817
+ onChange: (next) => {
818
+ if (next !== void 0) {
819
+ onSelectChange?.(next);
820
+ }
821
+ }
822
+ });
823
+ const setSelected = useCallback4((id) => setResolved(id), [
824
+ setResolved
825
+ ]);
826
+ return /* @__PURE__ */ React7.createElement(RowListProvider, {
827
+ scope: void 0,
828
+ selectedId: resolved,
829
+ setSelected
830
+ }, children);
831
+ };
832
+ Root2.displayName = ROW_LIST_ROOT_NAME;
833
+ var Viewport = composable2((props, forwardedRef) => {
834
+ const { thin, padding, centered, children, ...rest } = props;
835
+ return /* @__PURE__ */ React7.createElement(ScrollArea2.Root, {
836
+ ...composableProps2(rest, {
837
+ classNames: "dx-container"
838
+ }),
839
+ thin,
840
+ padding,
841
+ centered,
842
+ orientation: "vertical",
843
+ ref: forwardedRef
844
+ }, /* @__PURE__ */ React7.createElement(ScrollArea2.Viewport, null, children));
845
+ });
846
+ Viewport.displayName = ROW_LIST_VIEWPORT_NAME;
847
+ var firstEnabledOption = (ul) => {
848
+ if (!ul) {
849
+ return null;
850
+ }
851
+ return ul.querySelector('[role="option"]:not([aria-disabled="true"])');
852
+ };
853
+ var Content2 = composable2((props, forwardedRef) => {
854
+ useRowListContext(ROW_LIST_CONTENT_NAME, void 0);
855
+ const arrowGroup = useArrowNavigationGroup({
856
+ axis: "vertical",
857
+ memorizeCurrent: true
858
+ });
859
+ const { children, ...rest } = props;
860
+ const handleFocus = useCallback4((event) => {
861
+ if (event.target !== event.currentTarget) {
862
+ return;
863
+ }
864
+ const ul = event.currentTarget;
865
+ const selected = ul.querySelector('[role="option"][aria-selected="true"]:not([aria-disabled="true"])');
866
+ const target = selected ?? firstEnabledOption(ul);
867
+ target?.focus();
868
+ }, []);
869
+ const composed = composableProps2(rest, {
870
+ classNames: "flex flex-col"
871
+ });
872
+ return /* @__PURE__ */ React7.createElement(List2, {
873
+ variant: "unordered",
874
+ ...composed,
875
+ ...arrowGroup,
876
+ role: "listbox",
877
+ onFocus: handleFocus,
878
+ ref: forwardedRef
879
+ }, children);
880
+ });
881
+ Content2.displayName = ROW_LIST_CONTENT_NAME;
882
+ var ROW_BASE = "dx-hover dx-selected px-3 py-2 cursor-pointer outline-none";
883
+ var Row = composable2((props, forwardedRef) => {
884
+ const { id, disabled, onClick, onFocus, children, ...rest } = props;
885
+ const { selectedId, setSelected } = useRowListContext(ROW_NAME, void 0);
886
+ const isSelected = selectedId === id;
887
+ const handleClick = useCallback4((event) => {
888
+ if (disabled) {
889
+ return;
890
+ }
891
+ setSelected(id);
892
+ onClick?.(event);
893
+ }, [
894
+ disabled,
895
+ id,
896
+ setSelected,
897
+ onClick
898
+ ]);
899
+ const handleFocus = useCallback4((event) => {
900
+ if (!disabled && selectedId !== id) {
901
+ setSelected(id);
902
+ }
903
+ onFocus?.(event);
904
+ }, [
905
+ disabled,
906
+ selectedId,
907
+ id,
908
+ setSelected,
909
+ onFocus
910
+ ]);
911
+ const composed = composableProps2(rest, {
912
+ classNames: [
913
+ ROW_BASE,
914
+ disabled && "opacity-50 cursor-not-allowed"
915
+ ]
916
+ });
917
+ return /* @__PURE__ */ React7.createElement(ListItem2, {
918
+ ...composed,
919
+ role: "option",
920
+ tabIndex: 0,
921
+ "aria-selected": isSelected,
922
+ "aria-disabled": disabled || void 0,
923
+ onClick: handleClick,
924
+ onFocus: handleFocus,
925
+ ref: forwardedRef
926
+ }, children);
927
+ });
928
+ Row.displayName = ROW_NAME;
929
+ var useRowListSelection = (id) => {
930
+ const { selectedId } = useRowListContext("useRowListSelection", void 0);
931
+ return selectedId === id;
932
+ };
933
+ var RowList = {
934
+ Root: Root2,
935
+ Viewport,
936
+ Content: Content2
937
+ };
938
+
939
+ // src/components/Listbox/Listbox.tsx
940
+ var commandItem = "flex items-center overflow-hidden";
941
+ var LISTBOX_NAME = "Listbox";
942
+ var LISTBOX_OPTION_NAME = "ListboxOption";
943
+ var LISTBOX_OPTION_LABEL_NAME = "ListboxOptionLabel";
944
+ var LISTBOX_OPTION_INDICATOR_NAME = "ListboxOptionIndicator";
945
+ var [createListboxContext, createListboxScope] = createContextScope2(LISTBOX_NAME, [
946
+ createRowListScope
947
+ ]);
948
+ var [createListboxOptionContext, createListboxOptionScope] = createContextScope2(LISTBOX_OPTION_NAME, [
949
+ createListboxScope
950
+ ]);
951
+ var [ListboxOptionProvider, useListboxOptionContext] = createListboxOptionContext(LISTBOX_OPTION_NAME);
952
+ var ListboxRoot = /* @__PURE__ */ forwardRef3((props, forwardedRef) => {
953
+ const { __listboxScope: _scope, children, classNames, value, defaultValue, onValueChange, autoFocus: _autoFocus, ...rootProps } = props;
954
+ return /* @__PURE__ */ React8.createElement(RowList.Root, {
955
+ selectedId: value,
956
+ defaultSelectedId: defaultValue,
957
+ onSelectChange: onValueChange
958
+ }, /* @__PURE__ */ React8.createElement(RowList.Content, {
959
+ ...rootProps,
960
+ classNames: mx6("w-full", classNames),
961
+ ref: forwardedRef
962
+ }, children));
963
+ });
964
+ ListboxRoot.displayName = LISTBOX_NAME;
965
+ var ListboxOption = /* @__PURE__ */ forwardRef3((props, forwardedRef) => {
966
+ const { __listboxScope, children, classNames, value, ...rootProps } = props;
967
+ return /* @__PURE__ */ React8.createElement(Row, {
968
+ id: value,
969
+ ...rootProps,
970
+ classNames: mx6("dx-focus-ring rounded-xs", commandItem, classNames),
971
+ ref: forwardedRef
972
+ }, /* @__PURE__ */ React8.createElement(ListboxOptionProviderHost, {
973
+ value
974
+ }, children));
975
+ });
976
+ ListboxOption.displayName = LISTBOX_OPTION_NAME;
977
+ var ListboxOptionProviderHost = ({ value, children }) => {
978
+ const isSelected = useRowListSelection(value);
979
+ return /* @__PURE__ */ React8.createElement(ListboxOptionProvider, {
980
+ scope: void 0,
981
+ value,
982
+ isSelected
983
+ }, children);
984
+ };
985
+ var ListboxOptionLabel = /* @__PURE__ */ forwardRef3(({ children, classNames, ...rootProps }, forwardedRef) => {
986
+ return /* @__PURE__ */ React8.createElement("span", {
987
+ ...rootProps,
988
+ className: mx6("grow truncate", classNames),
989
+ ref: forwardedRef
990
+ }, children);
991
+ });
992
+ ListboxOptionLabel.displayName = LISTBOX_OPTION_LABEL_NAME;
993
+ var ListboxOptionIndicator = /* @__PURE__ */ forwardRef3((props, forwardedRef) => {
994
+ const { __listboxOptionScope, classNames, ...rootProps } = props;
995
+ const { isSelected } = useListboxOptionContext(LISTBOX_OPTION_INDICATOR_NAME, __listboxOptionScope);
996
+ return /* @__PURE__ */ React8.createElement(Icon3, {
997
+ icon: "ph--check--regular",
998
+ ...rootProps,
999
+ classNames: mx6(!isSelected && "invisible", classNames),
1000
+ ref: forwardedRef
1001
+ });
1002
+ });
1003
+ ListboxOptionIndicator.displayName = LISTBOX_OPTION_INDICATOR_NAME;
1004
+ var Listbox = {
1005
+ Root: ListboxRoot,
1006
+ Option: ListboxOption,
1007
+ OptionLabel: ListboxOptionLabel,
1008
+ OptionIndicator: ListboxOptionIndicator
1009
+ };
1010
+
364
1011
  // src/components/Tree/Tree.tsx
365
1012
  import { useAtomValue as useAtomValue2 } from "@effect-atom/atom-react";
366
- import React8, { useMemo as useMemo2 } from "react";
1013
+ import React12, { useMemo as useMemo3 } from "react";
367
1014
  import { Treegrid as Treegrid2 } from "@dxos/react-ui";
368
1015
 
369
1016
  // src/components/Tree/TreeContext.tsx
370
- import { createContext as createContext5, useContext } from "react";
1017
+ import { createContext as createContext7, useContext } from "react";
371
1018
  import { raise } from "@dxos/debug";
372
- var TreeContext = /* @__PURE__ */ createContext5(null);
1019
+ var TreeContext = /* @__PURE__ */ createContext7(null);
373
1020
  var TreeProvider = TreeContext.Provider;
374
1021
  var useTree = () => useContext(TreeContext) ?? raise(new Error("TreeContext not found"));
375
1022
 
376
1023
  // src/components/Tree/TreeItem.tsx
1024
+ import { attachInstruction, extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
377
1025
  import { combine as combine2 } from "@atlaskit/pragmatic-drag-and-drop/combine";
378
1026
  import { draggable as draggable2, dropTargetForElements as dropTargetForElements2 } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
379
- import { attachInstruction, extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
380
1027
  import { useAtomValue } from "@effect-atom/atom-react";
381
1028
  import * as Schema from "effect/Schema";
382
- import React7, { memo as memo3, useCallback as useCallback3, useEffect as useEffect3, useMemo, useRef as useRef2, useState as useState3 } from "react";
1029
+ import React11, { memo as memo3, useCallback as useCallback6, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef3, useState as useState4 } from "react";
383
1030
  import { invariant as invariant2 } from "@dxos/invariant";
384
- import { TreeItem as NaturalTreeItem, Treegrid } from "@dxos/react-ui";
385
- import { ghostFocusWithin, ghostHover, hoverableControls, hoverableFocusedKeyboardControls, hoverableFocusedWithinControls, mx as mx4 } from "@dxos/ui-theme";
1031
+ import { TreeItem as NaturalTreeItem, Treegrid, TREEGRID_PARENT_OF_SEPARATOR } from "@dxos/react-ui";
1032
+ import { ghostFocusWithin, ghostHover, hoverableControls, hoverableFocusedKeyboardControls, hoverableFocusedWithinControls, mx as mx7 } from "@dxos/ui-theme";
386
1033
 
387
1034
  // src/components/Tree/helpers.ts
388
1035
  var DEFAULT_INDENTATION = 8;
@@ -391,19 +1038,19 @@ var paddingIndentation = (level, indentation = DEFAULT_INDENTATION) => ({
391
1038
  });
392
1039
 
393
1040
  // src/components/Tree/TreeItemHeading.tsx
394
- import React5, { forwardRef, memo, useCallback as useCallback2 } from "react";
395
- import { Button, Icon as Icon2, toLocalizedString, useTranslation as useTranslation2 } from "@dxos/react-ui";
1041
+ import React9, { forwardRef as forwardRef4, memo, useCallback as useCallback5 } from "react";
1042
+ import { Button as Button2, Icon as Icon4, Tag, toLocalizedString, useTranslation as useTranslation2 } from "@dxos/react-ui";
396
1043
  import { TextTooltip } from "@dxos/react-ui-text-tooltip";
397
1044
  import { getStyles } from "@dxos/ui-theme";
398
- var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef(({ label, className, icon, iconHue, disabled, current, onSelect }, forwardedRef) => {
1045
+ var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef4(({ label, className, icon, iconHue, disabled, current, count, modifiedCount, onSelect }, forwardedRef) => {
399
1046
  const { t } = useTranslation2();
400
1047
  const styles = iconHue ? getStyles(iconHue) : void 0;
401
- const handleSelect = useCallback2((event) => {
1048
+ const handleSelect = useCallback5((event) => {
402
1049
  onSelect?.(event.altKey);
403
1050
  }, [
404
1051
  onSelect
405
1052
  ]);
406
- const handleButtonKeydown = useCallback2((event) => {
1053
+ const handleButtonKeydown = useCallback5((event) => {
407
1054
  if (event.key === " " || event.key === "Enter") {
408
1055
  event.preventDefault();
409
1056
  event.stopPropagation();
@@ -412,19 +1059,18 @@ var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef(({ label,
412
1059
  }, [
413
1060
  onSelect
414
1061
  ]);
415
- return /* @__PURE__ */ React5.createElement(TextTooltip, {
1062
+ return /* @__PURE__ */ React9.createElement(TextTooltip, {
416
1063
  text: toLocalizedString(label, t),
417
1064
  side: "bottom",
418
1065
  truncateQuery: "span[data-tooltip]",
419
1066
  onlyWhenTruncating: true,
420
1067
  asChild: true,
421
1068
  ref: forwardedRef
422
- }, /* @__PURE__ */ React5.createElement(Button, {
1069
+ }, /* @__PURE__ */ React9.createElement(Button2, {
423
1070
  "data-testid": "treeItem.heading",
424
1071
  variant: "ghost",
425
- density: "fine",
426
1072
  classNames: [
427
- "grow gap-2 ps-0.5 hover:bg-transparent dark:hover:bg-transparent",
1073
+ "grow shrink min-w-0 justify-start gap-2 ps-0.5 hover:bg-transparent dark:hover:bg-transparent",
428
1074
  "disabled:cursor-default disabled:opacity-100",
429
1075
  className
430
1076
  ],
@@ -434,33 +1080,51 @@ var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef(({ label,
434
1080
  ...current && {
435
1081
  "aria-current": "location"
436
1082
  }
437
- }, icon && /* @__PURE__ */ React5.createElement(Icon2, {
438
- icon: icon ?? "ph--placeholder--regular",
1083
+ }, icon && /* @__PURE__ */ React9.createElement(Icon4, {
439
1084
  size: 5,
1085
+ icon: icon ?? "ph--circle-dashed--regular",
440
1086
  classNames: [
441
1087
  "my-1",
442
- styles?.surfaceText
1088
+ styles?.text
443
1089
  ]
444
- }), /* @__PURE__ */ React5.createElement("span", {
445
- className: "flex-1 w-0 truncate text-start font-normal",
1090
+ }), /* @__PURE__ */ React9.createElement("span", {
1091
+ className: "min-w-0 truncate text-start font-normal",
446
1092
  "data-tooltip": true
447
- }, toLocalizedString(label, t))));
1093
+ }, toLocalizedString(label, t)), /* @__PURE__ */ React9.createElement(CountBadge, {
1094
+ count,
1095
+ modifiedCount
1096
+ })));
448
1097
  }));
1098
+ var CountBadge = ({ count, modifiedCount }) => {
1099
+ if (typeof modifiedCount === "number" && modifiedCount > 0) {
1100
+ return /* @__PURE__ */ React9.createElement(Tag, {
1101
+ palette: "rose",
1102
+ classNames: "shrink-0 text-center [min-inline-size:1.5rem] tabular-nums"
1103
+ }, modifiedCount);
1104
+ }
1105
+ if (typeof count === "number") {
1106
+ return /* @__PURE__ */ React9.createElement(Tag, {
1107
+ palette: "neutral",
1108
+ classNames: "shrink-0 text-center [min-inline-size:1.5rem] tabular-nums"
1109
+ }, count);
1110
+ }
1111
+ return null;
1112
+ };
449
1113
 
450
1114
  // src/components/Tree/TreeItemToggle.tsx
451
- import React6, { forwardRef as forwardRef2, memo as memo2 } from "react";
1115
+ import React10, { forwardRef as forwardRef5, memo as memo2 } from "react";
452
1116
  import { IconButton as IconButton2 } from "@dxos/react-ui";
453
- var TreeItemToggle = /* @__PURE__ */ memo2(/* @__PURE__ */ forwardRef2(({ open, isBranch, hidden, classNames, ...props }, forwardedRef) => {
454
- return /* @__PURE__ */ React6.createElement(IconButton2, {
1117
+ var TreeItemToggle = /* @__PURE__ */ memo2(/* @__PURE__ */ forwardRef5(({ classNames, open, isBranch, hidden, ...props }, forwardedRef) => {
1118
+ return /* @__PURE__ */ React10.createElement(IconButton2, {
455
1119
  ref: forwardedRef,
456
1120
  "data-testid": "treeItem.toggle",
457
1121
  "aria-expanded": open,
458
1122
  variant: "ghost",
459
- density: "fine",
1123
+ density: "md",
460
1124
  classNames: [
461
1125
  "h-full w-6 px-0",
462
- "[&_svg]:transition-[transform] [&_svg]:duration-200",
463
- open && "[&_svg]:rotate-90",
1126
+ "[&_svg]:transition-transform [&_svg]:duration-200",
1127
+ open ? "[&_svg]:rotate-90" : "[&_svg]:rotate-0",
464
1128
  hidden ? "hidden" : !isBranch && "invisible",
465
1129
  classNames
466
1130
  ],
@@ -484,22 +1148,22 @@ var TreeDataSchema = Schema.Struct({
484
1148
  });
485
1149
  var isTreeData = (data) => Schema.is(TreeDataSchema)(data);
486
1150
  var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: draggableProp, renderColumns: Columns, blockInstruction, canDrop, canSelect, onOpenChange, onSelect, onItemHover }) => {
487
- const rowRef = useRef2(null);
488
- const buttonRef = useRef2(null);
489
- const openRef = useRef2(false);
490
- const cancelExpandRef = useRef2(null);
491
- const [_state, setState] = useState3("idle");
492
- const [instruction, setInstruction] = useState3(null);
493
- const [menuOpen, setMenuOpen] = useState3(false);
1151
+ const rowRef = useRef3(null);
1152
+ const buttonRef = useRef3(null);
1153
+ const openRef = useRef3(false);
1154
+ const cancelExpandRef = useRef3(null);
1155
+ const [_state, setState] = useState4("idle");
1156
+ const [instruction, setInstruction] = useState4(null);
1157
+ const [menuOpen, setMenuOpen] = useState4(false);
494
1158
  const { itemProps: itemPropsAtom, childIds: childIdsAtom, itemOpen: itemOpenAtom, itemCurrent: itemCurrentAtom } = useTree();
495
- const path = useMemo(() => [
1159
+ const path = useMemo2(() => [
496
1160
  ...pathProp,
497
1161
  item.id
498
1162
  ], [
499
1163
  pathProp,
500
1164
  item.id
501
1165
  ]);
502
- const { id, parentOf, draggable: itemDraggable, droppable: itemDroppable, label, className, headingClassName, icon, iconHue, disabled, testId } = useAtomValue(itemPropsAtom(path));
1166
+ const { id, parentOf, draggable: itemDraggable, droppable: itemDroppable, label, className, headingClassName, icon, iconHue, disabled, testId, count, modifiedCount } = useAtomValue(itemPropsAtom(path));
503
1167
  const childIds = useAtomValue(childIdsAtom(item.id));
504
1168
  const open = useAtomValue(itemOpenAtom(path));
505
1169
  const current = useAtomValue(itemCurrentAtom(path));
@@ -515,7 +1179,8 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
515
1179
  path,
516
1180
  item
517
1181
  };
518
- const cancelExpand = useCallback3(() => {
1182
+ const shouldSeedNativeDragData = typeof document !== "undefined" && document.body.hasAttribute("data-platform");
1183
+ const cancelExpand = useCallback6(() => {
519
1184
  if (cancelExpandRef.current) {
520
1185
  clearTimeout(cancelExpandRef.current);
521
1186
  cancelExpandRef.current = null;
@@ -523,22 +1188,23 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
523
1188
  }, []);
524
1189
  const isItemDraggable = draggableProp && itemDraggable !== false;
525
1190
  const isItemDroppable = itemDroppable !== false;
526
- useEffect3(() => {
1191
+ const nativeDragText = id;
1192
+ useEffect4(() => {
527
1193
  if (!draggableProp) {
528
1194
  return;
529
1195
  }
530
- invariant2(buttonRef.current, void 0, {
531
- F: __dxlog_file2,
532
- L: 148,
533
- S: void 0,
534
- A: [
535
- "buttonRef.current",
536
- ""
537
- ]
538
- });
1196
+ invariant2(buttonRef.current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 70, S: void 0, A: ["buttonRef.current", ""] });
539
1197
  const makeDraggable = () => draggable2({
540
1198
  element: buttonRef.current,
541
1199
  getInitialData: () => data,
1200
+ getInitialDataForExternal: () => {
1201
+ if (!shouldSeedNativeDragData) {
1202
+ return {};
1203
+ }
1204
+ return {
1205
+ "text/plain": nativeDragText
1206
+ };
1207
+ },
542
1208
  onDragStart: () => {
543
1209
  setState("dragging");
544
1210
  if (open) {
@@ -642,10 +1308,10 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
642
1308
  blockInstruction,
643
1309
  canDrop
644
1310
  ]);
645
- useEffect3(() => () => cancelExpand(), [
1311
+ useEffect4(() => () => cancelExpand(), [
646
1312
  cancelExpand
647
1313
  ]);
648
- const handleOpenToggle = useCallback3(() => onOpenChange?.({
1314
+ const handleOpenToggle = useCallback6(() => onOpenChange?.({
649
1315
  item,
650
1316
  path,
651
1317
  open: !open
@@ -655,7 +1321,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
655
1321
  path,
656
1322
  open
657
1323
  ]);
658
- const handleSelect = useCallback3((option = false) => {
1324
+ const handleSelect = useCallback6((option = false) => {
659
1325
  if (isBranch && (option || current)) {
660
1326
  handleOpenToggle();
661
1327
  } else if (canSelectItem) {
@@ -680,7 +1346,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
680
1346
  handleOpenToggle,
681
1347
  onSelect
682
1348
  ]);
683
- const handleKeyDown = useCallback3((event) => {
1349
+ const handleKeyDown = useCallback6((event) => {
684
1350
  switch (event.key) {
685
1351
  case "ArrowRight":
686
1352
  case "ArrowLeft":
@@ -693,7 +1359,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
693
1359
  handleOpenToggle,
694
1360
  handleSelect
695
1361
  ]);
696
- const handleItemHover = useCallback3(() => {
1362
+ const handleItemHover = useCallback6(() => {
697
1363
  onItemHover?.({
698
1364
  item
699
1365
  });
@@ -701,7 +1367,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
701
1367
  onItemHover,
702
1368
  item
703
1369
  ]);
704
- const handleContextMenu = useCallback3((event) => {
1370
+ const handleContextMenu = useCallback6((event) => {
705
1371
  event.preventDefault();
706
1372
  setMenuOpen(true);
707
1373
  }, [
@@ -717,51 +1383,52 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
717
1383
  onOpenChange,
718
1384
  onSelect
719
1385
  };
720
- return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(Treegrid.Row, {
1386
+ return /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(Treegrid.Row, {
721
1387
  ref: rowRef,
722
1388
  key: id,
723
1389
  id,
724
1390
  "aria-labelledby": `${id}__label`,
725
- parentOf: parentOf?.join(Treegrid.PARENT_OF_SEPARATOR),
1391
+ parentOf: parentOf?.join(TREEGRID_PARENT_OF_SEPARATOR),
726
1392
  "data-object-id": id,
727
1393
  "data-testid": testId,
728
1394
  // NOTE(thure): This is intentionally an empty string to for descendents to select by in the CSS
729
1395
  // without alerting the user (except for in the correct link element). See also:
730
1396
  // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current#description
731
1397
  "aria-current": current ? "" : void 0,
732
- classNames: mx4("grid grid-cols-subgrid col-[tree-row] mt-0.5 is-current:bg-active-surface", hoverableControls, hoverableFocusedKeyboardControls, hoverableFocusedWithinControls, hoverableDescriptionIcons, ghostFocusWithin, ghostHover, className),
1398
+ classNames: mx7("grid grid-cols-subgrid col-[tree-row] mt-0.5 is-current:bg-current-surface", hoverableControls, hoverableFocusedKeyboardControls, hoverableFocusedWithinControls, hoverableDescriptionIcons, ghostFocusWithin, ghostHover, className),
733
1399
  onKeyDown: handleKeyDown,
734
1400
  onMouseEnter: handleItemHover,
735
1401
  onContextMenu: handleContextMenu
736
- }, /* @__PURE__ */ React7.createElement("div", {
737
- role: "none",
1402
+ }, /* @__PURE__ */ React11.createElement("div", {
738
1403
  className: "indent relative grid grid-cols-subgrid col-[tree-row]",
739
1404
  style: paddingIndentation(level)
740
- }, /* @__PURE__ */ React7.createElement(Treegrid.Cell, {
1405
+ }, /* @__PURE__ */ React11.createElement(Treegrid.Cell, {
741
1406
  classNames: "flex items-center"
742
- }, /* @__PURE__ */ React7.createElement(TreeItemToggle, {
1407
+ }, /* @__PURE__ */ React11.createElement(TreeItemToggle, {
743
1408
  isBranch,
744
1409
  open,
745
1410
  onClick: handleOpenToggle
746
- }), /* @__PURE__ */ React7.createElement(TreeItemHeading, {
1411
+ }), /* @__PURE__ */ React11.createElement(TreeItemHeading, {
747
1412
  disabled,
748
1413
  current,
749
1414
  label,
750
1415
  className: headingClassName,
751
1416
  icon,
752
1417
  iconHue,
1418
+ count,
1419
+ modifiedCount,
753
1420
  onSelect: handleSelect,
754
1421
  ref: buttonRef
755
- })), Columns && /* @__PURE__ */ React7.createElement(Columns, {
1422
+ })), Columns && /* @__PURE__ */ React11.createElement(Columns, {
756
1423
  item,
757
1424
  path,
758
1425
  open,
759
1426
  menuOpen,
760
1427
  setMenuOpen
761
- }), instruction && /* @__PURE__ */ React7.createElement(NaturalTreeItem.DropIndicator, {
1428
+ }), instruction && /* @__PURE__ */ React11.createElement(NaturalTreeItem.DropIndicator, {
762
1429
  instruction,
763
1430
  gap: 2
764
- }))), open && childIds.map((childId, index) => /* @__PURE__ */ React7.createElement(TreeItemById, {
1431
+ }))), open && childIds.map((childId, index) => /* @__PURE__ */ React11.createElement(TreeItemById, {
765
1432
  key: childId,
766
1433
  id: childId,
767
1434
  path,
@@ -776,7 +1443,7 @@ var RawTreeItemById = ({ id, ...props }) => {
776
1443
  if (!item) {
777
1444
  return null;
778
1445
  }
779
- return /* @__PURE__ */ React7.createElement(TreeItem, {
1446
+ return /* @__PURE__ */ React11.createElement(TreeItem, {
780
1447
  item,
781
1448
  ...props
782
1449
  });
@@ -784,9 +1451,9 @@ var RawTreeItemById = ({ id, ...props }) => {
784
1451
  var TreeItemById = /* @__PURE__ */ memo3(RawTreeItemById);
785
1452
 
786
1453
  // src/components/Tree/Tree.tsx
787
- var Tree = ({ model, rootId, path, id, draggable: draggable3 = false, gridTemplateColumns = "[tree-row-start] 1fr min-content [tree-row-end]", classNames, levelOffset, renderColumns, blockInstruction, canDrop, canSelect, onOpenChange, onSelect, onItemHover }) => {
1454
+ var Tree = ({ classNames, model, rootId, path, id, draggable: draggable3 = false, gridTemplateColumns = "[tree-row-start] minmax(0, 1fr) min-content [tree-row-end]", levelOffset, renderColumns, blockInstruction, canDrop, canSelect, onOpenChange, onSelect, onItemHover }) => {
788
1455
  const childIds = useAtomValue2(model.childIds(rootId));
789
- const treePath = useMemo2(() => path ? [
1456
+ const treePath = useMemo3(() => path ? [
790
1457
  ...path,
791
1458
  id
792
1459
  ] : [
@@ -807,12 +1474,12 @@ var Tree = ({ model, rootId, path, id, draggable: draggable3 = false, gridTempla
807
1474
  onSelect,
808
1475
  onItemHover
809
1476
  };
810
- return /* @__PURE__ */ React8.createElement(Treegrid2.Root, {
1477
+ return /* @__PURE__ */ React12.createElement(Treegrid2.Root, {
811
1478
  gridTemplateColumns,
812
1479
  classNames
813
- }, /* @__PURE__ */ React8.createElement(TreeProvider, {
1480
+ }, /* @__PURE__ */ React12.createElement(TreeProvider, {
814
1481
  value: model
815
- }, childIds.map((childId, index) => /* @__PURE__ */ React8.createElement(TreeItemById, {
1482
+ }, childIds.map((childId, index) => /* @__PURE__ */ React12.createElement(TreeItemById, {
816
1483
  key: childId,
817
1484
  id: childId,
818
1485
  last: index === childIds.length - 1,
@@ -837,17 +1504,27 @@ var Path = {
837
1504
  };
838
1505
  export {
839
1506
  Accordion,
1507
+ Combobox,
840
1508
  DEFAULT_INDENTATION,
841
1509
  List,
1510
+ Listbox,
842
1511
  Path,
1512
+ Picker,
1513
+ Row,
1514
+ RowList,
843
1515
  Tree,
844
1516
  TreeDataSchema,
845
1517
  TreeItem,
846
1518
  TreeItemById,
847
1519
  TreeItemToggle,
848
1520
  TreeProvider,
1521
+ createListboxScope,
1522
+ createRowListScope,
849
1523
  isTreeData,
850
1524
  paddingIndentation,
1525
+ usePickerInputContext,
1526
+ usePickerItemContext,
1527
+ useRowListSelection,
851
1528
  useTree
852
1529
  };
853
1530
  //# sourceMappingURL=index.mjs.map