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

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