@dxos/react-ui-list 0.9.0 → 0.9.1-staging.ee54ba693a

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 (169) hide show
  1. package/dist/lib/browser/index.mjs +1508 -575
  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 +1508 -575
  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/aspects/index.d.ts +6 -0
  8. package/dist/types/src/aspects/index.d.ts.map +1 -0
  9. package/dist/types/src/aspects/useListDisclosure.d.ts +60 -0
  10. package/dist/types/src/aspects/useListDisclosure.d.ts.map +1 -0
  11. package/dist/types/src/aspects/useListDisclosure.test.d.ts +2 -0
  12. package/dist/types/src/aspects/useListDisclosure.test.d.ts.map +1 -0
  13. package/dist/types/src/aspects/useListGrid.d.ts +30 -0
  14. package/dist/types/src/aspects/useListGrid.d.ts.map +1 -0
  15. package/dist/types/src/aspects/useListGrid.test.d.ts +2 -0
  16. package/dist/types/src/aspects/useListGrid.test.d.ts.map +1 -0
  17. package/dist/types/src/aspects/useListNavigation.d.ts +70 -0
  18. package/dist/types/src/aspects/useListNavigation.d.ts.map +1 -0
  19. package/dist/types/src/aspects/useListNavigation.test.d.ts +2 -0
  20. package/dist/types/src/aspects/useListNavigation.test.d.ts.map +1 -0
  21. package/dist/types/src/aspects/useListSelection.d.ts +48 -0
  22. package/dist/types/src/aspects/useListSelection.d.ts.map +1 -0
  23. package/dist/types/src/aspects/useListSelection.test.d.ts +2 -0
  24. package/dist/types/src/aspects/useListSelection.test.d.ts.map +1 -0
  25. package/dist/types/src/aspects/useReorder.d.ts +103 -0
  26. package/dist/types/src/aspects/useReorder.d.ts.map +1 -0
  27. package/dist/types/src/components/Accordion/Accordion.d.ts +1 -1
  28. package/dist/types/src/components/Accordion/AccordionItem.d.ts +7 -3
  29. package/dist/types/src/components/Accordion/AccordionItem.d.ts.map +1 -1
  30. package/dist/types/src/components/Accordion/AccordionRoot.d.ts +1 -1
  31. package/dist/types/src/components/Accordion/AccordionRoot.d.ts.map +1 -1
  32. package/dist/types/src/components/Combobox/Combobox.d.ts +10 -3
  33. package/dist/types/src/components/Combobox/Combobox.d.ts.map +1 -1
  34. package/dist/types/src/components/DropIndicator/DropIndicator.d.ts +12 -0
  35. package/dist/types/src/components/DropIndicator/DropIndicator.d.ts.map +1 -0
  36. package/dist/types/src/components/DropIndicator/index.d.ts +2 -0
  37. package/dist/types/src/components/DropIndicator/index.d.ts.map +1 -0
  38. package/dist/types/src/components/Empty/Empty.d.ts +17 -0
  39. package/dist/types/src/components/Empty/Empty.d.ts.map +1 -0
  40. package/dist/types/src/components/Empty/Empty.stories.d.ts +18 -0
  41. package/dist/types/src/components/Empty/Empty.stories.d.ts.map +1 -0
  42. package/dist/types/src/components/Empty/index.d.ts +2 -0
  43. package/dist/types/src/components/Empty/index.d.ts.map +1 -0
  44. package/dist/types/src/components/List.theme.d.ts +193 -0
  45. package/dist/types/src/components/List.theme.d.ts.map +1 -0
  46. package/dist/types/src/components/Listbox/ListItemContent.d.ts +27 -0
  47. package/dist/types/src/components/Listbox/ListItemContent.d.ts.map +1 -0
  48. package/dist/types/src/components/Listbox/ListItemContent.stories.d.ts +24 -0
  49. package/dist/types/src/components/Listbox/ListItemContent.stories.d.ts.map +1 -0
  50. package/dist/types/src/components/Listbox/Listbox.d.ts +77 -20
  51. package/dist/types/src/components/Listbox/Listbox.d.ts.map +1 -1
  52. package/dist/types/src/components/Listbox/Listbox.stories.d.ts +31 -3
  53. package/dist/types/src/components/Listbox/Listbox.stories.d.ts.map +1 -1
  54. package/dist/types/src/components/OrderedList/OrderedList.d.ts +49 -0
  55. package/dist/types/src/components/OrderedList/OrderedList.d.ts.map +1 -0
  56. package/dist/types/src/components/OrderedList/OrderedList.stories.d.ts +11 -0
  57. package/dist/types/src/components/OrderedList/OrderedList.stories.d.ts.map +1 -0
  58. package/dist/types/src/components/OrderedList/OrderedList.test.d.ts +2 -0
  59. package/dist/types/src/components/OrderedList/OrderedList.test.d.ts.map +1 -0
  60. package/dist/types/src/components/OrderedList/OrderedListItem.d.ts +94 -0
  61. package/dist/types/src/components/OrderedList/OrderedListItem.d.ts.map +1 -0
  62. package/dist/types/src/components/OrderedList/OrderedListRoot.d.ts +73 -0
  63. package/dist/types/src/components/OrderedList/OrderedListRoot.d.ts.map +1 -0
  64. package/dist/types/src/components/OrderedList/index.d.ts +2 -0
  65. package/dist/types/src/components/OrderedList/index.d.ts.map +1 -0
  66. package/dist/types/src/components/Picker/Picker.d.ts +12 -4
  67. package/dist/types/src/components/Picker/Picker.d.ts.map +1 -1
  68. package/dist/types/src/components/Picker/index.d.ts +1 -1
  69. package/dist/types/src/components/Picker/index.d.ts.map +1 -1
  70. package/dist/types/src/components/Tree/Tree.d.ts +1 -1
  71. package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
  72. package/dist/types/src/components/Tree/Tree.stories.d.ts +5 -2
  73. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
  74. package/dist/types/src/components/Tree/TreeContext.d.ts +2 -0
  75. package/dist/types/src/components/Tree/TreeContext.d.ts.map +1 -1
  76. package/dist/types/src/components/Tree/TreeDropIndicator.d.ts +10 -0
  77. package/dist/types/src/components/Tree/TreeDropIndicator.d.ts.map +1 -0
  78. package/dist/types/src/components/Tree/TreeItem.d.ts.map +1 -1
  79. package/dist/types/src/components/Tree/TreeItemHeading.d.ts.map +1 -1
  80. package/dist/types/src/components/Tree/testing.d.ts +4 -1
  81. package/dist/types/src/components/Tree/testing.d.ts.map +1 -1
  82. package/dist/types/src/components/Treegrid/Treegrid.d.ts +33 -0
  83. package/dist/types/src/components/Treegrid/Treegrid.d.ts.map +1 -0
  84. package/dist/types/src/components/Treegrid/Treegrid.stories.d.ts +11 -0
  85. package/dist/types/src/components/Treegrid/Treegrid.stories.d.ts.map +1 -0
  86. package/dist/types/src/components/Treegrid/Treegrid.theme.d.ts +37 -0
  87. package/dist/types/src/components/Treegrid/Treegrid.theme.d.ts.map +1 -0
  88. package/dist/types/src/components/Treegrid/index.d.ts +2 -0
  89. package/dist/types/src/components/Treegrid/index.d.ts.map +1 -0
  90. package/dist/types/src/components/index.d.ts +4 -2
  91. package/dist/types/src/components/index.d.ts.map +1 -1
  92. package/dist/types/src/index.d.ts +1 -0
  93. package/dist/types/src/index.d.ts.map +1 -1
  94. package/dist/types/src/vitest-setup.d.ts +2 -0
  95. package/dist/types/src/vitest-setup.d.ts.map +1 -0
  96. package/dist/types/tsconfig.tsbuildinfo +1 -1
  97. package/package.json +26 -22
  98. package/src/aspects/index.ts +9 -0
  99. package/src/aspects/useListDisclosure.test.ts +72 -0
  100. package/src/aspects/useListDisclosure.ts +160 -0
  101. package/src/aspects/useListGrid.test.ts +41 -0
  102. package/src/aspects/useListGrid.ts +61 -0
  103. package/src/aspects/useListNavigation.test.ts +44 -0
  104. package/src/aspects/useListNavigation.ts +162 -0
  105. package/src/aspects/useListSelection.test.ts +101 -0
  106. package/src/aspects/useListSelection.ts +162 -0
  107. package/src/aspects/useReorder.ts +370 -0
  108. package/src/components/Accordion/Accordion.stories.tsx +1 -1
  109. package/src/components/Accordion/AccordionItem.tsx +36 -13
  110. package/src/components/Accordion/AccordionRoot.tsx +4 -1
  111. package/src/components/Combobox/Combobox.tsx +46 -38
  112. package/src/components/DropIndicator/DropIndicator.tsx +74 -0
  113. package/src/components/DropIndicator/index.ts +5 -0
  114. package/src/components/Empty/Empty.stories.tsx +37 -0
  115. package/src/components/Empty/Empty.tsx +41 -0
  116. package/src/components/Empty/index.ts +5 -0
  117. package/src/components/List.theme.ts +99 -0
  118. package/src/components/Listbox/ListItemContent.stories.tsx +41 -0
  119. package/src/components/Listbox/ListItemContent.tsx +49 -0
  120. package/src/components/Listbox/Listbox.stories.tsx +269 -20
  121. package/src/components/Listbox/Listbox.tsx +343 -143
  122. package/src/components/OrderedList/OrderedList.stories.tsx +379 -0
  123. package/src/components/OrderedList/OrderedList.test.tsx +59 -0
  124. package/src/components/OrderedList/OrderedList.tsx +63 -0
  125. package/src/components/OrderedList/OrderedListItem.tsx +348 -0
  126. package/src/components/OrderedList/OrderedListRoot.tsx +176 -0
  127. package/src/components/OrderedList/index.ts +5 -0
  128. package/src/components/Picker/Picker.tsx +25 -15
  129. package/src/components/Picker/index.ts +1 -1
  130. package/src/components/Tree/Tree.stories.tsx +39 -15
  131. package/src/components/Tree/Tree.tsx +13 -3
  132. package/src/components/Tree/TreeContext.tsx +2 -0
  133. package/src/components/Tree/TreeDropIndicator.tsx +72 -0
  134. package/src/components/Tree/TreeItem.tsx +45 -3
  135. package/src/components/Tree/TreeItemHeading.tsx +3 -4
  136. package/src/components/Tree/testing.ts +19 -14
  137. package/src/components/Treegrid/Treegrid.stories.tsx +132 -0
  138. package/src/components/Treegrid/Treegrid.theme.ts +38 -0
  139. package/src/components/Treegrid/Treegrid.tsx +187 -0
  140. package/src/components/{List → Treegrid}/index.ts +1 -1
  141. package/src/components/index.ts +4 -2
  142. package/src/index.ts +1 -0
  143. package/src/vitest-setup.ts +11 -0
  144. package/dist/types/src/components/List/List.d.ts +0 -40
  145. package/dist/types/src/components/List/List.d.ts.map +0 -1
  146. package/dist/types/src/components/List/List.stories.d.ts +0 -18
  147. package/dist/types/src/components/List/List.stories.d.ts.map +0 -1
  148. package/dist/types/src/components/List/ListItem.d.ts +0 -49
  149. package/dist/types/src/components/List/ListItem.d.ts.map +0 -1
  150. package/dist/types/src/components/List/ListRoot.d.ts +0 -29
  151. package/dist/types/src/components/List/ListRoot.d.ts.map +0 -1
  152. package/dist/types/src/components/List/index.d.ts +0 -2
  153. package/dist/types/src/components/List/index.d.ts.map +0 -1
  154. package/dist/types/src/components/List/testing.d.ts +0 -15
  155. package/dist/types/src/components/List/testing.d.ts.map +0 -1
  156. package/dist/types/src/components/RowList/RowList.d.ts +0 -61
  157. package/dist/types/src/components/RowList/RowList.d.ts.map +0 -1
  158. package/dist/types/src/components/RowList/RowList.stories.d.ts +0 -35
  159. package/dist/types/src/components/RowList/RowList.stories.d.ts.map +0 -1
  160. package/dist/types/src/components/RowList/index.d.ts +0 -3
  161. package/dist/types/src/components/RowList/index.d.ts.map +0 -1
  162. package/src/components/List/List.stories.tsx +0 -129
  163. package/src/components/List/List.tsx +0 -47
  164. package/src/components/List/ListItem.tsx +0 -287
  165. package/src/components/List/ListRoot.tsx +0 -106
  166. package/src/components/List/testing.ts +0 -31
  167. package/src/components/RowList/RowList.stories.tsx +0 -163
  168. package/src/components/RowList/RowList.tsx +0 -350
  169. package/src/components/RowList/index.ts +0 -6
