@dxos/react-ui-list 0.8.4-main.a4bbb77 → 0.8.4-main.abd8ff62ef

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