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