@@ -1,3 +1,580 @@
1
+ // src/aspects/useListDisclosure.ts
2
+ import { useCallback, useEffect, useId, useRef, useState } from "react";
3
+ var isMulti = (value) => value instanceof Set;
4
+ var useListDisclosure = (opts) => {
5
+ const { mode, value, defaultValue, onValueChange } = opts;
6
+ const idPrefix = useId();
7
+ const wasControlledRef = useRef(Object.prototype.hasOwnProperty.call(opts, "value"));
8
+ if (Object.prototype.hasOwnProperty.call(opts, "value")) {
9
+ wasControlledRef.current = true;
10
+ }
11
+ const isControlled = wasControlledRef.current;
12
+ const [internalValue, setInternalValue] = useState(() => defaultValue);
13
+ useEffect(() => {
14
+ if (isControlled) {
15
+ setInternalValue(value);
16
+ }
17
+ }, [
18
+ isControlled,
19
+ value
20
+ ]);
21
+ const resolvedValue = isControlled ? value : internalValue;
22
+ const isExpanded = useCallback((id) => {
23
+ if (mode === "multi") {
24
+ return isMulti(resolvedValue) && resolvedValue.has(id);
25
+ }
26
+ return resolvedValue === id;
27
+ }, [
28
+ mode,
29
+ resolvedValue
30
+ ]);
31
+ const setExpanded = useCallback((id, expanded) => {
32
+ const computeNext = () => {
33
+ if (mode === "multi") {
34
+ const current = isMulti(resolvedValue) ? resolvedValue : /* @__PURE__ */ new Set();
35
+ const next2 = new Set(current);
36
+ if (expanded) {
37
+ next2.add(id);
38
+ } else {
39
+ next2.delete(id);
40
+ }
41
+ return next2;
42
+ }
43
+ return expanded ? id : void 0;
44
+ };
45
+ const next = computeNext();
46
+ if (!isControlled) {
47
+ setInternalValue(next);
48
+ }
49
+ onValueChange?.(next);
50
+ }, [
51
+ mode,
52
+ resolvedValue,
53
+ isControlled,
54
+ onValueChange
55
+ ]);
56
+ const bind = useCallback((id) => {
57
+ const expanded = isExpanded(id);
58
+ const triggerId = `${idPrefix}-${id}-trigger`;
59
+ const panelId = `${idPrefix}-${id}-panel`;
60
+ return {
61
+ expanded,
62
+ toggle: () => setExpanded(id, !expanded),
63
+ triggerId,
64
+ panelId,
65
+ triggerProps: {
66
+ "id": triggerId,
67
+ "aria-expanded": expanded,
68
+ "aria-controls": panelId,
69
+ "onClick": () => setExpanded(id, !expanded)
70
+ },
71
+ panelProps: {
72
+ "id": panelId,
73
+ "role": "region",
74
+ "aria-labelledby": triggerId
75
+ }
76
+ };
77
+ }, [
78
+ idPrefix,
79
+ isExpanded,
80
+ setExpanded
81
+ ]);
82
+ return {
83
+ bind
84
+ };
85
+ };
86
+
87
+ // src/aspects/useListGrid.ts
88
+ import { useMemo } from "react";
89
+ var useListGrid = ({ actionSlots = 0, expandable = false, trailing = false } = {}) => {
90
+ const gridTemplateColumns = useMemo(() => {
91
+ const tracks = [
92
+ "var(--dx-rail-item)",
93
+ "1fr"
94
+ ];
95
+ for (let index = 0; index < actionSlots; index++) {
96
+ tracks.push("var(--dx-rail-item)");
97
+ }
98
+ if (expandable) {
99
+ tracks.push("var(--dx-rail-item)");
100
+ }
101
+ if (trailing) {
102
+ tracks.push("var(--dx-rail-item)");
103
+ }
104
+ return tracks.join(" ");
105
+ }, [
106
+ actionSlots,
107
+ expandable,
108
+ trailing
109
+ ]);
110
+ return {
111
+ rowProps: {
112
+ className: "grid items-start gap-1",
113
+ style: {
114
+ gridTemplateColumns
115
+ }
116
+ }
117
+ };
118
+ };
119
+
120
+ // src/aspects/useListNavigation.ts
121
+ import { useArrowNavigationGroup } from "@fluentui/react-tabster";
122
+ import { useCallback as useCallback2, useMemo as useMemo2 } from "react";
123
+ var containerRoleByMode = {
124
+ list: "list",
125
+ listbox: "listbox",
126
+ grid: "grid"
127
+ };
128
+ var itemRoleByMode = {
129
+ list: "listitem",
130
+ listbox: "option",
131
+ grid: "row"
132
+ };
133
+ var defaultAxisByMode = {
134
+ list: "vertical",
135
+ listbox: "vertical",
136
+ grid: "grid"
137
+ };
138
+ var findListboxEntryTarget = (container) => {
139
+ return container.querySelector('[role="option"][aria-selected="true"]:not([aria-disabled="true"])') ?? container.querySelector('[role="option"]:not([aria-disabled="true"])');
140
+ };
141
+ var useListNavigation = ({ mode, axis, memorizeCurrent = true }) => {
142
+ const tabsterAttrs = useArrowNavigationGroup({
143
+ axis: axis ?? defaultAxisByMode[mode],
144
+ memorizeCurrent
145
+ });
146
+ const handleFocus = useCallback2((event) => {
147
+ if (event.target !== event.currentTarget) {
148
+ return;
149
+ }
150
+ if (mode !== "listbox") {
151
+ return;
152
+ }
153
+ const target = findListboxEntryTarget(event.currentTarget);
154
+ target?.focus();
155
+ }, [
156
+ mode
157
+ ]);
158
+ const orientation = mode === "grid" ? void 0 : axis === "horizontal" ? "horizontal" : "vertical";
159
+ const containerProps = useMemo2(() => ({
160
+ role: containerRoleByMode[mode],
161
+ ...orientation && {
162
+ "aria-orientation": orientation
163
+ },
164
+ ...tabsterAttrs,
165
+ onFocus: handleFocus
166
+ }), [
167
+ mode,
168
+ orientation,
169
+ tabsterAttrs,
170
+ handleFocus
171
+ ]);
172
+ const itemRole = itemRoleByMode[mode];
173
+ const itemTabIndex = mode === "listbox" ? 0 : -1;
174
+ const itemProps = useCallback2(({ disabled } = {}) => ({
175
+ role: itemRole,
176
+ tabIndex: itemTabIndex,
177
+ ...disabled && {
178
+ "aria-disabled": true
179
+ }
180
+ }), [
181
+ itemRole,
182
+ itemTabIndex
183
+ ]);
184
+ return {
185
+ containerProps,
186
+ itemProps
187
+ };
188
+ };
189
+
190
+ // src/aspects/useListSelection.ts
191
+ import { useCallback as useCallback3, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
192
+ var isMulti2 = (value) => value instanceof Set;
193
+ var useListSelection = (opts) => {
194
+ const { mode, value, defaultValue, onValueChange, followsFocus } = opts;
195
+ const wasControlledRef = useRef2(Object.prototype.hasOwnProperty.call(opts, "value"));
196
+ if (Object.prototype.hasOwnProperty.call(opts, "value")) {
197
+ wasControlledRef.current = true;
198
+ }
199
+ const isControlled = wasControlledRef.current;
200
+ const [internalValue, setInternalValue] = useState2(() => defaultValue);
201
+ useEffect2(() => {
202
+ if (isControlled) {
203
+ setInternalValue(value);
204
+ }
205
+ }, [
206
+ isControlled,
207
+ value
208
+ ]);
209
+ const resolvedValue = isControlled ? value : internalValue;
210
+ const setResolvedValue = useCallback3((next) => {
211
+ if (!isControlled) {
212
+ setInternalValue(next);
213
+ }
214
+ onValueChange?.(next);
215
+ }, [
216
+ isControlled,
217
+ onValueChange,
218
+ mode
219
+ ]);
220
+ const isSelected = useCallback3((id) => {
221
+ if (mode === "multi") {
222
+ return isMulti2(resolvedValue) && resolvedValue.has(id);
223
+ }
224
+ return resolvedValue === id;
225
+ }, [
226
+ mode,
227
+ resolvedValue
228
+ ]);
229
+ const setSelected = useCallback3((id, selected) => {
230
+ if (mode === "multi") {
231
+ const current = isMulti2(resolvedValue) ? resolvedValue : /* @__PURE__ */ new Set();
232
+ const next = new Set(current);
233
+ if (selected) {
234
+ next.add(id);
235
+ } else {
236
+ next.delete(id);
237
+ }
238
+ setResolvedValue(next);
239
+ } else {
240
+ setResolvedValue(selected ? id : void 0);
241
+ }
242
+ }, [
243
+ mode,
244
+ resolvedValue,
245
+ setResolvedValue
246
+ ]);
247
+ const followFocusDefault = mode === "single";
248
+ const trackFocus = followsFocus ?? followFocusDefault;
249
+ const bind = useCallback3((id, { disabled } = {}) => {
250
+ const selected = isSelected(id);
251
+ return {
252
+ selected,
253
+ toggle: () => {
254
+ if (!disabled) {
255
+ setSelected(id, mode === "multi" ? !selected : true);
256
+ }
257
+ },
258
+ rowProps: {
259
+ "aria-selected": selected,
260
+ "onClick": () => {
261
+ if (disabled) {
262
+ return;
263
+ }
264
+ setSelected(id, mode === "multi" ? !selected : true);
265
+ },
266
+ ...trackFocus && {
267
+ onFocus: (event) => {
268
+ if (disabled || selected) {
269
+ return;
270
+ }
271
+ const container = event.currentTarget?.closest?.('[role="listbox"],[role="list"],[role="grid"]');
272
+ if (container && !container.contains(event.relatedTarget)) {
273
+ return;
274
+ }
275
+ setSelected(id, true);
276
+ }
277
+ }
278
+ }
279
+ };
280
+ }, [
281
+ isSelected,
282
+ mode,
283
+ setSelected,
284
+ trackFocus
285
+ ]);
286
+ return {
287
+ bind
288
+ };
289
+ };
290
+
291
+ // src/aspects/useReorder.ts
292
+ import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
293
+ import { attachClosestEdge, extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
294
+ import { getReorderDestinationIndex } from "@atlaskit/pragmatic-drag-and-drop-hitbox/util/get-reorder-destination-index";
295
+ import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
296
+ import { draggable, dropTargetForElements, monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
297
+ import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview";
298
+ import { useCallback as useCallback4, useEffect as useEffect3, useMemo as useMemo3, useRef as useRef3, useState as useState3 } from "react";
299
+ var REORDER_LIST_KEY = "__dxosReorderListId";
300
+ var reorderListIdCounter = 0;
301
+ var allocateReorderListId = () => `reorder-${++reorderListIdCounter}`;
302
+ var IDLE = {
303
+ type: "idle"
304
+ };
305
+ var useReorderList = ({ items, getId, onMove, axis = "vertical", readonly = false, getInitialData, canDrop, getDragPreview }) => {
306
+ const listIdRef = useRef3(null);
307
+ if (!listIdRef.current) {
308
+ listIdRef.current = allocateReorderListId();
309
+ }
310
+ const listId = listIdRef.current;
311
+ const itemsRef = useRef3(items);
312
+ itemsRef.current = items;
313
+ const getIdRef = useRef3(getId);
314
+ getIdRef.current = getId;
315
+ const onMoveRef = useRef3(onMove);
316
+ onMoveRef.current = onMove;
317
+ const canDropRef = useRef3(canDrop);
318
+ canDropRef.current = canDrop;
319
+ const getInitialDataRef = useRef3(getInitialData);
320
+ getInitialDataRef.current = getInitialData;
321
+ const getDragPreviewRef = useRef3(getDragPreview);
322
+ getDragPreviewRef.current = getDragPreview;
323
+ const readonlyRef = useRef3(readonly);
324
+ readonlyRef.current = readonly;
325
+ const [active, setActive] = useState3(null);
326
+ const findIndex = useCallback4((id) => {
327
+ return itemsRef.current.findIndex((item) => getIdRef.current(item) === id);
328
+ }, []);
329
+ const findIndexFromPayload = useCallback4((data) => {
330
+ if (!data || data[REORDER_LIST_KEY] !== listId) {
331
+ return -1;
332
+ }
333
+ const id = data.id;
334
+ return id ? findIndex(id) : -1;
335
+ }, [
336
+ listId,
337
+ findIndex
338
+ ]);
339
+ useEffect3(() => {
340
+ return monitorForElements({
341
+ canMonitor: ({ source }) => {
342
+ if (canDropRef.current) {
343
+ return canDropRef.current({
344
+ source
345
+ });
346
+ }
347
+ return source.data[REORDER_LIST_KEY] === listId;
348
+ },
349
+ onDrop: ({ location, source }) => {
350
+ const target = location.current.dropTargets[0];
351
+ if (!target) {
352
+ return;
353
+ }
354
+ const sourceIdx = findIndexFromPayload(source.data);
355
+ const targetIdx = findIndexFromPayload(target.data);
356
+ if (sourceIdx < 0 || targetIdx < 0) {
357
+ return;
358
+ }
359
+ const destinationIndex = getReorderDestinationIndex({
360
+ closestEdgeOfTarget: extractClosestEdge(target.data),
361
+ startIndex: sourceIdx,
362
+ indexOfTarget: targetIdx,
363
+ axis
364
+ });
365
+ onMoveRef.current(sourceIdx, destinationIndex);
366
+ }
367
+ });
368
+ }, [
369
+ listId,
370
+ axis,
371
+ findIndexFromPayload
372
+ ]);
373
+ const controller = useMemo3(() => ({
374
+ listId,
375
+ getItem: (id) => {
376
+ const index = findIndex(id);
377
+ if (index < 0) {
378
+ return null;
379
+ }
380
+ return {
381
+ item: itemsRef.current[index],
382
+ index
383
+ };
384
+ },
385
+ bindItem: (id, refs, onItemState) => {
386
+ const lookup = () => {
387
+ const index2 = findIndex(id);
388
+ return {
389
+ item: itemsRef.current[index2],
390
+ index: index2
391
+ };
392
+ };
393
+ const { item, index } = lookup();
394
+ if (!item && index < 0) {
395
+ return () => {
396
+ };
397
+ }
398
+ const allowedEdges = axis === "vertical" ? [
399
+ "top",
400
+ "bottom"
401
+ ] : [
402
+ "left",
403
+ "right"
404
+ ];
405
+ return combine(draggable({
406
+ element: refs.row,
407
+ dragHandle: refs.handle,
408
+ canDrag: () => !readonlyRef.current,
409
+ getInitialData: () => {
410
+ const current = lookup();
411
+ return {
412
+ [REORDER_LIST_KEY]: listId,
413
+ id,
414
+ ...getInitialDataRef.current?.(current.item, current.index) ?? {}
415
+ };
416
+ },
417
+ onGenerateDragPreview: getDragPreviewRef.current ? ({ nativeSetDragImage, source }) => {
418
+ const rect = source.element.getBoundingClientRect();
419
+ setCustomNativeDragPreview({
420
+ nativeSetDragImage,
421
+ getOffset: ({ container }) => ({
422
+ x: 20,
423
+ y: container.getBoundingClientRect().height / 2
424
+ }),
425
+ render: ({ container }) => {
426
+ container.style.width = `${rect.width}px`;
427
+ onItemState({
428
+ type: "preview",
429
+ container
430
+ });
431
+ const current = lookup();
432
+ setActive({
433
+ id,
434
+ item: current.item,
435
+ container
436
+ });
437
+ return () => {
438
+ onItemState(IDLE);
439
+ setActive(null);
440
+ };
441
+ }
442
+ });
443
+ } : void 0,
444
+ onDragStart: () => {
445
+ onItemState({
446
+ type: "dragging"
447
+ });
448
+ const current = lookup();
449
+ setActive({
450
+ id,
451
+ item: current.item,
452
+ container: refs.row
453
+ });
454
+ },
455
+ onDrop: () => {
456
+ onItemState(IDLE);
457
+ setActive(null);
458
+ }
459
+ }), dropTargetForElements({
460
+ element: refs.row,
461
+ canDrop: ({ source }) => {
462
+ if (source.element === refs.row) {
463
+ return false;
464
+ }
465
+ if (canDropRef.current) {
466
+ return canDropRef.current({
467
+ source
468
+ });
469
+ }
470
+ return source.data[REORDER_LIST_KEY] === listId;
471
+ },
472
+ getData: ({ input }) => attachClosestEdge({
473
+ [REORDER_LIST_KEY]: listId,
474
+ id
475
+ }, {
476
+ element: refs.row,
477
+ input,
478
+ allowedEdges
479
+ }),
480
+ getIsSticky: () => true,
481
+ onDragEnter: ({ self }) => {
482
+ onItemState({
483
+ type: "dragging-over",
484
+ closestEdge: extractClosestEdge(self.data)
485
+ });
486
+ },
487
+ onDrag: ({ self }) => {
488
+ onItemState({
489
+ type: "dragging-over",
490
+ closestEdge: extractClosestEdge(self.data)
491
+ });
492
+ },
493
+ onDragLeave: () => onItemState(IDLE),
494
+ onDrop: () => onItemState(IDLE)
495
+ }));
496
+ }
497
+ }), [
498
+ listId,
499
+ axis,
500
+ findIndex
501
+ ]);
502
+ return {
503
+ controller,
504
+ active,
505
+ listId
506
+ };
507
+ };
508
+ var useReorderItem = (controller, id) => {
509
+ const [state, setState] = useState3(IDLE);
510
+ const rowElement = useRef3(null);
511
+ const handleElement = useRef3(null);
512
+ const cleanupRef = useRef3(null);
513
+ const tryRegister = useCallback4(() => {
514
+ if (!rowElement.current || !handleElement.current) {
515
+ return;
516
+ }
517
+ cleanupRef.current?.();
518
+ cleanupRef.current = controller.bindItem(id, {
519
+ row: rowElement.current,
520
+ handle: handleElement.current
521
+ }, setState);
522
+ }, [
523
+ controller,
524
+ id
525
+ ]);
526
+ const teardown = useCallback4(() => {
527
+ cleanupRef.current?.();
528
+ cleanupRef.current = null;
529
+ setState(IDLE);
530
+ }, []);
531
+ useEffect3(() => {
532
+ tryRegister();
533
+ return teardown;
534
+ }, [
535
+ tryRegister,
536
+ teardown
537
+ ]);
538
+ const rowRef = useCallback4((node) => {
539
+ rowElement.current = node;
540
+ if (node) {
541
+ tryRegister();
542
+ } else {
543
+ teardown();
544
+ }
545
+ }, [
546
+ tryRegister,
547
+ teardown
548
+ ]);
549
+ const handleRef = useCallback4((node) => {
550
+ handleElement.current = node;
551
+ if (node && rowElement.current) {
552
+ tryRegister();
553
+ } else if (!node) {
554
+ teardown();
555
+ }
556
+ }, [
557
+ tryRegister,
558
+ teardown
559
+ ]);
560
+ return {
561
+ rowRef,
562
+ handleRef,
563
+ state,
564
+ isDragging: state.type === "dragging",
565
+ closestEdge: state.type === "dragging-over" ? state.closestEdge : null
566
+ };
567
+ };
568
+ var useReorderAutoScroll = () => {
569
+ const cleanupRef = useRef3(null);
570
+ return useCallback4((node) => {
571
+ cleanupRef.current?.();
572
+ cleanupRef.current = node ? autoScrollForElements({
573
+ element: node
574
+ }) : null;
575
+ }, []);
576
+ };
577
+
1
578
  // src/components/Accordion/AccordionItem.tsx
2
579
  import * as AccordionPrimitive2 from "@radix-ui/react-accordion";
3
580
  import { createContext as createContext2 } from "@radix-ui/react-context";
@@ -5,6 +582,82 @@ import React2 from "react";
5
582
  import { Icon } from "@dxos/react-ui";
6
583
  import { mx as mx2 } from "@dxos/ui-theme";
7
584
 
585
+ // src/components/List.theme.ts
586
+ import { tv } from "@dxos/ui-theme";
587
+ var listStyles = tv({
588
+ slots: {
589
+ //
590
+ // Accordion
591
+ //
592
+ accordionItem: "overflow-hidden",
593
+ // Row trigger: spans the full width and pins the trailing caret to the inline-end edge.
594
+ accordionTrigger: "group flex items-start justify-between gap-2 p-2 dx-focus-ring-inset w-full text-start",
595
+ // Leading / trailing icon wrappers: fixed height so they sit on the centerline of the first
596
+ // content line even when the header spans multiple lines.
597
+ accordionTriggerIcon: "flex items-center h-6 shrink-0",
598
+ accordionTriggerContent: "min-w-0 flex-1",
599
+ // Slide animations are driven by Radix Accordion's data-state attribute.
600
+ accordionBody: "overflow-hidden data-[state=closed]:animate-slide-up data-[state=open]:animate-slide-down",
601
+ accordionBodyContent: "p-2",
602
+ //
603
+ // Listbox
604
+ //
605
+ listboxViewport: "dx-container",
606
+ listboxContent: "flex flex-col",
607
+ // `dx-selected` pairs with `aria-selected="true"` set per-option (see
608
+ // `ui-theme/src/css/components/state.md`). `outline-none` removes the native focus
609
+ // ring; Tabster / `dx-focus-ring` handles keyboard focus at the container level.
610
+ listboxItem: "flex items-center dx-hover dx-selected px-3 py-2 cursor-pointer outline-none",
611
+ listboxItemLabel: "grow truncate",
612
+ //
613
+ // OrderedList
614
+ //
615
+ orderedListViewport: "dx-container",
616
+ orderedListContent: "flex flex-col",
617
+ // `dx-current` enables `aria-current` row styling (not listbox/option semantics).
618
+ orderedListItem: "relative dx-current",
619
+ // Bordered column wrapping title + detail panel in the master-detail layout.
620
+ orderedListDetailColumn: "flex flex-col ring-1 ring-subdued-separator rounded-sm overflow-hidden",
621
+ // `min-h` matches the shared rail-item track so handles, title, and caret share a baseline.
622
+ orderedListDetailTitleRow: "flex items-center min-h-[var(--dx-rail-item)]",
623
+ orderedListDetailPanel: "px-2 pb-2",
624
+ orderedListTitle: "flex grow items-center truncate cursor-pointer",
625
+ //
626
+ // Picker
627
+ //
628
+ // `px-[var(--gutter,…)]` aligns padding with sibling `Column.Center` content, falling back to
629
+ // 0.75rem when not nested under `Column.Root`.
630
+ pickerItem: "dx-hover dx-selected px-[var(--gutter,0.75rem)] py-1 cursor-pointer select-none",
631
+ //
632
+ // Combobox
633
+ //
634
+ // `m-form-chrome mb-0` mirrors the rest of the form-chrome padding convention.
635
+ comboboxInput: "m-form-chrome mb-0 w-[calc(100%-2*var(--spacing-form-chrome))]",
636
+ comboboxList: "py-form-chrome",
637
+ // Trigger value / placeholder text — grows and truncates; subdued when placeholder.
638
+ comboboxTriggerText: "font-normal text-start flex-1 min-w-0 truncate me-2",
639
+ // Item row adds flex layout; `dx-hover`/`dx-selected` and padding come from `Picker.Item`.
640
+ comboboxItem: "flex w-full gap-2 items-center",
641
+ comboboxItemDescription: "text-sm text-description truncate",
642
+ //
643
+ // ItemContent
644
+ //
645
+ // Two-column grid: fixed rail-item icon track + flexible content track.
646
+ itemContentRoot: "grid grid-cols-[var(--dx-rail-item)_minmax(0,1fr)] items-center gap-x-2 is-full min-is-0",
647
+ itemContentIcon: "col-start-1 row-start-1 place-self-center",
648
+ itemContentTitle: "col-start-2 row-start-1 min-is-0 truncate",
649
+ itemContentDescription: "col-start-2 row-start-2 min-is-0 truncate text-sm text-description",
650
+ //
651
+ // Empty
652
+ //
653
+ empty: "flex flex-col items-center justify-center gap-2 p-4 text-sm text-center text-description"
654
+ }
655
+ });
656
+ var listTheme = {
657
+ styles: listStyles
658
+ };
659
+ var listSlots = Object.keys(listTheme.styles());
660
+
8
661
  // src/components/Accordion/AccordionRoot.tsx
9
662
  import * as AccordionPrimitive from "@radix-ui/react-accordion";
10
663
  import { createContext } from "@radix-ui/react-context";
@@ -29,6 +682,7 @@ var AccordionRoot = ({ classNames, items, getId = defaultGetId, children, value,
29
682
 
30
683
  // src/components/Accordion/AccordionItem.tsx
31
684
  var ACCORDION_ITEM_NAME = "AccordionItem";
685
+ var styles = listTheme.styles();
32
686
  var [AccordionItemProvider, useDxAccordionItemContext] = createContext2(ACCORDION_ITEM_NAME);
33
687
  var AccordionItem = ({ children, classNames, item }) => {
34
688
  const { getId } = useAccordionContext(ACCORDION_ITEM_NAME);
@@ -36,26 +690,41 @@ var AccordionItem = ({ children, classNames, item }) => {
36
690
  item
37
691
  }, /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Item, {
38
692
  value: getId(item),
39
- className: mx2("overflow-hidden", classNames)
693
+ className: styles.accordionItem({
694
+ class: mx2(classNames)
695
+ })
40
696
  }, children));
41
697
  };
42
- var AccordionItemHeader = ({ classNames, children, ...props }) => {
698
+ var AccordionItemHeader = ({ classNames, children, icon, hover, ...props }) => {
43
699
  return /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Header, {
44
700
  ...props,
45
701
  className: mx2(classNames)
46
702
  }, /* @__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, {
703
+ className: styles.accordionTrigger({
704
+ class: hover && "dx-hover"
705
+ })
706
+ }, icon && /* @__PURE__ */ React2.createElement("span", {
707
+ className: styles.accordionTriggerIcon()
708
+ }, /* @__PURE__ */ React2.createElement(Icon, {
709
+ icon,
710
+ size: 4
711
+ })), /* @__PURE__ */ React2.createElement("div", {
712
+ className: styles.accordionTriggerContent()
713
+ }, children), /* @__PURE__ */ React2.createElement("span", {
714
+ className: styles.accordionTriggerIcon()
715
+ }, /* @__PURE__ */ React2.createElement(Icon, {
49
716
  icon: "ph--caret-right--regular",
50
717
  size: 4,
51
718
  classNames: "transition-transform duration-200 group-data-[state=open]:rotate-90"
52
- })));
719
+ }))));
53
720
  };
