@dxos/react-ui-list 0.8.4-main.ead640a → 0.8.4-main.f466a3d56e

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