54
721
  var AccordionItemBody = ({ children, classNames }) => {
55
722
  return /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Content, {
56
- className: "overflow-hidden data-[state=closed]:animate-slide-up data-[state=open]:animate-slide-down"
723
+ className: styles.accordionBody()
57
724
  }, /* @__PURE__ */ React2.createElement("div", {
58
- className: mx2("p-2", classNames)
725
+ className: styles.accordionBodyContent({
726
+ class: mx2(classNames)
727
+ })
59
728
  }, children));
60
729
  };
61
730
 
@@ -70,14 +739,14 @@ var Accordion = {
70
739
  // src/components/Combobox/Combobox.tsx
71
740
  import { createContext as createContext4 } from "@radix-ui/react-context";
72
741
  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";
742
+ import React4, { forwardRef as forwardRef2, useCallback as useCallback6 } from "react";
743
+ import { Button, Icon as Icon2, Popover, ScrollArea, useId as useId2 } from "@dxos/react-ui";
75
744
  import { composable, composableProps } from "@dxos/react-ui";
76
745
  import { mx as mx4 } from "@dxos/ui-theme";
77
746
 
78
747
  // src/components/Picker/Picker.tsx
79
748
  import { Slot } from "@radix-ui/react-slot";
80
- import React3, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
749
+ import React3, { forwardRef, useCallback as useCallback5, useEffect as useEffect4, useMemo as useMemo4, useRef as useRef4, useState as useState4 } from "react";
81
750
  import { Input, useThemeContext } from "@dxos/react-ui";
82
751
  import { mx as mx3 } from "@dxos/ui-theme";
83
752
 
@@ -87,14 +756,18 @@ var [PickerItemContextProvider, usePickerItemContext] = createContext3("PickerIt
87
756
  var [PickerInputContextProvider, usePickerInputContext] = createContext3("PickerInput");
88
757
 
89
758
  // 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(() => {
759
+ var styles2 = listTheme.styles();
760
+ var PickerRoot = ({ children, resetSelectionOnChange = false }) => {
761
+ const [selectedValue, setSelectedValue] = useState4(void 0);
762
+ const itemsRef = useRef4(/* @__PURE__ */ new Map());
763
+ const [itemVersion, setItemVersion] = useState4(0);
764
+ const prevItemVersionRef = useRef4(itemVersion);
765
+ useEffect4(() => {
766
+ const itemsChanged = prevItemVersionRef.current !== itemVersion;
767
+ prevItemVersionRef.current = itemVersion;
95
768
  const current = selectedValue !== void 0 ? itemsRef.current.get(selectedValue) : void 0;
96
769
  const isValid = current !== void 0 && !current.disabled;
97
- if (!isValid && itemsRef.current.size > 0) {
770
+ if ((!isValid || resetSelectionOnChange && itemsChanged) && itemsRef.current.size > 0) {
98
771
  const entries = Array.from(itemsRef.current.entries()).filter(([, data]) => !data.disabled);
99
772
  if (entries.length > 0) {
100
773
  entries.sort(([, a], [, b]) => {
@@ -117,9 +790,10 @@ var PickerRoot = ({ children }) => {
117
790
  }
118
791
  }, [
119
792
  itemVersion,
120
- selectedValue
793
+ selectedValue,
794
+ resetSelectionOnChange
121
795
  ]);
122
- const registerItem = useCallback((value, element, onSelect, disabled) => {
796
+ const registerItem = useCallback5((value, element, onSelect, disabled) => {
123
797
  if (element) {
124
798
  itemsRef.current.set(value, {
125
799
  element,
@@ -129,17 +803,17 @@ var PickerRoot = ({ children }) => {
129
803
  setItemVersion((v) => v + 1);
130
804
  }
131
805
  }, []);
132
- const unregisterItem = useCallback((value) => {
806
+ const unregisterItem = useCallback5((value) => {
133
807
  itemsRef.current.delete(value);
134
808
  setItemVersion((v) => v + 1);
135
809
  }, []);
136
- const getItemValues = useCallback(() => {
810
+ const getItemValues = useCallback5(() => {
137
811
  return Array.from(itemsRef.current.entries()).filter(([, data]) => !data.disabled).sort(([, a], [, b]) => {
138
812
  const position = a.element.compareDocumentPosition(b.element);
139
813
  return position & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : position & Node.DOCUMENT_POSITION_PRECEDING ? 1 : 0;
140
814
  }).map(([value]) => value);
141
815
  }, []);
142
- const triggerSelect = useCallback(() => {
816
+ const triggerSelect = useCallback5(() => {
143
817
  if (selectedValue !== void 0) {
144
818
  const item = itemsRef.current.get(selectedValue);
145
819
  item?.onSelect?.();
@@ -147,7 +821,7 @@ var PickerRoot = ({ children }) => {
147
821
  }, [
148
822
  selectedValue
149
823
  ]);
150
- const itemContextValue = useMemo(() => ({
824
+ const itemContextValue = useMemo4(() => ({
151
825
  selectedValue,
152
826
  onSelectedValueChange: setSelectedValue,
153
827
  registerItem,
@@ -157,7 +831,7 @@ var PickerRoot = ({ children }) => {
157
831
  registerItem,
158
832
  unregisterItem
159
833
  ]);
160
- const inputContextValue = useMemo(() => ({
834
+ const inputContextValue = useMemo4(() => ({
161
835
  selectedValue,
162
836
  onSelectedValueChange: setSelectedValue,
163
837
  getItemValues,
@@ -173,14 +847,14 @@ PickerRoot.displayName = "Picker.Root";
173
847
  var PickerInput = /* @__PURE__ */ forwardRef(({ value, onValueChange, onChange, onKeyDown, autoFocus, ...props }, forwardedRef) => {
174
848
  const { hasIosKeyboard } = useThemeContext();
175
849
  const { selectedValue, onSelectedValueChange, getItemValues, triggerSelect } = usePickerInputContext("Picker.Input");
176
- const handleChange = useCallback((event) => {
850
+ const handleChange = useCallback5((event) => {
177
851
  onValueChange?.(event.target.value);
178
852
  onChange?.(event);
179
853
  }, [
180
854
  onValueChange,
181
855
  onChange
182
856
  ]);
183
- const handleKeyDown = useCallback((event) => {
857
+ const handleKeyDown = useCallback5((event) => {
184
858
  onKeyDown?.(event);
185
859
  if (event.defaultPrevented) {
186
860
  return;
@@ -267,9 +941,9 @@ var PickerInput = /* @__PURE__ */ forwardRef(({ value, onValueChange, onChange,
267
941
  PickerInput.displayName = "Picker.Input";
268
942
  var PickerItem = /* @__PURE__ */ forwardRef(({ classNames, value, onSelect, disabled, asChild, children, ...props }, forwardedRef) => {
269
943
  const { selectedValue, onSelectedValueChange, registerItem, unregisterItem } = usePickerItemContext("Picker.Item");
270
- const internalRef = useRef(null);
944
+ const internalRef = useRef4(null);
271
945
  const isSelected = selectedValue === value && !disabled;
272
- useEffect(() => {
946
+ useEffect4(() => {
273
947
  const element = internalRef.current;
274
948
  if (element) {
275
949
  registerItem(value, element, onSelect, disabled);
@@ -282,7 +956,7 @@ var PickerItem = /* @__PURE__ */ forwardRef(({ classNames, value, onSelect, disa
282
956
  registerItem,
283
957
  unregisterItem
284
958
  ]);
285
- useEffect(() => {
959
+ useEffect4(() => {
286
960
  if (isSelected && internalRef.current) {
287
961
  internalRef.current.scrollIntoView({
288
962
  block: "nearest",
@@ -292,7 +966,7 @@ var PickerItem = /* @__PURE__ */ forwardRef(({ classNames, value, onSelect, disa
292
966
  }, [
293
967
  isSelected
294
968
  ]);
295
- const handleClick = useCallback(() => {
969
+ const handleClick = useCallback5(() => {
296
970
  if (disabled) {
297
971
  return;
298
972
  }
@@ -304,7 +978,7 @@ var PickerItem = /* @__PURE__ */ forwardRef(({ classNames, value, onSelect, disa
304
978
  onSelectedValueChange,
305
979
  onSelect
306
980
  ]);
307
- const handleMouseDown = useCallback((event) => {
981
+ const handleMouseDown = useCallback5((event) => {
308
982
  event.preventDefault();
309
983
  }, []);
310
984
  const Comp = asChild ? Slot : "div";
@@ -326,7 +1000,9 @@ var PickerItem = /* @__PURE__ */ forwardRef(({ classNames, value, onSelect, disa
326
1000
  "data-value": value,
327
1001
  // Browser focus stays on the input; highlight is via `aria-selected`.
328
1002
  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),
1003
+ className: styles2.pickerItem({
1004
+ class: mx3(disabled && "opacity-50 cursor-not-allowed", classNames)
1005
+ }),
330
1006
  onMouseDown: handleMouseDown,
331
1007
  onClick: handleClick
332
1008
  }, children);
@@ -339,13 +1015,14 @@ var Picker = {
339
1015
  };
340
1016
 
341
1017
  // src/components/Combobox/Combobox.tsx
1018
+ var styles3 = listTheme.styles();
342
1019
  var COMBOBOX_NAME = "Combobox";
343
1020
  var COMBOBOX_CONTENT_NAME = "ComboboxContent";
344
1021
  var COMBOBOX_ITEM_NAME = "ComboboxItem";
345
1022
  var COMBOBOX_TRIGGER_NAME = "ComboboxTrigger";
346
1023
  var [ComboboxProvider, useComboboxContext] = createContext4(COMBOBOX_NAME, {});
347
1024
  var ComboboxRoot = ({ children, modal, modalId: modalIdProp, open: openProp, defaultOpen, onOpenChange: propsOnOpenChange, value: valueProp, defaultValue, onValueChange: propsOnValueChange, placeholder }) => {
348
- const modalId = useId(COMBOBOX_NAME, modalIdProp);
1025
+ const modalId = useId2(COMBOBOX_NAME, modalIdProp);
349
1026
  const [open = false, onOpenChange] = useControllableState({
350
1027
  prop: openProp,
351
1028
  defaultProp: defaultOpen,
@@ -370,7 +1047,7 @@ var ComboboxRoot = ({ children, modal, modalId: modalIdProp, open: openProp, def
370
1047
  onValueChange
371
1048
  }, children));
372
1049
  };
373
- var ComboboxContent = composable(({ children, ...props }, forwardedRef) => {
1050
+ var ComboboxContent = composable(({ children, resetSelectionOnChange, ...props }, forwardedRef) => {
374
1051
  const { modalId } = useComboboxContext(COMBOBOX_CONTENT_NAME);
375
1052
  return /* @__PURE__ */ React4.createElement(Popover.Content, {
376
1053
  ...composableProps(props, {
@@ -379,12 +1056,14 @@ var ComboboxContent = composable(({ children, ...props }, forwardedRef) => {
379
1056
  ref: forwardedRef
380
1057
  }, /* @__PURE__ */ React4.createElement(Popover.Viewport, {
381
1058
  classNames: "w-(--radix-popover-trigger-width)"
382
- }, /* @__PURE__ */ React4.createElement(Picker.Root, null, children)));
1059
+ }, /* @__PURE__ */ React4.createElement(Picker.Root, {
1060
+ resetSelectionOnChange
1061
+ }, children)));
383
1062
  });
384
1063
  ComboboxContent.displayName = COMBOBOX_CONTENT_NAME;
385
1064
  var ComboboxTrigger = /* @__PURE__ */ forwardRef2(({ children, onClick, ...props }, forwardedRef) => {
386
1065
  const { modalId, open, onOpenChange, placeholder, value } = useComboboxContext(COMBOBOX_TRIGGER_NAME);
387
- const handleClick = useCallback2((event) => {
1066
+ const handleClick = useCallback6((event) => {
388
1067
  onClick?.(event);
389
1068
  onOpenChange?.(true);
390
1069
  }, [
@@ -402,7 +1081,9 @@ var ComboboxTrigger = /* @__PURE__ */ forwardRef2(({ children, onClick, ...props
402
1081
  onClick: handleClick,
403
1082
  ref: forwardedRef
404
1083
  }, 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")
1084
+ className: styles3.comboboxTriggerText({
1085
+ class: !value && "text-subdued"
1086
+ })
406
1087
  }, value || placeholder), /* @__PURE__ */ React4.createElement(Icon2, {
407
1088
  icon: "ph--caret-down--bold",
408
1089
  size: 3
@@ -413,10 +1094,9 @@ var ComboboxVirtualTrigger = Popover.VirtualTrigger;
413
1094
  var ComboboxInput = /* @__PURE__ */ forwardRef2(({ classNames, ...props }, forwardedRef) => {
414
1095
  return /* @__PURE__ */ React4.createElement(Picker.Input, {
415
1096
  ...props,
416
- classNames: [
417
- "m-form-chrome mb-0 w-[calc(100%-2*var(--spacing-form-chrome))]",
418
- classNames
419
- ],
1097
+ classNames: styles3.comboboxInput({
1098
+ class: classNames
1099
+ }),
420
1100
  ref: forwardedRef
421
1101
  });
422
1102
  });
@@ -424,10 +1104,9 @@ ComboboxInput.displayName = "Combobox.Input";
424
1104
  var ComboboxList = /* @__PURE__ */ forwardRef2(({ classNames, children, ...props }, forwardedRef) => {
425
1105
  return /* @__PURE__ */ React4.createElement(ScrollArea.Root, {
426
1106
  ...composableProps(props, {
427
- classNames: [
428
- "py-form-chrome",
429
- classNames
430
- ]
1107
+ classNames: styles3.comboboxList({
1108
+ class: classNames
1109
+ })
431
1110
  }),
432
1111
  role: "listbox",
433
1112
  centered: true,
@@ -437,9 +1116,9 @@ var ComboboxList = /* @__PURE__ */ forwardRef2(({ classNames, children, ...props
437
1116
  }, /* @__PURE__ */ React4.createElement(ScrollArea.Viewport, null, children));
438
1117
  });
439
1118
  ComboboxList.displayName = "Combobox.List";
440
- var ComboboxItem = /* @__PURE__ */ forwardRef2(({ classNames, onSelect, value, label, icon, iconClassNames, checked, suffix, disabled, closeOnSelect = true, children }, forwardedRef) => {
1119
+ var ComboboxItem = /* @__PURE__ */ forwardRef2(({ classNames, onSelect, value, label, description, icon, iconClassNames, checked, suffix, disabled, closeOnSelect = true, children }, forwardedRef) => {
441
1120
  const { onValueChange, onOpenChange } = useComboboxContext(COMBOBOX_ITEM_NAME);
442
- const handleSelect = useCallback2(() => {
1121
+ const handleSelect = useCallback6(() => {
443
1122
  onSelect?.();
444
1123
  if (value !== void 0) {
445
1124
  onValueChange?.(value);
@@ -459,20 +1138,22 @@ var ComboboxItem = /* @__PURE__ */ forwardRef2(({ classNames, onSelect, value, l
459
1138
  disabled,
460
1139
  onSelect: handleSelect,
461
1140
  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
- ]
1141
+ classNames: styles3.comboboxItem({
1142
+ // `px-3 py-1`, `cursor-pointer`, `select-none` and the `dx-hover` / `dx-selected`
1143
+ // pairing come from `Picker.Item`'s defaults; the slot only adds row-shape (flex /
1144
+ // icons + label). Disabled overrides are layered on per-instance.
1145
+ class: mx4(disabled && "hover:bg-transparent data-[selected=true]:bg-transparent", classNames)
1146
+ })
472
1147
  }, children ?? /* @__PURE__ */ React4.createElement(React4.Fragment, null, icon && /* @__PURE__ */ React4.createElement(Icon2, {
473
1148
  icon,
474
1149
  classNames: iconClassNames
475
- }), /* @__PURE__ */ React4.createElement("span", {
1150
+ }), description ? /* @__PURE__ */ React4.createElement("span", {
1151
+ className: "w-0 grow flex flex-col"
1152
+ }, /* @__PURE__ */ React4.createElement("span", {
1153
+ className: "truncate"
1154
+ }, label), /* @__PURE__ */ React4.createElement("span", {
1155
+ className: styles3.comboboxItemDescription()
1156
+ }, description)) : /* @__PURE__ */ React4.createElement("span", {
476
1157
  className: "w-0 grow truncate"
477
1158
  }, label), suffix && /* @__PURE__ */ React4.createElement("span", {
478
1159
  className: "shrink-0 text-description"
@@ -504,516 +1185,676 @@ var Combobox = {
504
1185
  Empty: ComboboxEmpty
505
1186
  };
506
1187
 
507
- // src/components/List/ListItem.tsx
508
- import { attachClosestEdge, extractClosestEdge as extractClosestEdge2 } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
509
- import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
510
- import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
511
- import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview";
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";
515
- import { createPortal } from "react-dom";
516
- import { invariant } from "@dxos/invariant";
517
- import { IconButton, ListItem as NaturalListItem, useTranslation } from "@dxos/react-ui";
518
- import { mx as mx5, osTranslations } from "@dxos/ui-theme";
1188
+ // src/components/DropIndicator/DropIndicator.tsx
1189
+ import React5 from "react";
1190
+ var edgeToOrientationMap = {
1191
+ top: "horizontal",
1192
+ bottom: "horizontal",
1193
+ left: "vertical",
1194
+ right: "vertical"
1195
+ };
1196
+ var orientationStyles = {
1197
+ horizontal: "h-(--line-thickness) left-[calc(var(--line-inset)+var(--terminal-radius))] right-(--line-inset) before:left-(--terminal-inset)",
1198
+ vertical: "w-(--line-thickness) top-[calc(var(--line-inset)+var(--terminal-radius))] bottom-(--line-inset) before:top-(--terminal-inset)"
1199
+ };
1200
+ var edgeStyles = {
1201
+ top: "top-(--line-offset) before:top-(--offset-terminal)",
1202
+ right: "right-(--line-offset) before:right-(--offset-terminal)",
1203
+ bottom: "bottom-(--line-offset) before:bottom-(--offset-terminal)",
1204
+ left: "left-(--line-offset) before:left-(--offset-terminal)"
1205
+ };
1206
+ var strokeSize = 2;
1207
+ var terminalSize = 8;
1208
+ var offsetToAlignTerminalWithLine = (strokeSize - terminalSize) / 2;
1209
+ var DropIndicator = ({ edge, gap = 0, lineInset = 0, terminalInset = lineInset - terminalSize }) => {
1210
+ const orientation = edgeToOrientationMap[edge];
1211
+ return /* @__PURE__ */ React5.createElement("div", {
1212
+ style: {
1213
+ "--line-thickness": `${strokeSize}px`,
1214
+ "--line-offset": `calc(-0.5 * (${gap}px + ${strokeSize}px))`,
1215
+ "--line-inset": `${lineInset}px`,
1216
+ "--terminal-size": `${terminalSize}px`,
1217
+ "--terminal-radius": `${terminalSize / 2}px`,
1218
+ "--terminal-inset": `${terminalInset}px`,
1219
+ "--offset-terminal": `${offsetToAlignTerminalWithLine}px`
1220
+ },
1221
+ className: `absolute z-10 pointer-events-none bg-accent-bg before:content-[''] before:w-(--terminal-size) before:h-(--terminal-size) box-border before:box-border before:absolute before:border-[length:--line-thickness] before:border-solid before:border-accent-bg before:rounded-full ${orientationStyles[orientation]} ${edgeStyles[edge]}`
1222
+ });
1223
+ };
519
1224
 
520
- // src/components/List/ListRoot.tsx
521
- import { extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
522
- import { getReorderDestinationIndex } from "@atlaskit/pragmatic-drag-and-drop-hitbox/util/get-reorder-destination-index";
523
- import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
1225
+ // src/components/Empty/Empty.tsx
1226
+ import React6 from "react";
1227
+ import { Icon as Icon3, composable as composable2, composableProps as composableProps2, useTranslation } from "@dxos/react-ui";
1228
+ import { osTranslations } from "@dxos/ui-theme";
1229
+ var Empty = composable2(({ label, icon, ...props }, forwardedRef) => {
1230
+ const { t } = useTranslation(osTranslations);
1231
+ const message = label ?? t("empty.label", {
1232
+ defaultValue: "No items"
1233
+ });
1234
+ return /* @__PURE__ */ React6.createElement("div", {
1235
+ ...composableProps2(props, {
1236
+ classNames: "flex flex-col items-center justify-center gap-2 p-4 text-sm text-center text-description",
1237
+ role: "status"
1238
+ }),
1239
+ ref: forwardedRef
1240
+ }, icon && /* @__PURE__ */ React6.createElement(Icon3, {
1241
+ icon,
1242
+ size: 6,
1243
+ classNames: "text-subdued"
1244
+ }), /* @__PURE__ */ React6.createElement("span", null, message));
1245
+ });
1246
+ Empty.displayName = "Empty";
1247
+
1248
+ // src/components/Listbox/Listbox.tsx
524
1249
  import { createContext as createContext5 } from "@radix-ui/react-context";
525
- import React5, { useCallback as useCallback3, useEffect as useEffect2, useState as useState2 } from "react";
526
- var LIST_NAME = "List";
527
- var [ListProvider, useListContext] = createContext5(LIST_NAME);
528
- var defaultGetId2 = (item) => item?.id;
529
- var ListRoot = ({ children, items, isItem, getId = defaultGetId2, onMove, ...props }) => {
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;
1250
+ import React8, { forwardRef as forwardRef4, useCallback as useCallback7, useMemo as useMemo5 } from "react";
1251
+ import { List, ListItem } from "@dxos/react-list";
1252
+ import { Icon as Icon5, ScrollArea as ScrollArea2, composable as composable3, composableProps as composableProps3 } from "@dxos/react-ui";
1253
+ import { mx as mx6 } from "@dxos/ui-theme";
1254
+
1255
+ // src/components/Listbox/ListItemContent.tsx
1256
+ import React7, { forwardRef as forwardRef3 } from "react";
1257
+ import { Icon as Icon4 } from "@dxos/react-ui";
1258
+ import { mx as mx5 } from "@dxos/ui-theme";
1259
+ var styles4 = listTheme.styles();
1260
+ var ListItemContent = /* @__PURE__ */ forwardRef3(({ classNames, icon, title, description }, forwardedRef) => /* @__PURE__ */ React7.createElement("div", {
1261
+ ref: forwardedRef,
1262
+ className: styles4.itemContentRoot({
1263
+ class: mx5(classNames)
1264
+ })
1265
+ }, icon != null && /* @__PURE__ */ React7.createElement("div", {
1266
+ className: styles4.itemContentIcon()
1267
+ }, typeof icon === "string" ? /* @__PURE__ */ React7.createElement(Icon4, {
1268
+ icon,
1269
+ size: 5
1270
+ }) : icon), /* @__PURE__ */ React7.createElement("span", {
1271
+ className: styles4.itemContentTitle()
1272
+ }, title), description != null && /* @__PURE__ */ React7.createElement("span", {
1273
+ className: styles4.itemContentDescription()
1274
+ }, description)));
1275
+ ListItemContent.displayName = "ItemContent";
1276
+
1277
+ // src/components/Listbox/Listbox.tsx
1278
+ var styles5 = listTheme.styles();
1279
+ var LISTBOX_NAME = "Listbox";
1280
+ var LISTBOX_ROOT_NAME = "Listbox.Root";
1281
+ var LISTBOX_VIEWPORT_NAME = "Listbox.Viewport";
1282
+ var LISTBOX_CONTENT_NAME = "Listbox.Content";
1283
+ var LISTBOX_ITEM_NAME = "Listbox.Item";
1284
+ var LISTBOX_ITEM_LABEL_NAME = "Listbox.ItemLabel";
1285
+ var LISTBOX_INDICATOR_NAME = "Listbox.Indicator";
1286
+ var [ListboxProvider, useListboxContext] = createContext5(LISTBOX_NAME);
1287
+ var [ListboxItemProvider, useListboxItemContext] = createContext5(LISTBOX_ITEM_NAME);
1288
+ var Root2 = ({ value, defaultValue, onValueChange, autoFocus: _autoFocus, children }) => {
1289
+ const selectable = value !== void 0 || defaultValue !== void 0 || onValueChange !== void 0;
1290
+ const selection = useListSelection({
1291
+ mode: "single",
1292
+ value,
1293
+ defaultValue,
1294
+ onValueChange: (next) => {
1295
+ if (next !== void 0) {
1296
+ onValueChange?.(next);
1297
+ }
537
1298
  }
538
- }, [
539
- getId
1299
+ });
1300
+ const context = useMemo5(() => ({
1301
+ selectable,
1302
+ selection
1303
+ }), [
1304
+ selectable,
1305
+ selection
540
1306
  ]);
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;
552
- }
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
- }));
587
- };
588
-
589
- // src/components/List/ListItem.tsx
590
- var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-list/src/components/List/ListItem.tsx";
591
- var idle = {
592
- type: "idle"
593
- };
594
- var stateStyles = {
595
- "is-dragging": "opacity-50"
1307
+ return /* @__PURE__ */ React8.createElement(ListboxProvider, context, children);
596
1308
  };
597
- var defaultContext = {};
598
- var LIST_ITEM_NAME = "ListItem";
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();
624
- return {
625
- x: 20,
626
- y: height / 2
627
- };
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
- }));
720
- };
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
- });
734
- };
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
- });
751
- };
752
- var ListItemDragHandle = ({ disabled }) => {
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
- });
763
- };
764
- var ListItemDragPreview = ({ children }) => {
765
- const { state } = useListContext("DRAG_PREVIEW");
766
- return state?.type === "preview" ? /* @__PURE__ */ createPortal(children({
767
- item: state.item
768
- }), state.container) : null;
769
- };
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);
777
-
778
- // src/components/List/List.tsx
779
- var List = {
780
- Root: ListRoot,
781
- Item: ListItem,
782
- ItemDragPreview: ListItemDragPreview,
783
- ItemWrapper: ListItemWrapper,
784
- ItemDragHandle: ListItemDragHandle,
785
- ItemIconButton: ListItemIconButton,
786
- ItemDeleteButton: ListItemDeleteButton,
787
- ItemTitle: ListItemTitle
788
- };
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) => {
1309
+ Root2.displayName = LISTBOX_ROOT_NAME;
1310
+ var Viewport = composable3((props, forwardedRef) => {
832
1311
  const { thin, padding, centered, children, ...rest } = props;
833
- return /* @__PURE__ */ React7.createElement(ScrollArea2.Root, {
834
- ...composableProps2(rest, {
835
- classNames: "dx-container"
1312
+ return /* @__PURE__ */ React8.createElement(ScrollArea2.Root, {
1313
+ ...composableProps3(rest, {
1314
+ classNames: styles5.listboxViewport()
836
1315
  }),
837
1316
  thin,
838
1317
  padding,
839
1318
  centered,
840
1319
  orientation: "vertical",
841
1320
  ref: forwardedRef
842
- }, /* @__PURE__ */ React7.createElement(ScrollArea2.Viewport, null, children));
1321
+ }, /* @__PURE__ */ React8.createElement(ScrollArea2.Viewport, null, children));
843
1322
  });
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
1323
+ Viewport.displayName = LISTBOX_VIEWPORT_NAME;
1324
+ var Content2 = composable3((props, forwardedRef) => {
1325
+ const { selectable } = useListboxContext(LISTBOX_CONTENT_NAME);
1326
+ const navigation = useListNavigation({
1327
+ mode: selectable ? "listbox" : "list"
856
1328
  });
857
1329
  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"
1330
+ const composed = composableProps3(rest, {
1331
+ classNames: styles5.listboxContent()
869
1332
  });
870
- return /* @__PURE__ */ React7.createElement(List2, {
1333
+ return /* @__PURE__ */ React8.createElement(List, {
871
1334
  variant: "unordered",
872
1335
  ...composed,
873
- ...arrowGroup,
874
- role: "listbox",
875
- onFocus: handleFocus,
1336
+ ...navigation.containerProps,
876
1337
  ref: forwardedRef
877
1338
  }, children);
878
1339
  });
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;
1340
+ Content2.displayName = LISTBOX_CONTENT_NAME;
1341
+ var Item2 = composable3((props, forwardedRef) => {
1342
+ const { id, disabled, onClick, onFocus, onMouseDown, children, ...rest } = props;
1343
+ const { selectable, selection } = useListboxContext(LISTBOX_ITEM_NAME);
1344
+ const binding = selection.bind(id, {
1345
+ disabled
1346
+ });
1347
+ const selected = selectable && binding.selected;
1348
+ const interactive = selectable || onClick != null;
1349
+ const handleClick = useCallback7((event) => {
1350
+ if (selectable) {
1351
+ binding.rowProps.onClick(event);
1352
+ }
1353
+ if (!disabled) {
1354
+ onClick?.(event);
888
1355
  }
889
- setSelected(id);
890
- onClick?.(event);
891
1356
  }, [
1357
+ selectable,
1358
+ binding,
892
1359
  disabled,
893
- id,
894
- setSelected,
895
1360
  onClick
896
1361
  ]);
897
- const handleFocus = useCallback4((event) => {
898
- if (!disabled && selectedId !== id) {
899
- setSelected(id);
1362
+ const handleFocus = useCallback7((event) => {
1363
+ if (selectable) {
1364
+ binding.rowProps.onFocus?.(event);
900
1365
  }
901
1366
  onFocus?.(event);
902
1367
  }, [
903
- disabled,
904
- selectedId,
905
- id,
906
- setSelected,
1368
+ selectable,
1369
+ binding,
907
1370
  onFocus
908
1371
  ]);
909
- const composed = composableProps2(rest, {
910
- classNames: [
911
- ROW_BASE,
912
- disabled && "opacity-50 cursor-not-allowed"
913
- ]
1372
+ const composed = composableProps3(rest, {
1373
+ classNames: styles5.listboxItem({
1374
+ class: [
1375
+ !interactive && "cursor-default",
1376
+ disabled && "opacity-50 cursor-not-allowed"
1377
+ ]
1378
+ })
914
1379
  });
915
- return /* @__PURE__ */ React7.createElement(ListItem2, {
1380
+ return /* @__PURE__ */ React8.createElement(ListItemProviderHost, {
1381
+ id,
1382
+ selected
1383
+ }, /* @__PURE__ */ React8.createElement(ListItem, {
916
1384
  ...composed,
917
- role: "option",
918
- tabIndex: 0,
919
- "aria-selected": isSelected,
1385
+ role: selectable ? "option" : "listitem",
1386
+ tabIndex: selectable ? 0 : -1,
1387
+ "aria-selected": selectable ? selected : void 0,
920
1388
  "aria-disabled": disabled || void 0,
921
1389
  onClick: handleClick,
922
1390
  onFocus: handleFocus,
1391
+ onMouseDown,
923
1392
  ref: forwardedRef
924
- }, children);
1393
+ }, children));
925
1394
  });
926
- Row.displayName = ROW_NAME;
927
- var useRowListSelection = (id) => {
928
- const { selectedId } = useRowListContext("useRowListSelection", void 0);
929
- return selectedId === id;
1395
+ Item2.displayName = LISTBOX_ITEM_NAME;
1396
+ var ListItemProviderHost = ({ id, selected, children }) => /* @__PURE__ */ React8.createElement(ListboxItemProvider, {
1397
+ id,
1398
+ selected
1399
+ }, children);
1400
+ var ItemLabel = /* @__PURE__ */ forwardRef4(({ classNames, children, ...rest }, forwardedRef) => /* @__PURE__ */ React8.createElement("span", {
1401
+ ...rest,
1402
+ className: styles5.listboxItemLabel({
1403
+ class: mx6(classNames)
1404
+ }),
1405
+ ref: forwardedRef
1406
+ }, children));
1407
+ ItemLabel.displayName = LISTBOX_ITEM_LABEL_NAME;
1408
+ var Indicator = /* @__PURE__ */ forwardRef4(({ classNames, ...rootProps }, forwardedRef) => {
1409
+ const { selected } = useListboxItemContext(LISTBOX_INDICATOR_NAME);
1410
+ return /* @__PURE__ */ React8.createElement(Icon5, {
1411
+ icon: "ph--check--regular",
1412
+ ...rootProps,
1413
+ classNames: mx6(!selected && "invisible", classNames),
1414
+ ref: forwardedRef
1415
+ });
1416
+ });
1417
+ Indicator.displayName = LISTBOX_INDICATOR_NAME;
1418
+ var useListboxSelection = (id) => {
1419
+ const { selection } = useListboxContext("useListboxSelection");
1420
+ return selection.bind(id).selected;
930
1421
  };
931
- var RowList = {
1422
+ var Listbox = {
932
1423
  Root: Root2,
933
1424
  Viewport,
934
- Content: Content2
1425
+ Content: Content2,
1426
+ Item: Item2,
1427
+ ItemLabel,
1428
+ ItemContent: ListItemContent,
1429
+ Indicator
935
1430
  };
936
1431
 
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_INDICATOR_NAME = "ListboxOptionIndicator";
942
- var [createListboxContext, createListboxScope] = createContextScope2(LISTBOX_NAME, [
943
- createRowListScope
944
- ]);
945
- var [createListboxOptionContext, createListboxOptionScope] = createContextScope2(LISTBOX_OPTION_NAME, [
946
- createListboxScope
947
- ]);
948
- var [ListboxOptionProvider, useListboxOptionContext] = createListboxOptionContext(LISTBOX_OPTION_NAME);
949
- var ListboxRoot = /* @__PURE__ */ forwardRef3((props, forwardedRef) => {
950
- const { __listboxScope: _scope, children, classNames, value, defaultValue, onValueChange, autoFocus: _autoFocus, ...rootProps } = props;
951
- return /* @__PURE__ */ React8.createElement(RowList.Root, {
952
- selectedId: value,
953
- defaultSelectedId: defaultValue,
954
- onSelectChange: onValueChange
955
- }, /* @__PURE__ */ React8.createElement(RowList.Content, {
956
- ...rootProps,
957
- classNames: mx6("w-full", classNames),
958
- ref: forwardedRef
959
- }, children));
960
- });
961
- ListboxRoot.displayName = "Listbox.Root";
962
- var ListboxOption = /* @__PURE__ */ forwardRef3((props, forwardedRef) => {
963
- const { __listboxScope, children, classNames, value, ...rootProps } = props;
964
- return /* @__PURE__ */ React8.createElement(Row, {
965
- id: value,
966
- ...rootProps,
967
- classNames: mx6("dx-focus-ring rounded-xs", commandItem, classNames),
1432
+ // src/components/OrderedList/OrderedListItem.tsx
1433
+ import { createContext as createContext7 } from "@radix-ui/react-context";
1434
+ import React10, { useCallback as useCallback8 } from "react";
1435
+ import { IconBlock, IconButton, ToggleIconButton, useTranslation as useTranslation2 } from "@dxos/react-ui";
1436
+ import { mx as mx8, osTranslations as osTranslations2 } from "@dxos/ui-theme";
1437
+
1438
+ // src/components/OrderedList/OrderedListRoot.tsx
1439
+ import { createContext as createContext6 } from "@radix-ui/react-context";
1440
+ import React9, { useMemo as useMemo6 } from "react";
1441
+ import { ScrollArea as ScrollArea3, composable as composable4, composableProps as composableProps4 } from "@dxos/react-ui";
1442
+ import { mx as mx7 } from "@dxos/ui-theme";
1443
+ var styles6 = listTheme.styles();
1444
+ var ORDERED_LIST_NAME = "OrderedList";
1445
+ var [OrderedListProvider, useOrderedListContext] = createContext6(ORDERED_LIST_NAME);
1446
+ var defaultGetId2 = (item) => item?.id;
1447
+ var noopMove = () => {
1448
+ };
1449
+ var OrderedListRoot = ({ items, getId = defaultGetId2, onMove = noopMove, readonly, expandedId, defaultExpandedId, onExpandedChange, children }) => {
1450
+ const { controller, active } = useReorderList({
1451
+ items,
1452
+ getId,
1453
+ onMove,
1454
+ readonly
1455
+ });
1456
+ const disclosure = useListDisclosure({
1457
+ mode: "single",
1458
+ value: expandedId,
1459
+ defaultValue: defaultExpandedId,
1460
+ onValueChange: (next) => onExpandedChange?.(next)
1461
+ });
1462
+ const navigation = useListNavigation({
1463
+ mode: "list"
1464
+ });
1465
+ const context = useMemo6(() => ({
1466
+ reorder: controller,
1467
+ disclosure,
1468
+ navigation,
1469
+ readonly,
1470
+ active,
1471
+ getId
1472
+ }), [
1473
+ controller,
1474
+ disclosure,
1475
+ navigation,
1476
+ readonly,
1477
+ active,
1478
+ getId
1479
+ ]);
1480
+ return /* @__PURE__ */ React9.createElement(OrderedListProvider, context, children({
1481
+ items
1482
+ }));
1483
+ };
1484
+ var OrderedListContent = ({ classNames, children }) => {
1485
+ const { navigation } = useOrderedListContext("OrderedList.Content");
1486
+ return /* @__PURE__ */ React9.createElement("div", {
1487
+ ...navigation.containerProps,
1488
+ className: styles6.orderedListContent({
1489
+ class: mx7(classNames)
1490
+ })
1491
+ }, children);
1492
+ };
1493
+ var OrderedListViewport = composable4((props, forwardedRef) => {
1494
+ const { thin, padding, centered, children, ...rest } = props;
1495
+ const autoScrollRef = useReorderAutoScroll();
1496
+ return /* @__PURE__ */ React9.createElement(ScrollArea3.Root, {
1497
+ ...composableProps4(rest, {
1498
+ classNames: styles6.orderedListViewport()
1499
+ }),
1500
+ thin,
1501
+ padding,
1502
+ centered,
1503
+ orientation: "vertical",
968
1504
  ref: forwardedRef
969
- }, /* @__PURE__ */ React8.createElement(ListboxOptionProviderHost, {
970
- value
1505
+ }, /* @__PURE__ */ React9.createElement(ScrollArea3.Viewport, {
1506
+ ref: autoScrollRef
971
1507
  }, children));
972
1508
  });
973
- ListboxOption.displayName = "Listbox.Option";
974
- var ListboxOptionProviderHost = ({ value, children }) => {
975
- const isSelected = useRowListSelection(value);
976
- return /* @__PURE__ */ React8.createElement(ListboxOptionProvider, {
977
- scope: void 0,
978
- value,
979
- isSelected
1509
+ OrderedListViewport.displayName = "OrderedList.Viewport";
1510
+
1511
+ // src/components/OrderedList/OrderedListItem.tsx
1512
+ var styles7 = listTheme.styles();
1513
+ var ORDERED_LIST_ITEM_NAME = "OrderedListItem";
1514
+ var [OrderedListItemProvider, useOrderedListItemContext] = createContext7(ORDERED_LIST_ITEM_NAME);
1515
+ var OrderedListItem = ({ id, canDrag = true, hover = false, selected, onClick, classNames, style, children }) => {
1516
+ const { reorder, disclosure, navigation } = useOrderedListContext(ORDERED_LIST_ITEM_NAME);
1517
+ const { rowRef, handleRef, closestEdge, state } = useReorderItem(reorder, id);
1518
+ const { expanded, toggle, triggerProps, panelProps } = disclosure.bind(id);
1519
+ return /* @__PURE__ */ React10.createElement(OrderedListItemProvider, {
1520
+ id,
1521
+ expanded,
1522
+ toggle,
1523
+ canDrag,
1524
+ handleRef,
1525
+ triggerProps,
1526
+ panelProps
1527
+ }, /* @__PURE__ */ React10.createElement("div", {
1528
+ ref: rowRef,
1529
+ ...navigation.itemProps(),
1530
+ style,
1531
+ "aria-current": selected || void 0,
1532
+ onClick,
1533
+ className: styles7.orderedListItem({
1534
+ class: mx8(hover && "dx-hover", state.type === "dragging" && "opacity-50", classNames)
1535
+ })
1536
+ }, children, closestEdge && /* @__PURE__ */ React10.createElement(DropIndicator, {
1537
+ edge: closestEdge
1538
+ })));
1539
+ };
1540
+ var OrderedListDragHandle = () => {
1541
+ const { readonly } = useOrderedListContext("OrderedListDragHandle");
1542
+ const { canDrag, handleRef } = useOrderedListItemContext("OrderedListDragHandle");
1543
+ const { t } = useTranslation2(osTranslations2);
1544
+ const disabled = readonly || !canDrag;
1545
+ return /* @__PURE__ */ React10.createElement(IconButton, {
1546
+ variant: "ghost",
1547
+ disabled,
1548
+ noTooltip: true,
1549
+ icon: "ph--dots-six-vertical--regular",
1550
+ iconOnly: true,
1551
+ label: t("drag-handle.label"),
1552
+ ref: handleRef
1553
+ });
1554
+ };
1555
+ var OrderedListTitle = ({ classNames, children, onClick, ...props }) => {
1556
+ const { triggerProps } = useOrderedListItemContext("OrderedListTitle");
1557
+ const handleClick = useCallback8((event) => {
1558
+ onClick?.(event);
1559
+ triggerProps.onClick(event);
1560
+ }, [
1561
+ onClick,
1562
+ triggerProps
1563
+ ]);
1564
+ return /* @__PURE__ */ React10.createElement("div", {
1565
+ ...props,
1566
+ // The title row is also the disclosure trigger, so it carries the trigger's
1567
+ // `id` + `aria-expanded` + `aria-controls` for assistive tech.
1568
+ id: triggerProps.id,
1569
+ "aria-expanded": triggerProps["aria-expanded"],
1570
+ "aria-controls": triggerProps["aria-controls"],
1571
+ className: styles7.orderedListTitle({
1572
+ class: mx8(classNames)
1573
+ }),
1574
+ onClick: handleClick
980
1575
  }, children);
981
1576
  };
982
- var ListboxOptionLabel = /* @__PURE__ */ forwardRef3(({ children, classNames, ...rootProps }, forwardedRef) => {
983
- return /* @__PURE__ */ React8.createElement("span", {
984
- ...rootProps,
985
- className: mx6("grow truncate", classNames),
986
- ref: forwardedRef
1577
+ var OrderedListIconButton = ({ autoHide = false, disabled, classNames, ...props }) => /* @__PURE__ */ React10.createElement(IconBlock, null, /* @__PURE__ */ React10.createElement(IconButton, {
1578
+ ...props,
1579
+ variant: "ghost",
1580
+ iconOnly: true,
1581
+ disabled,
1582
+ classNames: [
1583
+ classNames,
1584
+ autoHide && disabled && "hidden"
1585
+ ]
1586
+ }));
1587
+ var OrderedListDeleteButton = ({ autoHide = false, icon = "ph--x--regular", label, disabled, classNames, ...props }) => {
1588
+ const { t } = useTranslation2(osTranslations2);
1589
+ return /* @__PURE__ */ React10.createElement(OrderedListIconButton, {
1590
+ ...props,
1591
+ autoHide,
1592
+ disabled,
1593
+ icon,
1594
+ label: label ?? t("delete.label"),
1595
+ classNames
1596
+ });
1597
+ };
1598
+ var OrderedListExpandCaret = ({ onClick, ...props }) => {
1599
+ const { t } = useTranslation2(osTranslations2);
1600
+ const { expanded, toggle, triggerProps } = useOrderedListItemContext("OrderedListExpandCaret");
1601
+ const handleClick = useCallback8((event) => {
1602
+ toggle();
1603
+ onClick?.(event);
1604
+ }, [
1605
+ toggle,
1606
+ onClick
1607
+ ]);
1608
+ return /* @__PURE__ */ React10.createElement(ToggleIconButton, {
1609
+ iconOnly: true,
1610
+ variant: "ghost",
1611
+ active: expanded,
1612
+ icon: "ph--caret-right--regular",
1613
+ label: t("toggle-expand.label"),
1614
+ // Disclosure semantics are carried here for AT users that interact with the caret
1615
+ // rather than the title.
1616
+ "aria-expanded": triggerProps["aria-expanded"],
1617
+ "aria-controls": triggerProps["aria-controls"],
1618
+ onClick: handleClick,
1619
+ ...props
1620
+ });
1621
+ };
1622
+ var OrderedListDetailItem = ({ id, item, canDrag, title, titleClassNames, actions, trailing, expandable = true, classNames, children }) => {
1623
+ const grid = useListGrid({
1624
+ trailing: !!trailing
1625
+ });
1626
+ return /* @__PURE__ */ React10.createElement(OrderedListItem, {
1627
+ id,
1628
+ item,
1629
+ canDrag,
1630
+ // The grid template is inline so the row's three slots (handle / card / trailing)
1631
+ // land in fixed-width tracks that share a baseline with the title row inside the card.
1632
+ // See useListGrid for the rationale.
1633
+ style: grid.rowProps.style,
1634
+ classNames: mx8(grid.rowProps.className, "pb-1", classNames)
1635
+ }, /* @__PURE__ */ React10.createElement(OrderedListDragHandle, null), /* @__PURE__ */ React10.createElement("div", {
1636
+ className: styles7.orderedListDetailColumn()
1637
+ }, /* @__PURE__ */ React10.createElement("div", {
1638
+ className: styles7.orderedListDetailTitleRow()
1639
+ }, expandable ? /* @__PURE__ */ React10.createElement(OrderedListTitle, {
1640
+ classNames: mx8("px-2", titleClassNames)
1641
+ }, title) : (
1642
+ // When the row is not expandable, render a plain (non-toggling) title so a click
1643
+ // doesn't mutate hidden disclosure state. Mirrors `OrderedListTitle`'s structure
1644
+ // minus the trigger plumbing.
1645
+ /* @__PURE__ */ React10.createElement("div", {
1646
+ className: styles7.orderedListTitle({
1647
+ class: mx8("cursor-auto px-2", titleClassNames)
1648
+ })
1649
+ }, title)
1650
+ ), actions, expandable && /* @__PURE__ */ React10.createElement(OrderedListExpandCaret, null)), expandable && /* @__PURE__ */ React10.createElement(DetailPanel, null, children)), trailing);
1651
+ };
1652
+ var DetailPanel = ({ children }) => {
1653
+ const { expanded, panelProps } = useOrderedListItemContext("OrderedListDetailItem.Panel");
1654
+ if (!expanded || !children) {
1655
+ return null;
1656
+ }
1657
+ return /* @__PURE__ */ React10.createElement("div", {
1658
+ ...panelProps,
1659
+ className: styles7.orderedListDetailPanel()
987
1660
  }, children);
1661
+ };
1662
+
1663
+ // src/components/OrderedList/OrderedList.tsx
1664
+ var OrderedList = {
1665
+ Root: OrderedListRoot,
1666
+ Viewport: OrderedListViewport,
1667
+ Content: OrderedListContent,
1668
+ Item: OrderedListItem,
1669
+ DetailItem: OrderedListDetailItem,
1670
+ DragHandle: OrderedListDragHandle,
1671
+ Title: OrderedListTitle,
1672
+ IconButton: OrderedListIconButton,
1673
+ DeleteButton: OrderedListDeleteButton,
1674
+ ExpandCaret: OrderedListExpandCaret
1675
+ };
1676
+
1677
+ // src/components/Tree/Tree.tsx
1678
+ import { useAtomValue as useAtomValue2 } from "@effect-atom/atom-react";
1679
+ import React16, { useMemo as useMemo8 } from "react";
1680
+
1681
+ // src/components/Treegrid/Treegrid.tsx
1682
+ import { useFocusFinders } from "@fluentui/react-tabster";
1683
+ import { createContextScope } from "@radix-ui/react-context";
1684
+ import { Primitive } from "@radix-ui/react-primitive";
1685
+ import { Slot as Slot2 } from "@radix-ui/react-slot";
1686
+ import { useControllableState as useControllableState2 } from "@radix-ui/react-use-controllable-state";
1687
+ import React11, { forwardRef as forwardRef5, useCallback as useCallback9 } from "react";
1688
+ import { composable as composable5, composableProps as composableProps5 } from "@dxos/react-ui";
1689
+ import { mx as mx9 } from "@dxos/ui-theme";
1690
+
1691
+ // src/components/Treegrid/Treegrid.theme.ts
1692
+ import { tv as tv2 } from "@dxos/ui-theme";
1693
+ var levelStyles = /* @__PURE__ */ new Map([
1694
+ [
1695
+ 1,
1696
+ "[&>.indent:first-of-type]:pl-0 font-medium"
1697
+ ],
1698
+ [
1699
+ 2,
1700
+ "[&>.indent:first-of-type]:pl-0"
1701
+ ],
1702
+ [
1703
+ 3,
1704
+ "[&>.indent:first-of-type]:pl-1"
1705
+ ],
1706
+ [
1707
+ 4,
1708
+ "[&>.indent:first-of-type]:pl-2"
1709
+ ],
1710
+ [
1711
+ 5,
1712
+ "[&>.indent:first-of-type]:pl-3"
1713
+ ],
1714
+ [
1715
+ 6,
1716
+ "[&>.indent:first-of-type]:pl-4"
1717
+ ],
1718
+ [
1719
+ 7,
1720
+ "[&>.indent:first-of-type]:pl-5"
1721
+ ],
1722
+ [
1723
+ 8,
1724
+ "[&>.indent:first-of-type]:pl-6"
1725
+ ]
1726
+ ]);
1727
+ var treegridStyles = tv2({
1728
+ slots: {
1729
+ root: "grid",
1730
+ row: "",
1731
+ cell: ""
1732
+ },
1733
+ variants: {
1734
+ // `indent` marks the cell that carries the per-level left padding (selected via `.indent`).
1735
+ indent: {
1736
+ true: {
1737
+ cell: "indent"
1738
+ }
1739
+ }
1740
+ }
988
1741
  });
989
- ListboxOptionLabel.displayName = "Listbox.OptionLabel";
990
- var ListboxOptionIndicator = /* @__PURE__ */ forwardRef3((props, forwardedRef) => {
991
- const { __listboxOptionScope, classNames, ...rootProps } = props;
992
- const { isSelected } = useListboxOptionContext(LISTBOX_OPTION_INDICATOR_NAME, __listboxOptionScope);
993
- return /* @__PURE__ */ React8.createElement(Icon3, {
994
- icon: "ph--check--regular",
995
- ...rootProps,
996
- classNames: mx6(!isSelected && "invisible", classNames),
1742
+ var treegridTheme = {
1743
+ styles: treegridStyles,
1744
+ /** Row class for a 1-based depth level (clamped to 1–8). */
1745
+ rowLevel: (level) => levelStyles.get(Math.min(Math.max(Math.round(level), 1), 8)) ?? ""
1746
+ };
1747
+
1748
+ // src/components/Treegrid/Treegrid.tsx
1749
+ var styles8 = treegridTheme.styles();
1750
+ var TREEGRID_ROW_NAME = "Treegrid.Row";
1751
+ var [createTreegridRowContext, createTreegridRowScope] = createContextScope(TREEGRID_ROW_NAME, []);
1752
+ var [TreegridRowProvider, useTreegridRowContext] = createTreegridRowContext(TREEGRID_ROW_NAME);
1753
+ var TREEGRID_PATH_SEPARATOR = "~";
1754
+ var TREEGRID_PARENT_OF_SEPARATOR = " ";
1755
+ var TreegridRoot = composable5(({ asChild, classNames, children, style, gridTemplateColumns, onKeyDown: onKeyDownProp, ...props }, forwardedRef) => {
1756
+ const { className, role: _role, ...rest } = composableProps5(props, {
1757
+ classNames
1758
+ });
1759
+ const Comp = asChild ? Slot2 : Primitive.div;
1760
+ const { findFirstFocusable } = useFocusFinders();
1761
+ const handleKeyDown = useCallback9((event) => {
1762
+ switch (event.key) {
1763
+ case "ArrowDown":
1764
+ case "ArrowUp": {
1765
+ const direction = event.key === "ArrowDown" ? "down" : "up";
1766
+ const target = event.target;
1767
+ const ancestorWithArrowKeys = target.closest(`[data-arrow-keys*="${direction}"], [data-arrow-keys="all"]`);
1768
+ if (!ancestorWithArrowKeys) {
1769
+ const currentRow = target.closest('[role="row"]');
1770
+ if (currentRow) {
1771
+ const treegrid = currentRow.closest('[role="treegrid"]');
1772
+ if (treegrid) {
1773
+ const rows = Array.from(treegrid.querySelectorAll('[role="row"]'));
1774
+ const currentIndex = rows.indexOf(currentRow);
1775
+ const nextIndex = direction === "down" ? currentIndex + 1 : currentIndex - 1;
1776
+ const targetRow = rows[nextIndex];
1777
+ if (targetRow) {
1778
+ const firstFocusable = findFirstFocusable(targetRow);
1779
+ if (firstFocusable) {
1780
+ event.preventDefault();
1781
+ firstFocusable.focus();
1782
+ }
1783
+ }
1784
+ }
1785
+ }
1786
+ }
1787
+ break;
1788
+ }
1789
+ }
1790
+ onKeyDownProp?.(event);
1791
+ }, [
1792
+ findFirstFocusable,
1793
+ onKeyDownProp
1794
+ ]);
1795
+ return /* @__PURE__ */ React11.createElement(Comp, {
1796
+ role: "treegrid",
1797
+ ...rest,
1798
+ className: styles8.root({
1799
+ class: mx9(className)
1800
+ }),
1801
+ style: {
1802
+ ...style,
1803
+ gridTemplateColumns
1804
+ },
1805
+ onKeyDown: handleKeyDown,
997
1806
  ref: forwardedRef
1807
+ }, children);
1808
+ });
1809
+ var TreegridRow = /* @__PURE__ */ forwardRef5(({ __treegridRowScope, asChild, classNames, children, id, parentOf, open: propsOpen, defaultOpen, onOpenChange: propsOnOpenChange, ...props }, forwardedRef) => {
1810
+ const Comp = asChild ? Slot2 : Primitive.div;
1811
+ const pathParts = id.split(TREEGRID_PATH_SEPARATOR);
1812
+ const level = pathParts.length - 1;
1813
+ const [open, onOpenChange] = useControllableState2({
1814
+ prop: propsOpen,
1815
+ onChange: propsOnOpenChange,
1816
+ defaultProp: defaultOpen
998
1817
  });
1818
+ return /* @__PURE__ */ React11.createElement(TreegridRowProvider, {
1819
+ open,
1820
+ onOpenChange,
1821
+ scope: __treegridRowScope
1822
+ }, /* @__PURE__ */ React11.createElement(Comp, {
1823
+ role: "row",
1824
+ "aria-level": level,
1825
+ className: styles8.row({
1826
+ class: mx9(treegridTheme.rowLevel(level), classNames)
1827
+ }),
1828
+ ...parentOf && {
1829
+ "aria-expanded": open,
1830
+ "aria-owns": parentOf
1831
+ },
1832
+ ...props,
1833
+ id,
1834
+ ref: forwardedRef
1835
+ }, children));
999
1836
  });
1000
- ListboxOptionIndicator.displayName = "Listbox.OptionIndicator";
1001
- var Listbox = {
1002
- Root: ListboxRoot,
1003
- Option: ListboxOption,
1004
- OptionLabel: ListboxOptionLabel,
1005
- OptionIndicator: ListboxOptionIndicator
1837
+ var TreegridCell = /* @__PURE__ */ forwardRef5(({ classNames, children, indent, ...props }, forwardedRef) => {
1838
+ return /* @__PURE__ */ React11.createElement("div", {
1839
+ role: "gridcell",
1840
+ className: styles8.cell({
1841
+ indent,
1842
+ class: mx9(classNames)
1843
+ }),
1844
+ ...props,
1845
+ ref: forwardedRef
1846
+ }, children);
1847
+ });
1848
+ var Treegrid = {
1849
+ Root: TreegridRoot,
1850
+ Row: TreegridRow,
1851
+ Cell: TreegridCell
1006
1852
  };
1007
1853
 
1008
- // src/components/Tree/Tree.tsx
1009
- import { useAtomValue as useAtomValue2 } from "@effect-atom/atom-react";
1010
- import React12, { useMemo as useMemo3 } from "react";
1011
- import { Treegrid as Treegrid2 } from "@dxos/react-ui";
1012
-
1013
1854
  // src/components/Tree/TreeContext.tsx
1014
- import { createContext as createContext7, useContext } from "react";
1855
+ import { createContext as createContext8, useContext } from "react";
1015
1856
  import { raise } from "@dxos/debug";
1016
- var TreeContext = /* @__PURE__ */ createContext7(null);
1857
+ var TreeContext = /* @__PURE__ */ createContext8(null);
1017
1858
  var TreeProvider = TreeContext.Provider;
1018
1859
  var useTree = () => useContext(TreeContext) ?? raise(new Error("TreeContext not found"));
1019
1860
 
@@ -1023,10 +1864,10 @@ import { combine as combine2 } from "@atlaskit/pragmatic-drag-and-drop/combine";
1023
1864
  import { draggable as draggable2, dropTargetForElements as dropTargetForElements2 } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
1024
1865
  import { useAtomValue } from "@effect-atom/atom-react";
1025
1866
  import * as Schema from "effect/Schema";
1026
- import React11, { memo as memo3, useCallback as useCallback6, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef3, useState as useState4 } from "react";
1027
- import { invariant as invariant2 } from "@dxos/invariant";
1028
- import { TreeItem as NaturalTreeItem, Treegrid, TREEGRID_PARENT_OF_SEPARATOR } from "@dxos/react-ui";
1029
- import { ghostFocusWithin, ghostHover, hoverableControls, hoverableFocusedKeyboardControls, hoverableFocusedWithinControls, mx as mx7 } from "@dxos/ui-theme";
1867
+ import React15, { memo as memo3, useCallback as useCallback11, useEffect as useEffect5, useMemo as useMemo7, useRef as useRef5, useState as useState5 } from "react";
1868
+ import { invariant } from "@dxos/invariant";
1869
+ import { toLocalizedString as toLocalizedString2, useTranslation as useTranslation4 } from "@dxos/react-ui";
1870
+ import { ghostFocusWithin, ghostHover, hoverableControls, hoverableFocusedKeyboardControls, hoverableFocusedWithinControls, mx as mx10 } from "@dxos/ui-theme";
1030
1871
 
1031
1872
  // src/components/Tree/helpers.ts
1032
1873
  var DEFAULT_INDENTATION = 8;
@@ -1034,20 +1875,62 @@ var paddingIndentation = (level, indentation = DEFAULT_INDENTATION) => ({
1034
1875
  paddingInlineStart: `${(level - 1) * indentation}px`
1035
1876
  });
1036
1877
 
1878
+ // src/components/Tree/TreeDropIndicator.tsx
1879
+ import React12 from "react";
1880
+ var edgeToOrientationMap2 = {
1881
+ "reorder-above": "sibling",
1882
+ "reorder-below": "sibling",
1883
+ "make-child": "child",
1884
+ "reparent": "child"
1885
+ };
1886
+ var orientationStyles2 = {
1887
+ sibling: "h-(--line-thickness) left-(--horizontal-indent) right-0 bg-accent-bg before:left-(--negative-terminal-size)",
1888
+ child: "inset-0 border-[length:var(--line-thickness)] before:invisible"
1889
+ };
1890
+ var instructionStyles = {
1891
+ "reorder-above": "top-(--line-offset) before:top-(--offset-terminal)",
1892
+ "reorder-below": "bottom-(--line-offset) before:bottom-(--offset-terminal)",
1893
+ "make-child": "border-accent-bg",
1894
+ "reparent": ""
1895
+ };
1896
+ var strokeSize2 = 2;
1897
+ var terminalSize2 = 8;
1898
+ var offsetToAlignTerminalWithLine2 = (strokeSize2 - terminalSize2) / 2;
1899
+ var TreeDropIndicator = ({ instruction, gap = 0 }) => {
1900
+ const lineOffset = `calc(-0.5 * (${gap}px + ${strokeSize2}px))`;
1901
+ const isBlocked = instruction.type === "instruction-blocked";
1902
+ const desiredInstruction = isBlocked ? instruction.desired : instruction;
1903
+ const orientation = edgeToOrientationMap2[desiredInstruction.type];
1904
+ if (isBlocked) {
1905
+ return null;
1906
+ }
1907
+ return /* @__PURE__ */ React12.createElement("div", {
1908
+ style: {
1909
+ "--line-thickness": `${strokeSize2}px`,
1910
+ "--line-offset": `${lineOffset}`,
1911
+ "--terminal-size": `${terminalSize2}px`,
1912
+ "--terminal-radius": `${terminalSize2 / 2}px`,
1913
+ "--negative-terminal-size": `-${terminalSize2}px`,
1914
+ "--offset-terminal": `${offsetToAlignTerminalWithLine2}px`,
1915
+ "--horizontal-indent": `${desiredInstruction.currentLevel * desiredInstruction.indentPerLevel + 4}px`
1916
+ },
1917
+ className: `absolute z-10 pointer-events-none before:w-(--terminal-size) before:h-(--terminal-size) box-border before:absolute before:border-[length:--line-thickness] before:border-solid before:border-accent-bg before:rounded-full ${orientationStyles2[orientation]} ${instructionStyles[desiredInstruction.type]}`
1918
+ });
1919
+ };
1920
+
1037
1921
  // src/components/Tree/TreeItemHeading.tsx
1038
- import React9, { forwardRef as forwardRef4, memo, useCallback as useCallback5 } from "react";
1039
- import { Button as Button2, Icon as Icon4, Tag, toLocalizedString, useTranslation as useTranslation2 } from "@dxos/react-ui";
1040
- import { TextTooltip } from "@dxos/react-ui-text-tooltip";
1922
+ import React13, { forwardRef as forwardRef6, memo, useCallback as useCallback10 } from "react";
1923
+ import { Button as Button2, Icon as Icon6, Tag, TextTooltip, toLocalizedString, useTranslation as useTranslation3 } from "@dxos/react-ui";
1041
1924
  import { getStyles } from "@dxos/ui-theme";
1042
- var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef4(({ label, className, icon, iconHue, disabled, current, count, modifiedCount, onSelect }, forwardedRef) => {
1043
- const { t } = useTranslation2();
1044
- const styles = iconHue ? getStyles(iconHue) : void 0;
1045
- const handleSelect = useCallback5((event) => {
1925
+ var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef6(({ label, className, icon, iconHue, disabled, current, count, modifiedCount, onSelect }, forwardedRef) => {
1926
+ const { t } = useTranslation3();
1927
+ const styles9 = iconHue ? getStyles(iconHue) : void 0;
1928
+ const handleSelect = useCallback10((event) => {
1046
1929
  onSelect?.(event.altKey);
1047
1930
  }, [
1048
1931
  onSelect
1049
1932
  ]);
1050
- const handleButtonKeydown = useCallback5((event) => {
1933
+ const handleButtonKeydown = useCallback10((event) => {
1051
1934
  if (event.key === " " || event.key === "Enter") {
1052
1935
  event.preventDefault();
1053
1936
  event.stopPropagation();
@@ -1056,14 +1939,14 @@ var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef4(({ label,
1056
1939
  }, [
1057
1940
  onSelect
1058
1941
  ]);
1059
- return /* @__PURE__ */ React9.createElement(TextTooltip, {
1942
+ return /* @__PURE__ */ React13.createElement(TextTooltip, {
1060
1943
  text: toLocalizedString(label, t),
1061
1944
  side: "bottom",
1062
1945
  truncateQuery: "span[data-tooltip]",
1063
1946
  onlyWhenTruncating: true,
1064
1947
  asChild: true,
1065
1948
  ref: forwardedRef
1066
- }, /* @__PURE__ */ React9.createElement(Button2, {
1949
+ }, /* @__PURE__ */ React13.createElement(Button2, {
1067
1950
  "data-testid": "treeItem.heading",
1068
1951
  variant: "ghost",
1069
1952
  classNames: [
@@ -1077,31 +1960,31 @@ var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef4(({ label,
1077
1960
  ...current && {
1078
1961
  "aria-current": "location"
1079
1962
  }
1080
- }, icon && /* @__PURE__ */ React9.createElement(Icon4, {
1963
+ }, icon && /* @__PURE__ */ React13.createElement(Icon6, {
1081
1964
  size: 5,
1082
1965
  icon: icon ?? "ph--circle-dashed--regular",
1083
1966
  classNames: [
1084
1967
  "my-1",
1085
- styles?.text
1968
+ styles9?.text
1086
1969
  ]
1087
- }), /* @__PURE__ */ React9.createElement("span", {
1970
+ }), /* @__PURE__ */ React13.createElement("span", {
1088
1971
  className: "min-w-0 truncate text-start font-normal",
1089
1972
  "data-tooltip": true
1090
- }, toLocalizedString(label, t)), /* @__PURE__ */ React9.createElement(CountBadge, {
1973
+ }, toLocalizedString(label, t)), /* @__PURE__ */ React13.createElement(CountBadge, {
1091
1974
  count,
1092
1975
  modifiedCount
1093
1976
  })));
1094
1977
  }));
1095
1978
  var CountBadge = ({ count, modifiedCount }) => {
1096
1979
  if (typeof modifiedCount === "number" && modifiedCount > 0) {
1097
- return /* @__PURE__ */ React9.createElement(Tag, {
1098
- palette: "rose",
1980
+ return /* @__PURE__ */ React13.createElement(Tag, {
1981
+ hue: "rose",
1099
1982
  classNames: "shrink-0 text-center [min-inline-size:1.5rem] tabular-nums"
1100
1983
  }, modifiedCount);
1101
1984
  }
1102
1985
  if (typeof count === "number") {
1103
- return /* @__PURE__ */ React9.createElement(Tag, {
1104
- palette: "neutral",
1986
+ return /* @__PURE__ */ React13.createElement(Tag, {
1987
+ hue: "neutral",
1105
1988
  classNames: "shrink-0 text-center [min-inline-size:1.5rem] tabular-nums"
1106
1989
  }, count);
1107
1990
  }
@@ -1109,10 +1992,10 @@ var CountBadge = ({ count, modifiedCount }) => {
1109
1992
  };
1110
1993
 
1111
1994
  // src/components/Tree/TreeItemToggle.tsx
1112
- import React10, { forwardRef as forwardRef5, memo as memo2 } from "react";
1995
+ import React14, { forwardRef as forwardRef7, memo as memo2 } from "react";
1113
1996
  import { IconButton as IconButton2 } from "@dxos/react-ui";
1114
- var TreeItemToggle = /* @__PURE__ */ memo2(/* @__PURE__ */ forwardRef5(({ classNames, open, isBranch, hidden, ...props }, forwardedRef) => {
1115
- return /* @__PURE__ */ React10.createElement(IconButton2, {
1997
+ var TreeItemToggle = /* @__PURE__ */ memo2(/* @__PURE__ */ forwardRef7(({ classNames, open, isBranch, hidden, ...props }, forwardedRef) => {
1998
+ return /* @__PURE__ */ React14.createElement(IconButton2, {
1116
1999
  ref: forwardedRef,
1117
2000
  "data-testid": "treeItem.toggle",
1118
2001
  "aria-expanded": open,
@@ -1136,8 +2019,16 @@ var TreeItemToggle = /* @__PURE__ */ memo2(/* @__PURE__ */ forwardRef5(({ classN
1136
2019
  }));
1137
2020
 
1138
2021
  // src/components/Tree/TreeItem.tsx
1139
- var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-list/src/components/Tree/TreeItem.tsx";
2022
+ var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-list/src/components/Tree/TreeItem.tsx";
1140
2023
  var hoverableDescriptionIcons = "[--icons-color:inherit] hover-hover:[--icons-color:var(--description-text)] hover-hover:hover:[--icons-color:inherit] focus-within:[--icons-color:inherit]";
2024
+ var NavTreeSectionHeader = ({ label }) => {
2025
+ const { t } = useTranslation4();
2026
+ return /* @__PURE__ */ React15.createElement("div", {
2027
+ role: "heading",
2028
+ "aria-level": 2,
2029
+ className: "col-[tree-row] pl-7 pt-3 pb-0.5 text-xs uppercase tracking-widest text-subdued hover:text-description select-none"
2030
+ }, toLocalizedString2(label, t));
2031
+ };
1141
2032
  var TreeDataSchema = Schema.Struct({
1142
2033
  id: Schema.String,
1143
2034
  path: Schema.Array(Schema.String),
@@ -1145,22 +2036,22 @@ var TreeDataSchema = Schema.Struct({
1145
2036
  });
1146
2037
  var isTreeData = (data) => Schema.is(TreeDataSchema)(data);
1147
2038
  var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: draggableProp, renderColumns: Columns, blockInstruction, canDrop, canSelect, onOpenChange, onSelect, onItemHover }) => {
1148
- const rowRef = useRef3(null);
1149
- const buttonRef = useRef3(null);
1150
- const openRef = useRef3(false);
1151
- const cancelExpandRef = useRef3(null);
1152
- const [_state, setState] = useState4("idle");
1153
- const [instruction, setInstruction] = useState4(null);
1154
- const [menuOpen, setMenuOpen] = useState4(false);
2039
+ const rowRef = useRef5(null);
2040
+ const buttonRef = useRef5(null);
2041
+ const openRef = useRef5(false);
2042
+ const cancelExpandRef = useRef5(null);
2043
+ const [_state, setState] = useState5("idle");
2044
+ const [instruction, setInstruction] = useState5(null);
2045
+ const [menuOpen, setMenuOpen] = useState5(false);
1155
2046
  const { itemProps: itemPropsAtom, childIds: childIdsAtom, itemOpen: itemOpenAtom, itemCurrent: itemCurrentAtom } = useTree();
1156
- const path = useMemo2(() => [
2047
+ const path = useMemo7(() => [
1157
2048
  ...pathProp,
1158
2049
  item.id
1159
2050
  ], [
1160
2051
  pathProp,
1161
2052
  item.id
1162
2053
  ]);
1163
- const { id, parentOf, draggable: itemDraggable, droppable: itemDroppable, label, className, headingClassName, icon, iconHue, disabled, testId, count, modifiedCount } = useAtomValue(itemPropsAtom(path));
2054
+ const { id, parentOf, disposition, draggable: itemDraggable, droppable: itemDroppable, label, className, headingClassName, icon, iconHue, disabled, testId, count, modifiedCount } = useAtomValue(itemPropsAtom(path));
1164
2055
  const childIds = useAtomValue(childIdsAtom(item.id));
1165
2056
  const open = useAtomValue(itemOpenAtom(path));
1166
2057
  const current = useAtomValue(itemCurrentAtom(path));
@@ -1177,7 +2068,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1177
2068
  item
1178
2069
  };
1179
2070
  const shouldSeedNativeDragData = typeof document !== "undefined" && document.body.hasAttribute("data-platform");
1180
- const cancelExpand = useCallback6(() => {
2071
+ const cancelExpand = useCallback11(() => {
1181
2072
  if (cancelExpandRef.current) {
1182
2073
  clearTimeout(cancelExpandRef.current);
1183
2074
  cancelExpandRef.current = null;
@@ -1186,11 +2077,11 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1186
2077
  const isItemDraggable = draggableProp && itemDraggable !== false;
1187
2078
  const isItemDroppable = itemDroppable !== false;
1188
2079
  const nativeDragText = id;
1189
- useEffect4(() => {
1190
- if (!draggableProp) {
2080
+ useEffect5(() => {
2081
+ if (!draggableProp || !isItemDraggable && !isItemDroppable) {
1191
2082
  return;
1192
2083
  }
1193
- invariant2(buttonRef.current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 70, S: void 0, A: ["buttonRef.current", ""] });
2084
+ invariant(buttonRef.current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 80, S: void 0, A: ["buttonRef.current", ""] });
1194
2085
  const makeDraggable = () => draggable2({
1195
2086
  element: buttonRef.current,
1196
2087
  getInitialData: () => data,
@@ -1305,10 +2196,10 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1305
2196
  blockInstruction,
1306
2197
  canDrop
1307
2198
  ]);
1308
- useEffect4(() => () => cancelExpand(), [
2199
+ useEffect5(() => () => cancelExpand(), [
1309
2200
  cancelExpand
1310
2201
  ]);
1311
- const handleOpenToggle = useCallback6(() => onOpenChange?.({
2202
+ const handleOpenToggle = useCallback11(() => onOpenChange?.({
1312
2203
  item,
1313
2204
  path,
1314
2205
  open: !open
@@ -1318,7 +2209,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1318
2209
  path,
1319
2210
  open
1320
2211
  ]);
1321
- const handleSelect = useCallback6((option = false) => {
2212
+ const handleSelect = useCallback11((option = false) => {
1322
2213
  if (isBranch && (option || current)) {
1323
2214
  handleOpenToggle();
1324
2215
  } else if (canSelectItem) {
@@ -1343,7 +2234,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1343
2234
  handleOpenToggle,
1344
2235
  onSelect
1345
2236
  ]);
1346
- const handleKeyDown = useCallback6((event) => {
2237
+ const handleKeyDown = useCallback11((event) => {
1347
2238
  switch (event.key) {
1348
2239
  case "ArrowRight":
1349
2240
  case "ArrowLeft":
@@ -1356,7 +2247,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1356
2247
  handleOpenToggle,
1357
2248
  handleSelect
1358
2249
  ]);
1359
- const handleItemHover = useCallback6(() => {
2250
+ const handleItemHover = useCallback11(() => {
1360
2251
  onItemHover?.({
1361
2252
  item
1362
2253
  });
@@ -1364,7 +2255,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1364
2255
  onItemHover,
1365
2256
  item
1366
2257
  ]);
1367
- const handleContextMenu = useCallback6((event) => {
2258
+ const handleContextMenu = useCallback11((event) => {
1368
2259
  event.preventDefault();
1369
2260
  setMenuOpen(true);
1370
2261
  }, [
@@ -1380,7 +2271,22 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1380
2271
  onOpenChange,
1381
2272
  onSelect
1382
2273
  };
1383
- return /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(Treegrid.Row, {
2274
+ if (disposition === "group") {
2275
+ if (childIds.length === 0) {
2276
+ return null;
2277
+ }
2278
+ return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(NavTreeSectionHeader, {
2279
+ label
2280
+ }), childIds.map((childId, index) => /* @__PURE__ */ React15.createElement(TreeItemById, {
2281
+ key: childId,
2282
+ id: childId,
2283
+ path,
2284
+ last: index === childIds.length - 1,
2285
+ levelOffset: levelOffset + 1,
2286
+ ...childProps
2287
+ })));
2288
+ }
2289
+ return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(Treegrid.Row, {
1384
2290
  ref: rowRef,
1385
2291
  key: id,
1386
2292
  id,
@@ -1392,20 +2298,31 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1392
2298
  // without alerting the user (except for in the correct link element). See also:
1393
2299
  // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current#description
1394
2300
  "aria-current": current ? "" : void 0,
1395
- classNames: mx7("grid grid-cols-subgrid col-[tree-row] mt-0.5 is-current:bg-current-surface", hoverableControls, hoverableFocusedKeyboardControls, hoverableFocusedWithinControls, hoverableDescriptionIcons, ghostFocusWithin, ghostHover, className),
2301
+ classNames: mx10(
2302
+ "grid grid-cols-subgrid col-[tree-row] mt-0.5 is-current:bg-current-surface",
2303
+ // Highlight the row while a descendant marks an open popover anchor (e.g. inline rename).
2304
+ "has-[[data-popover-anchor]]:bg-current-surface",
2305
+ hoverableControls,
2306
+ hoverableFocusedKeyboardControls,
2307
+ hoverableFocusedWithinControls,
2308
+ hoverableDescriptionIcons,
2309
+ ghostFocusWithin,
2310
+ ghostHover,
2311
+ className
2312
+ ),
1396
2313
  onKeyDown: handleKeyDown,
1397
2314
  onMouseEnter: handleItemHover,
1398
2315
  onContextMenu: handleContextMenu
1399
- }, /* @__PURE__ */ React11.createElement("div", {
2316
+ }, /* @__PURE__ */ React15.createElement("div", {
1400
2317
  className: "indent relative grid grid-cols-subgrid col-[tree-row]",
1401
2318
  style: paddingIndentation(level)
1402
- }, /* @__PURE__ */ React11.createElement(Treegrid.Cell, {
2319
+ }, /* @__PURE__ */ React15.createElement(Treegrid.Cell, {
1403
2320
  classNames: "flex items-center"
1404
- }, /* @__PURE__ */ React11.createElement(TreeItemToggle, {
2321
+ }, /* @__PURE__ */ React15.createElement(TreeItemToggle, {
1405
2322
  isBranch,
1406
2323
  open,
1407
2324
  onClick: handleOpenToggle
1408
- }), /* @__PURE__ */ React11.createElement(TreeItemHeading, {
2325
+ }), /* @__PURE__ */ React15.createElement(TreeItemHeading, {
1409
2326
  disabled,
1410
2327
  current,
1411
2328
  label,
@@ -1416,16 +2333,16 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1416
2333
  modifiedCount,
1417
2334
  onSelect: handleSelect,
1418
2335
  ref: buttonRef
1419
- })), Columns && /* @__PURE__ */ React11.createElement(Columns, {
2336
+ })), Columns && /* @__PURE__ */ React15.createElement(Columns, {
1420
2337
  item,
1421
2338
  path,
1422
2339
  open,
1423
2340
  menuOpen,
1424
2341
  setMenuOpen
1425
- }), instruction && /* @__PURE__ */ React11.createElement(NaturalTreeItem.DropIndicator, {
2342
+ }), instruction && /* @__PURE__ */ React15.createElement(TreeDropIndicator, {
1426
2343
  instruction,
1427
2344
  gap: 2
1428
- }))), open && childIds.map((childId, index) => /* @__PURE__ */ React11.createElement(TreeItemById, {
2345
+ }))), open && childIds.map((childId, index) => /* @__PURE__ */ React15.createElement(TreeItemById, {
1429
2346
  key: childId,
1430
2347
  id: childId,
1431
2348
  path,
@@ -1440,7 +2357,7 @@ var RawTreeItemById = ({ id, ...props }) => {
1440
2357
  if (!item) {
1441
2358
  return null;
1442
2359
  }
1443
- return /* @__PURE__ */ React11.createElement(TreeItem, {
2360
+ return /* @__PURE__ */ React15.createElement(TreeItem, {
1444
2361
  item,
1445
2362
  ...props
1446
2363
  });
@@ -1448,9 +2365,17 @@ var RawTreeItemById = ({ id, ...props }) => {
1448
2365
  var TreeItemById = /* @__PURE__ */ memo3(RawTreeItemById);
1449
2366
 
1450
2367
  // src/components/Tree/Tree.tsx
2368
+ var TreeChild = ({ id, path: parentPath, last, ...childProps }) => {
2369
+ return /* @__PURE__ */ React16.createElement(TreeItemById, {
2370
+ id,
2371
+ path: parentPath,
2372
+ last,
2373
+ ...childProps
2374
+ });
2375
+ };
1451
2376
  var Tree = ({ classNames, model, rootId, path, id, draggable: draggable3 = false, gridTemplateColumns = "[tree-row-start] minmax(0, 1fr) min-content [tree-row-end]", levelOffset, renderColumns, blockInstruction, canDrop, canSelect, onOpenChange, onSelect, onItemHover }) => {
1452
2377
  const childIds = useAtomValue2(model.childIds(rootId));
1453
- const treePath = useMemo3(() => path ? [
2378
+ const treePath = useMemo8(() => path ? [
1454
2379
  ...path,
1455
2380
  id
1456
2381
  ] : [
@@ -1471,12 +2396,12 @@ var Tree = ({ classNames, model, rootId, path, id, draggable: draggable3 = false
1471
2396
  onSelect,
1472
2397
  onItemHover
1473
2398
  };
1474
- return /* @__PURE__ */ React12.createElement(Treegrid2.Root, {
2399
+ return /* @__PURE__ */ React16.createElement(Treegrid.Root, {
1475
2400
  gridTemplateColumns,
1476
2401
  classNames
1477
- }, /* @__PURE__ */ React12.createElement(TreeProvider, {
2402
+ }, /* @__PURE__ */ React16.createElement(TreeProvider, {
1478
2403
  value: model
1479
- }, childIds.map((childId, index) => /* @__PURE__ */ React12.createElement(TreeItemById, {
2404
+ }, childIds.map((childId, index) => /* @__PURE__ */ React16.createElement(TreeChild, {
1480
2405
  key: childId,
1481
2406
  id: childId,
1482
2407
  last: index === childIds.length - 1,
@@ -1503,25 +2428,33 @@ export {
1503
2428
  Accordion,
1504
2429
  Combobox,
1505
2430
  DEFAULT_INDENTATION,
1506
- List,
2431
+ DropIndicator,
2432
+ Empty,
1507
2433
  Listbox,
2434
+ OrderedList,
1508
2435
  Path,
1509
2436
  Picker,
1510
- Row,
1511
- RowList,
2437
+ TREEGRID_PARENT_OF_SEPARATOR,
2438
+ TREEGRID_PATH_SEPARATOR,
1512
2439
  Tree,
1513
2440
  TreeDataSchema,
1514
2441
  TreeItem,
1515
2442
  TreeItemById,
1516
2443
  TreeItemToggle,
1517
2444
  TreeProvider,
1518
- createListboxScope,
1519
- createRowListScope,
2445
+ Treegrid,
1520
2446
  isTreeData,
1521
2447
  paddingIndentation,
2448
+ useListDisclosure,
2449
+ useListGrid,
2450
+ useListNavigation,
2451
+ useListSelection,
2452
+ useListboxSelection,
1522
2453
  usePickerInputContext,
1523
2454
  usePickerItemContext,
1524
- useRowListSelection,
2455
+ useReorderAutoScroll,
2456
+ useReorderItem,
2457
+ useReorderList,
1525
2458
  useTree
1526
2459
  };
1527
2460
  //# sourceMappingURL=index.mjs.map