@dxos/react-ui-list 0.8.4-main.3f58842 → 0.8.4-main.40e3dcdf1b

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 (55) hide show
  1. package/dist/lib/browser/index.mjs +684 -726
  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 +684 -726
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/components/Accordion/Accordion.stories.d.ts +7 -4
  8. package/dist/types/src/components/Accordion/Accordion.stories.d.ts.map +1 -1
  9. package/dist/types/src/components/Accordion/AccordionItem.d.ts +1 -1
  10. package/dist/types/src/components/Accordion/AccordionItem.d.ts.map +1 -1
  11. package/dist/types/src/components/List/List.d.ts +9 -9
  12. package/dist/types/src/components/List/List.d.ts.map +1 -1
  13. package/dist/types/src/components/List/List.stories.d.ts +14 -5
  14. package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
  15. package/dist/types/src/components/List/ListItem.d.ts +9 -10
  16. package/dist/types/src/components/List/ListItem.d.ts.map +1 -1
  17. package/dist/types/src/components/List/ListRoot.d.ts +2 -2
  18. package/dist/types/src/components/List/ListRoot.d.ts.map +1 -1
  19. package/dist/types/src/components/List/testing.d.ts +1 -1
  20. package/dist/types/src/components/List/testing.d.ts.map +1 -1
  21. package/dist/types/src/components/Tree/Tree.d.ts +10 -6
  22. package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
  23. package/dist/types/src/components/Tree/Tree.stories.d.ts +18 -7
  24. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
  25. package/dist/types/src/components/Tree/TreeContext.d.ts +24 -10
  26. package/dist/types/src/components/Tree/TreeContext.d.ts.map +1 -1
  27. package/dist/types/src/components/Tree/TreeItem.d.ts +32 -10
  28. package/dist/types/src/components/Tree/TreeItem.d.ts.map +1 -1
  29. package/dist/types/src/components/Tree/TreeItemHeading.d.ts +4 -3
  30. package/dist/types/src/components/Tree/TreeItemHeading.d.ts.map +1 -1
  31. package/dist/types/src/components/Tree/TreeItemToggle.d.ts +3 -3
  32. package/dist/types/src/components/Tree/TreeItemToggle.d.ts.map +1 -1
  33. package/dist/types/src/components/Tree/index.d.ts +2 -0
  34. package/dist/types/src/components/Tree/index.d.ts.map +1 -1
  35. package/dist/types/src/components/Tree/testing.d.ts +3 -3
  36. package/dist/types/src/components/Tree/testing.d.ts.map +1 -1
  37. package/dist/types/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +32 -28
  39. package/src/components/Accordion/Accordion.stories.tsx +5 -7
  40. package/src/components/Accordion/Accordion.tsx +1 -1
  41. package/src/components/Accordion/AccordionItem.tsx +8 -5
  42. package/src/components/Accordion/AccordionRoot.tsx +1 -1
  43. package/src/components/List/List.stories.tsx +42 -28
  44. package/src/components/List/List.tsx +3 -6
  45. package/src/components/List/ListItem.tsx +79 -49
  46. package/src/components/List/ListRoot.tsx +3 -3
  47. package/src/components/List/testing.ts +3 -3
  48. package/src/components/Tree/Tree.stories.tsx +172 -79
  49. package/src/components/Tree/Tree.tsx +43 -40
  50. package/src/components/Tree/TreeContext.tsx +21 -9
  51. package/src/components/Tree/TreeItem.tsx +214 -134
  52. package/src/components/Tree/TreeItemHeading.tsx +13 -8
  53. package/src/components/Tree/TreeItemToggle.tsx +29 -18
  54. package/src/components/Tree/index.ts +2 -0
  55. package/src/components/Tree/testing.ts +5 -4
@@ -1,87 +1,65 @@
1
1
  import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
2
 
3
3
  // src/components/Accordion/AccordionItem.tsx
4
- import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
5
4
  import * as AccordionPrimitive2 from "@radix-ui/react-accordion";
6
5
  import { createContext as createContext2 } from "@radix-ui/react-context";
7
6
  import React2 from "react";
8
7
  import { Icon } from "@dxos/react-ui";
9
- import { mx as mx2 } from "@dxos/react-ui-theme";
8
+ import { mx as mx2 } from "@dxos/ui-theme";
10
9
 
11
10
  // src/components/Accordion/AccordionRoot.tsx
12
- import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
13
11
  import * as AccordionPrimitive from "@radix-ui/react-accordion";
14
12
  import { createContext } from "@radix-ui/react-context";
15
13
  import React from "react";
16
- import { mx } from "@dxos/react-ui-theme";
14
+ import { mx } from "@dxos/ui-theme";
17
15
  var ACCORDION_NAME = "Accordion";
18
16
  var [AccordionProvider, useAccordionContext] = createContext(ACCORDION_NAME);
19
17
  var defaultGetId = (item) => item?.id;
20
18
  var AccordionRoot = ({ classNames, items, getId = defaultGetId, children, value, defaultValue, onValueChange }) => {
21
- var _effect = _useSignals();
22
- try {
23
- return /* @__PURE__ */ React.createElement(AccordionProvider, {
24
- getId
25
- }, /* @__PURE__ */ React.createElement(AccordionPrimitive.Root, {
26
- type: "multiple",
27
- value,
28
- defaultValue,
29
- onValueChange,
30
- className: mx(classNames)
31
- }, children?.({
32
- items: items ?? []
33
- })));
34
- } finally {
35
- _effect.f();
36
- }
19
+ return /* @__PURE__ */ React.createElement(AccordionProvider, {
20
+ getId
21
+ }, /* @__PURE__ */ React.createElement(AccordionPrimitive.Root, {
22
+ type: "multiple",
23
+ value,
24
+ defaultValue,
25
+ onValueChange,
26
+ className: mx(classNames)
27
+ }, children?.({
28
+ items: items ?? []
29
+ })));
37
30
  };
38
31
 
39
32
  // src/components/Accordion/AccordionItem.tsx
40
33
  var ACCORDION_ITEM_NAME = "AccordionItem";
41
- var [AccordionItemProvider, useAccordionItemContext] = createContext2(ACCORDION_ITEM_NAME);
34
+ var [AccordionItemProvider, useDxAccordionItemContext] = createContext2(ACCORDION_ITEM_NAME);
42
35
  var AccordionItem = ({ children, classNames, item }) => {
43
- var _effect = _useSignals2();
44
- try {
45
- const { getId } = useAccordionContext(ACCORDION_ITEM_NAME);
46
- return /* @__PURE__ */ React2.createElement(AccordionItemProvider, {
47
- item
48
- }, /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Item, {
49
- value: getId(item),
50
- className: mx2("overflow-hidden", classNames)
51
- }, children));
52
- } finally {
53
- _effect.f();
54
- }
36
+ const { getId } = useAccordionContext(ACCORDION_ITEM_NAME);
37
+ return /* @__PURE__ */ React2.createElement(AccordionItemProvider, {
38
+ item
39
+ }, /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Item, {
40
+ value: getId(item),
41
+ className: mx2("overflow-hidden", classNames)
42
+ }, children));
55
43
  };
56
44
  var AccordionItemHeader = ({ classNames, children, ...props }) => {
57
- var _effect = _useSignals2();
58
- try {
59
- return /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Header, {
60
- ...props,
61
- className: mx2(classNames)
62
- }, /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Trigger, {
63
- className: "group flex items-center p-2 dx-focus-ring-inset is-full text-start"
64
- }, children, /* @__PURE__ */ React2.createElement(Icon, {
65
- icon: "ph--caret-right--regular",
66
- size: 4,
67
- classNames: "transition-transform duration-200 group-data-[state=open]:rotate-90"
68
- })));
69
- } finally {
70
- _effect.f();
71
- }
45
+ return /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Header, {
46
+ ...props,
47
+ className: mx2(classNames)
48
+ }, /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Trigger, {
49
+ className: "group flex items-center p-2 dx-focus-ring-inset w-full text-start"
50
+ }, children, /* @__PURE__ */ React2.createElement(Icon, {
51
+ icon: "ph--caret-right--regular",
52
+ size: 4,
53
+ classNames: "transition-transform duration-200 group-data-[state=open]:rotate-90"
54
+ })));
72
55
  };
73
56
  var AccordionItemBody = ({ children, classNames }) => {
74
- var _effect = _useSignals2();
75
- try {
76
- return /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Content, {
77
- className: "overflow-hidden data-[state=closed]:animate-slideUp data-[state=open]:animate-slideDown"
78
- }, /* @__PURE__ */ React2.createElement("div", {
79
- role: "none",
80
- className: mx2("p-2", classNames)
81
- }, children));
82
- } finally {
83
- _effect.f();
84
- }
57
+ return /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Content, {
58
+ className: "overflow-hidden data-[state=closed]:animate-slide-up data-[state=open]:animate-slide-down"
59
+ }, /* @__PURE__ */ React2.createElement("div", {
60
+ role: "none",
61
+ className: mx2("p-2", classNames)
62
+ }, children));
85
63
  };
86
64
 
87
65
  // src/components/Accordion/Accordion.tsx
@@ -93,20 +71,19 @@ var Accordion = {
93
71
  };
94
72
 
95
73
  // src/components/List/ListItem.tsx
96
- import { useSignals as _useSignals4 } from "@preact-signals/safe-react/tracking";
97
74
  import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
98
75
  import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
99
76
  import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview";
100
77
  import { attachClosestEdge, extractClosestEdge as extractClosestEdge2 } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
101
78
  import { createContext as createContext4 } from "@radix-ui/react-context";
102
- import React4, { forwardRef, useEffect as useEffect2, useRef, useState as useState2 } from "react";
79
+ import { Slot } from "@radix-ui/react-slot";
80
+ import React4, { useEffect as useEffect2, useRef, useState as useState2 } from "react";
103
81
  import { createPortal } from "react-dom";
104
82
  import { invariant } from "@dxos/invariant";
105
- import { Icon as Icon2, ListItem as NaturalListItem } from "@dxos/react-ui";
106
- import { mx as mx3 } from "@dxos/react-ui-theme";
83
+ import { IconButton, ListItem as NaturalListItem, useTranslation } from "@dxos/react-ui";
84
+ import { mx as mx3, osTranslations } from "@dxos/ui-theme";
107
85
 
108
86
  // src/components/List/ListRoot.tsx
109
- import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
110
87
  import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
111
88
  import { extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
112
89
  import { getReorderDestinationIndex } from "@atlaskit/pragmatic-drag-and-drop-hitbox/util/get-reorder-destination-index";
@@ -116,68 +93,63 @@ var LIST_NAME = "List";
116
93
  var [ListProvider, useListContext] = createContext3(LIST_NAME);
117
94
  var defaultGetId2 = (item) => item?.id;
118
95
  var ListRoot = ({ children, items, isItem, getId = defaultGetId2, onMove, ...props }) => {
119
- var _effect = _useSignals3();
120
- try {
121
- const isEqual = useCallback((a, b) => {
122
- const idA = getId?.(a);
123
- const idB = getId?.(b);
124
- if (idA !== void 0 && idB !== void 0) {
125
- return idA === idB;
126
- } else {
127
- return a === b;
128
- }
129
- }, [
130
- getId
131
- ]);
132
- const [state, setState] = useState(idle);
133
- useEffect(() => {
134
- if (!items) {
135
- return;
136
- }
137
- return monitorForElements({
138
- canMonitor: ({ source }) => isItem?.(source.data) ?? false,
139
- onDrop: ({ location, source }) => {
140
- const target = location.current.dropTargets[0];
141
- if (!target) {
142
- return;
143
- }
144
- const sourceData = source.data;
145
- const targetData = target.data;
146
- if (!isItem?.(sourceData) || !isItem?.(targetData)) {
147
- return;
148
- }
149
- const sourceIdx = items.findIndex((item) => isEqual(item, sourceData));
150
- const targetIdx = items.findIndex((item) => isEqual(item, targetData));
151
- if (targetIdx < 0 || sourceIdx < 0) {
152
- return;
153
- }
154
- const closestEdgeOfTarget = extractClosestEdge(targetData);
155
- const destinationIndex = getReorderDestinationIndex({
156
- closestEdgeOfTarget,
157
- startIndex: sourceIdx,
158
- indexOfTarget: targetIdx,
159
- axis: "vertical"
160
- });
161
- onMove?.(sourceIdx, destinationIndex);
96
+ const isEqual = useCallback((a, b) => {
97
+ const idA = getId?.(a);
98
+ const idB = getId?.(b);
99
+ if (idA !== void 0 && idB !== void 0) {
100
+ return idA === idB;
101
+ } else {
102
+ return a === b;
103
+ }
104
+ }, [
105
+ getId
106
+ ]);
107
+ const [state, setState] = useState(idle);
108
+ useEffect(() => {
109
+ if (!items) {
110
+ return;
111
+ }
112
+ return monitorForElements({
113
+ canMonitor: ({ source }) => isItem?.(source.data) ?? false,
114
+ onDrop: ({ location, source }) => {
115
+ const target = location.current.dropTargets[0];
116
+ if (!target) {
117
+ return;
162
118
  }
163
- });
164
- }, [
165
- items,
166
- isEqual,
167
- onMove
168
- ]);
169
- return /* @__PURE__ */ React3.createElement(ListProvider, {
170
- state,
171
- setState,
172
- isItem,
173
- ...props
174
- }, children?.({
175
- state,
176
- items: items ?? []
177
- }));
178
- } finally {
179
- _effect.f();
180
- }
119
+ const sourceData = source.data;
120
+ const targetData = target.data;
121
+ if (!isItem?.(sourceData) || !isItem?.(targetData)) {
122
+ return;
123
+ }
124
+ const sourceIdx = items.findIndex((item) => isEqual(item, sourceData));
125
+ const targetIdx = items.findIndex((item) => isEqual(item, targetData));
126
+ if (targetIdx < 0 || sourceIdx < 0) {
127
+ return;
128
+ }
129
+ const closestEdgeOfTarget = extractClosestEdge(targetData);
130
+ const destinationIndex = getReorderDestinationIndex({
131
+ closestEdgeOfTarget,
132
+ startIndex: sourceIdx,
133
+ indexOfTarget: targetIdx,
134
+ axis: "vertical"
135
+ });
136
+ onMove?.(sourceIdx, destinationIndex);
137
+ }
138
+ });
139
+ }, [
140
+ items,
141
+ isEqual,
142
+ onMove
143
+ ]);
144
+ return /* @__PURE__ */ React3.createElement(ListProvider, {
145
+ state,
146
+ setState,
147
+ isItem,
148
+ ...props
149
+ }, children?.({
150
+ state,
151
+ items: items ?? []
152
+ }));
181
153
  };
182
154
 
183
155
  // src/components/List/ListItem.tsx
@@ -186,209 +158,182 @@ var idle = {
186
158
  type: "idle"
187
159
  };
188
160
  var stateStyles = {
189
- "is-dragging": "opacity-50"
161
+ "w-dragging": "opacity-50"
190
162
  };
191
163
  var defaultContext = {};
192
164
  var LIST_ITEM_NAME = "ListItem";
193
165
  var [ListItemProvider, useListItemContext] = createContext4(LIST_ITEM_NAME, defaultContext);
194
- var ListItem = ({ children, classNames, item, ...props }) => {
195
- var _effect = _useSignals4();
196
- try {
197
- const { isItem, readonly, dragPreview, setState: setRootState } = useListContext(LIST_ITEM_NAME);
198
- const ref = useRef(null);
199
- const dragHandleRef = useRef(null);
200
- const [state, setState] = useState2(idle);
201
- useEffect2(() => {
202
- const element = ref.current;
203
- invariant(element, void 0, {
204
- F: __dxlog_file,
205
- L: 93,
206
- S: void 0,
207
- A: [
208
- "element",
209
- ""
210
- ]
211
- });
212
- return combine(
213
- //
214
- // https://atlassian.design/components/pragmatic-drag-and-drop/core-package/adapters/element/about#draggable
215
- //
216
- draggable({
217
- element,
218
- dragHandle: dragHandleRef.current,
219
- canDrag: () => !readonly,
220
- getInitialData: () => item,
221
- onGenerateDragPreview: dragPreview ? ({ nativeSetDragImage, source }) => {
222
- const rect = source.element.getBoundingClientRect();
223
- setCustomNativeDragPreview({
224
- nativeSetDragImage,
225
- getOffset: ({ container }) => {
226
- const { height } = container.getBoundingClientRect();
227
- return {
228
- x: 20,
229
- y: height / 2
230
- };
231
- },
232
- render: ({ container }) => {
233
- container.style.width = rect.width + "px";
234
- setState({
235
- type: "preview",
236
- container
237
- });
238
- setRootState({
239
- type: "preview",
240
- container,
241
- item
242
- });
243
- return () => {
244
- };
245
- }
246
- });
247
- } : void 0,
248
- onDragStart: () => {
249
- setState({
250
- type: "is-dragging"
251
- });
252
- setRootState({
253
- type: "is-dragging",
254
- item
255
- });
256
- },
257
- onDrop: () => {
258
- setState(idle);
259
- setRootState(idle);
260
- }
261
- }),
262
- //
263
- // https://atlassian.design/components/pragmatic-drag-and-drop/core-package/adapters/element/about#drop-target-for-elements
264
- //
265
- dropTargetForElements({
266
- element,
267
- canDrop: ({ source }) => {
268
- return (source.element !== element && isItem?.(source.data)) ?? false;
269
- },
270
- getData: ({ input }) => {
271
- return attachClosestEdge(item, {
272
- element,
273
- input,
274
- allowedEdges: [
275
- "top",
276
- "bottom"
277
- ]
278
- });
279
- },
280
- getIsSticky: () => true,
281
- onDragEnter: ({ self }) => {
282
- const closestEdge = extractClosestEdge2(self.data);
283
- setState({
284
- type: "is-dragging-over",
285
- closestEdge
286
- });
287
- },
288
- onDragLeave: () => {
289
- setState(idle);
290
- },
291
- onDrag: ({ self }) => {
292
- const closestEdge = extractClosestEdge2(self.data);
293
- setState((current) => {
294
- if (current.type === "is-dragging-over" && current.closestEdge === closestEdge) {
295
- return current;
296
- }
166
+ var ListItem = ({ children, classNames, item, asChild, selected, ...props }) => {
167
+ const Comp = asChild ? Slot : "div";
168
+ const { isItem, readonly, dragPreview, setState: setRootState } = useListContext(LIST_ITEM_NAME);
169
+ const ref = useRef(null);
170
+ const dragHandleRef = useRef(null);
171
+ const [state, setState] = useState2(idle);
172
+ useEffect2(() => {
173
+ const element = ref.current;
174
+ invariant(element, void 0, {
175
+ F: __dxlog_file,
176
+ L: 109,
177
+ S: void 0,
178
+ A: [
179
+ "element",
180
+ ""
181
+ ]
182
+ });
183
+ return combine(
184
+ //
185
+ // https://atlassian.design/components/pragmatic-drag-and-drop/core-package/adapters/element/about#draggable
186
+ //
187
+ draggable({
188
+ element,
189
+ dragHandle: dragHandleRef.current,
190
+ canDrag: () => !readonly,
191
+ getInitialData: () => item,
192
+ onGenerateDragPreview: dragPreview ? ({ nativeSetDragImage, source }) => {
193
+ const rect = source.element.getBoundingClientRect();
194
+ setCustomNativeDragPreview({
195
+ nativeSetDragImage,
196
+ getOffset: ({ container }) => {
197
+ const { height } = container.getBoundingClientRect();
297
198
  return {
298
- type: "is-dragging-over",
299
- closestEdge
199
+ x: 20,
200
+ y: height / 2
300
201
  };
301
- });
302
- },
303
- onDrop: () => {
304
- setState(idle);
305
- }
306
- })
307
- );
308
- }, [
309
- item
310
- ]);
311
- return /* @__PURE__ */ React4.createElement(ListItemProvider, {
312
- item,
313
- dragHandleRef
314
- }, /* @__PURE__ */ React4.createElement("div", {
315
- role: "none",
316
- className: "relative"
317
- }, /* @__PURE__ */ React4.createElement("div", {
318
- ref,
319
- role: "listitem",
320
- className: mx3("flex overflow-hidden", classNames, stateStyles[state.type]),
321
- ...props
322
- }, children), state.type === "is-dragging-over" && state.closestEdge && /* @__PURE__ */ React4.createElement(NaturalListItem.DropIndicator, {
323
- edge: state.closestEdge
324
- })));
325
- } finally {
326
- _effect.f();
327
- }
202
+ },
203
+ render: ({ container }) => {
204
+ container.style.width = rect.width + "px";
205
+ setState({
206
+ type: "preview",
207
+ container
208
+ });
209
+ setRootState({
210
+ type: "preview",
211
+ container,
212
+ item
213
+ });
214
+ return () => {
215
+ };
216
+ }
217
+ });
218
+ } : void 0,
219
+ onDragStart: () => {
220
+ setState({
221
+ type: "w-dragging"
222
+ });
223
+ setRootState({
224
+ type: "w-dragging",
225
+ item
226
+ });
227
+ },
228
+ onDrop: () => {
229
+ setState(idle);
230
+ setRootState(idle);
231
+ }
232
+ }),
233
+ //
234
+ // https://atlassian.design/components/pragmatic-drag-and-drop/core-package/adapters/element/about#drop-target-for-elements
235
+ //
236
+ dropTargetForElements({
237
+ element,
238
+ canDrop: ({ source }) => {
239
+ return (source.element !== element && isItem?.(source.data)) ?? false;
240
+ },
241
+ getData: ({ input }) => {
242
+ return attachClosestEdge(item, {
243
+ element,
244
+ input,
245
+ allowedEdges: [
246
+ "top",
247
+ "bottom"
248
+ ]
249
+ });
250
+ },
251
+ getIsSticky: () => true,
252
+ onDragEnter: ({ self }) => {
253
+ const closestEdge = extractClosestEdge2(self.data);
254
+ setState({
255
+ type: "w-dragging-over",
256
+ closestEdge
257
+ });
258
+ },
259
+ onDragLeave: () => {
260
+ setState(idle);
261
+ },
262
+ onDrag: ({ self }) => {
263
+ const closestEdge = extractClosestEdge2(self.data);
264
+ setState((current) => {
265
+ if (current.type === "w-dragging-over" && current.closestEdge === closestEdge) {
266
+ return current;
267
+ }
268
+ return {
269
+ type: "w-dragging-over",
270
+ closestEdge
271
+ };
272
+ });
273
+ },
274
+ onDrop: () => {
275
+ setState(idle);
276
+ }
277
+ })
278
+ );
279
+ }, [
280
+ item
281
+ ]);
282
+ return /* @__PURE__ */ React4.createElement(ListItemProvider, {
283
+ item,
284
+ dragHandleRef
285
+ }, /* @__PURE__ */ React4.createElement(Comp, {
286
+ ref,
287
+ role: "listitem",
288
+ "aria-selected": selected,
289
+ className: mx3("relative dx-selected", classNames, stateStyles[state.type]),
290
+ ...props
291
+ }, children), state.type === "w-dragging-over" && state.closestEdge && /* @__PURE__ */ React4.createElement(NaturalListItem.DropIndicator, {
292
+ edge: state.closestEdge
293
+ }));
328
294
  };
329
- var IconButton = /* @__PURE__ */ forwardRef(({ classNames, icon, ...props }, forwardedRef) => {
330
- var _effect = _useSignals4();
331
- try {
332
- return /* @__PURE__ */ React4.createElement("button", {
333
- ref: forwardedRef,
334
- className: mx3("flex items-center justify-center", classNames),
335
- ...props
336
- }, /* @__PURE__ */ React4.createElement(Icon2, {
337
- icon,
338
- classNames: "cursor-pointer",
339
- size: 4
340
- }));
341
- } finally {
342
- _effect.f();
343
- }
344
- });
345
- var ListItemDeleteButton = ({ autoHide = true, classNames, disabled, icon = "ph--x--regular", ...props }) => {
346
- var _effect = _useSignals4();
347
- try {
348
- const { state } = useListContext("DELETE_BUTTON");
349
- const isDisabled = state.type !== "idle" || disabled;
350
- return /* @__PURE__ */ React4.createElement(IconButton, {
351
- icon,
352
- disabled: isDisabled,
353
- classNames: [
354
- classNames,
355
- autoHide && disabled && "hidden"
356
- ],
357
- ...props
358
- });
359
- } finally {
360
- _effect.f();
361
- }
295
+ var ListItemIconButton = ({ autoHide = true, iconOnly = true, variant = "ghost", classNames, disabled, ...props }) => {
296
+ const { state } = useListContext("ITEM_BUTTON");
297
+ const isDisabled = state.type !== "idle" || disabled;
298
+ return /* @__PURE__ */ React4.createElement(IconButton, {
299
+ ...props,
300
+ disabled: isDisabled,
301
+ iconOnly,
302
+ variant,
303
+ classNames: [
304
+ classNames,
305
+ autoHide && disabled && "hidden"
306
+ ]
307
+ });
362
308
  };
363
- var ListItemButton = ({ autoHide = true, classNames, disabled, ...props }) => {
364
- var _effect = _useSignals4();
365
- try {
366
- const { state } = useListContext("ITEM_BUTTON");
367
- const isDisabled = state.type !== "idle" || disabled;
368
- return /* @__PURE__ */ React4.createElement(IconButton, {
369
- disabled: isDisabled,
370
- classNames: [
371
- classNames,
372
- autoHide && disabled && "hidden"
373
- ],
374
- ...props
375
- });
376
- } finally {
377
- _effect.f();
378
- }
309
+ var ListItemDeleteButton = ({ autoHide = true, classNames, disabled, icon = "ph--x--regular", label, ...props }) => {
310
+ const { state } = useListContext("DELETE_BUTTON");
311
+ const isDisabled = state.type !== "idle" || disabled;
312
+ const { t } = useTranslation(osTranslations);
313
+ return /* @__PURE__ */ React4.createElement(IconButton, {
314
+ iconOnly: true,
315
+ variant: "ghost",
316
+ ...props,
317
+ icon,
318
+ disabled: isDisabled,
319
+ label: label ?? t("delete label"),
320
+ classNames: [
321
+ classNames,
322
+ autoHide && disabled && "hidden"
323
+ ]
324
+ });
379
325
  };
380
326
  var ListItemDragHandle = ({ disabled }) => {
381
- var _effect = _useSignals4();
382
- try {
383
- const { dragHandleRef } = useListItemContext("DRAG_HANDLE");
384
- return /* @__PURE__ */ React4.createElement(IconButton, {
385
- ref: dragHandleRef,
386
- icon: "ph--dots-six-vertical--regular",
387
- disabled
388
- });
389
- } finally {
390
- _effect.f();
391
- }
327
+ const { dragHandleRef } = useListItemContext("DRAG_HANDLE");
328
+ const { t } = useTranslation(osTranslations);
329
+ return /* @__PURE__ */ React4.createElement(IconButton, {
330
+ iconOnly: true,
331
+ variant: "ghost",
332
+ label: t("drag handle label"),
333
+ ref: dragHandleRef,
334
+ icon: "ph--dots-six-vertical--regular",
335
+ disabled
336
+ });
392
337
  };
393
338
  var ListItemDragPreview = ({ children }) => {
394
339
  const { state } = useListContext("DRAG_PREVIEW");
@@ -396,27 +341,13 @@ var ListItemDragPreview = ({ children }) => {
396
341
  item: state.item
397
342
  }), state.container) : null;
398
343
  };
399
- var ListItemWrapper = ({ classNames, children }) => {
400
- var _effect = _useSignals4();
401
- try {
402
- return /* @__PURE__ */ React4.createElement("div", {
403
- className: mx3("flex is-full gap-2", classNames)
404
- }, children);
405
- } finally {
406
- _effect.f();
407
- }
408
- };
409
- var ListItemTitle = ({ classNames, children, ...props }) => {
410
- var _effect = _useSignals4();
411
- try {
412
- return /* @__PURE__ */ React4.createElement("div", {
413
- className: mx3("flex grow items-center truncate", classNames),
414
- ...props
415
- }, children);
416
- } finally {
417
- _effect.f();
418
- }
419
- };
344
+ var ListItemWrapper = ({ classNames, children }) => /* @__PURE__ */ React4.createElement("div", {
345
+ className: mx3("flex w-full gap-2", classNames)
346
+ }, children);
347
+ var ListItemTitle = ({ classNames, children, ...props }) => /* @__PURE__ */ React4.createElement("div", {
348
+ className: mx3("flex grow items-center truncate", classNames),
349
+ ...props
350
+ }, children);
420
351
 
421
352
  // src/components/List/List.tsx
422
353
  var List = {
@@ -425,14 +356,13 @@ var List = {
425
356
  ItemDragPreview: ListItemDragPreview,
426
357
  ItemWrapper: ListItemWrapper,
427
358
  ItemDragHandle: ListItemDragHandle,
359
+ ItemIconButton: ListItemIconButton,
428
360
  ItemDeleteButton: ListItemDeleteButton,
429
- ItemButton: ListItemButton,
430
- ItemTitle: ListItemTitle,
431
- IconButton
361
+ ItemTitle: ListItemTitle
432
362
  };
433
363
 
434
364
  // src/components/Tree/Tree.tsx
435
- import { useSignals as _useSignals8 } from "@preact-signals/safe-react/tracking";
365
+ import { useAtomValue as useAtomValue2 } from "@effect-atom/atom-react";
436
366
  import React8, { useMemo as useMemo2 } from "react";
437
367
  import { Treegrid as Treegrid2 } from "@dxos/react-ui";
438
368
 
@@ -444,111 +374,106 @@ var TreeProvider = TreeContext.Provider;
444
374
  var useTree = () => useContext(TreeContext) ?? raise(new Error("TreeContext not found"));
445
375
 
446
376
  // src/components/Tree/TreeItem.tsx
447
- import { useSignals as _useSignals7 } from "@preact-signals/safe-react/tracking";
448
377
  import { combine as combine2 } from "@atlaskit/pragmatic-drag-and-drop/combine";
449
378
  import { draggable as draggable2, dropTargetForElements as dropTargetForElements2 } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
450
379
  import { attachInstruction, extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
451
- import { Schema } from "effect";
380
+ import { useAtomValue } from "@effect-atom/atom-react";
381
+ import * as Schema from "effect/Schema";
452
382
  import React7, { memo as memo3, useCallback as useCallback3, useEffect as useEffect3, useMemo, useRef as useRef2, useState as useState3 } from "react";
453
383
  import { invariant as invariant2 } from "@dxos/invariant";
454
- import { Treegrid, TreeItem as NaturalTreeItem } from "@dxos/react-ui";
455
- import { ghostHover, hoverableControls, hoverableFocusedKeyboardControls, hoverableFocusedWithinControls } from "@dxos/react-ui-theme";
384
+ import { TreeItem as NaturalTreeItem, Treegrid } from "@dxos/react-ui";
385
+ import { ghostFocusWithin, ghostHover, hoverableControls, hoverableFocusedKeyboardControls, hoverableFocusedWithinControls, mx as mx4 } from "@dxos/ui-theme";
386
+
387
+ // src/components/Tree/helpers.ts
388
+ var DEFAULT_INDENTATION = 8;
389
+ var paddingIndentation = (level, indentation = DEFAULT_INDENTATION) => ({
390
+ paddingInlineStart: `${(level - 1) * indentation}px`
391
+ });
456
392
 
457
393
  // src/components/Tree/TreeItemHeading.tsx
458
- import { useSignals as _useSignals5 } from "@preact-signals/safe-react/tracking";
459
- import React5, { forwardRef as forwardRef2, memo, useCallback as useCallback2 } from "react";
460
- import { Button, Icon as Icon3, toLocalizedString, useTranslation } from "@dxos/react-ui";
394
+ import React5, { forwardRef, memo, useCallback as useCallback2 } from "react";
395
+ import { Button, Icon as Icon2, toLocalizedString, useTranslation as useTranslation2 } from "@dxos/react-ui";
461
396
  import { TextTooltip } from "@dxos/react-ui-text-tooltip";
462
- var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef2(({ label, icon, className, disabled, current, onSelect }, forwardedRef) => {
463
- var _effect = _useSignals5();
464
- try {
465
- const { t } = useTranslation();
466
- const handleSelect = useCallback2((event) => {
397
+ import { getStyles } from "@dxos/ui-theme";
398
+ var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef(({ label, className, icon, iconHue, disabled, current, onSelect }, forwardedRef) => {
399
+ const { t } = useTranslation2();
400
+ const styles = iconHue ? getStyles(iconHue) : void 0;
401
+ const handleSelect = useCallback2((event) => {
402
+ onSelect?.(event.altKey);
403
+ }, [
404
+ onSelect
405
+ ]);
406
+ const handleButtonKeydown = useCallback2((event) => {
407
+ if (event.key === " " || event.key === "Enter") {
408
+ event.preventDefault();
409
+ event.stopPropagation();
467
410
  onSelect?.(event.altKey);
468
- }, [
469
- onSelect
470
- ]);
471
- const handleButtonKeydown = useCallback2((event) => {
472
- if (event.key === " " || event.key === "Enter") {
473
- event.preventDefault();
474
- event.stopPropagation();
475
- onSelect?.(event.altKey);
476
- }
477
- }, [
478
- onSelect
479
- ]);
480
- return /* @__PURE__ */ React5.createElement(TextTooltip, {
481
- text: toLocalizedString(label, t),
482
- side: "bottom",
483
- truncateQuery: "span[data-tooltip]",
484
- onlyWhenTruncating: true,
485
- asChild: true,
486
- ref: forwardedRef
487
- }, /* @__PURE__ */ React5.createElement(Button, {
488
- "data-testid": "treeItem.heading",
489
- variant: "ghost",
490
- density: "fine",
491
- classNames: [
492
- "grow gap-2 pis-0.5 hover:bg-transparent dark:hover:bg-transparent",
493
- "disabled:cursor-default disabled:opacity-100",
494
- className
495
- ],
496
- disabled,
497
- onClick: handleSelect,
498
- onKeyDown: handleButtonKeydown,
499
- ...current && {
500
- "aria-current": "location"
501
- }
502
- }, icon && /* @__PURE__ */ React5.createElement(Icon3, {
503
- icon: icon ?? "ph--placeholder--regular",
504
- size: 5,
505
- classNames: "mlb-1"
506
- }), /* @__PURE__ */ React5.createElement("span", {
507
- className: "flex-1 is-0 truncate text-start text-sm font-normal",
508
- "data-tooltip": true
509
- }, toLocalizedString(label, t))));
510
- } finally {
511
- _effect.f();
512
- }
411
+ }
412
+ }, [
413
+ onSelect
414
+ ]);
415
+ return /* @__PURE__ */ React5.createElement(TextTooltip, {
416
+ text: toLocalizedString(label, t),
417
+ side: "bottom",
418
+ truncateQuery: "span[data-tooltip]",
419
+ onlyWhenTruncating: true,
420
+ asChild: true,
421
+ ref: forwardedRef
422
+ }, /* @__PURE__ */ React5.createElement(Button, {
423
+ "data-testid": "treeItem.heading",
424
+ variant: "ghost",
425
+ density: "fine",
426
+ classNames: [
427
+ "grow gap-2 ps-0.5 hover:bg-transparent dark:hover:bg-transparent",
428
+ "disabled:cursor-default disabled:opacity-100",
429
+ className
430
+ ],
431
+ disabled,
432
+ onClick: handleSelect,
433
+ onKeyDown: handleButtonKeydown,
434
+ ...current && {
435
+ "aria-current": "location"
436
+ }
437
+ }, icon && /* @__PURE__ */ React5.createElement(Icon2, {
438
+ icon: icon ?? "ph--placeholder--regular",
439
+ size: 5,
440
+ classNames: [
441
+ "my-1",
442
+ styles?.surfaceText
443
+ ]
444
+ }), /* @__PURE__ */ React5.createElement("span", {
445
+ className: "flex-1 w-0 truncate text-start font-normal",
446
+ "data-tooltip": true
447
+ }, toLocalizedString(label, t))));
513
448
  }));
514
449
 
515
450
  // src/components/Tree/TreeItemToggle.tsx
516
- import { useSignals as _useSignals6 } from "@preact-signals/safe-react/tracking";
517
- import React6, { forwardRef as forwardRef3, memo as memo2 } from "react";
518
- import { Button as Button2, Icon as Icon4 } from "@dxos/react-ui";
519
- var TreeItemToggle = /* @__PURE__ */ memo2(/* @__PURE__ */ forwardRef3(({ open, isBranch, hidden, onToggle }, forwardedRef) => {
520
- var _effect = _useSignals6();
521
- try {
522
- return /* @__PURE__ */ React6.createElement(Button2, {
523
- ref: forwardedRef,
524
- "data-testid": "treeItem.toggle",
525
- "aria-expanded": open,
526
- variant: "ghost",
527
- density: "fine",
528
- classNames: [
529
- "is-6 pli-0 dx-focus-ring-inset",
530
- hidden ? "hidden" : !isBranch && "invisible"
531
- ],
532
- onClick: onToggle
533
- }, /* @__PURE__ */ React6.createElement(Icon4, {
534
- icon: "ph--caret-right--bold",
535
- size: 3,
536
- classNames: [
537
- "transition duration-200",
538
- open && "rotate-90"
539
- ]
540
- }));
541
- } finally {
542
- _effect.f();
543
- }
451
+ import React6, { forwardRef as forwardRef2, memo as memo2 } from "react";
452
+ import { IconButton as IconButton2 } from "@dxos/react-ui";
453
+ var TreeItemToggle = /* @__PURE__ */ memo2(/* @__PURE__ */ forwardRef2(({ open, isBranch, hidden, classNames, ...props }, forwardedRef) => {
454
+ return /* @__PURE__ */ React6.createElement(IconButton2, {
455
+ ref: forwardedRef,
456
+ "data-testid": "treeItem.toggle",
457
+ "aria-expanded": open,
458
+ variant: "ghost",
459
+ density: "fine",
460
+ classNames: [
461
+ "h-full w-6 px-0",
462
+ "[&_svg]:transition-[transform] [&_svg]:duration-200",
463
+ open && "[&_svg]:rotate-90",
464
+ hidden ? "hidden" : !isBranch && "invisible",
465
+ classNames
466
+ ],
467
+ size: 3,
468
+ icon: "ph--caret-right--bold",
469
+ iconOnly: true,
470
+ noTooltip: true,
471
+ label: open ? "Click to close" : "Click to open",
472
+ tabIndex: -1,
473
+ ...props
474
+ });
544
475
  }));
545
476
 
546
- // src/components/Tree/helpers.ts
547
- var DEFAULT_INDENTATION = 8;
548
- var paddingIndentation = (level, indentation = DEFAULT_INDENTATION) => ({
549
- paddingInlineStart: `${(level - 1) * indentation}px`
550
- });
551
-
552
477
  // src/components/Tree/TreeItem.tsx
553
478
  var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-list/src/components/Tree/TreeItem.tsx";
554
479
  var hoverableDescriptionIcons = "[--icons-color:inherit] hover-hover:[--icons-color:var(--description-text)] hover-hover:hover:[--icons-color:inherit] focus-within:[--icons-color:inherit]";
@@ -558,312 +483,341 @@ var TreeDataSchema = Schema.Struct({
558
483
  item: Schema.Any
559
484
  });
560
485
  var isTreeData = (data) => Schema.is(TreeDataSchema)(data);
561
- var RawTreeItem = ({ item, path: _path, last, draggable: _draggable, renderColumns: Columns, canDrop, onOpenChange, onSelect, levelOffset = 2 }) => {
562
- var _effect = _useSignals7();
563
- try {
564
- const rowRef = useRef2(null);
565
- const buttonRef = useRef2(null);
566
- const openRef = useRef2(false);
567
- const cancelExpandRef = useRef2(null);
568
- const [_state, setState] = useState3("idle");
569
- const [instruction, setInstruction] = useState3(null);
570
- const [menuOpen, setMenuOpen] = useState3(false);
571
- const { useItems, getProps, isOpen, isCurrent } = useTree();
572
- const items = useItems(item);
573
- const { id, label, parentOf, icon, disabled, className, headingClassName, testId } = getProps(item, _path);
574
- const path = useMemo(() => [
575
- ..._path,
576
- id
577
- ], [
578
- _path,
579
- id
580
- ]);
581
- const open = isOpen(path, item);
582
- const current = isCurrent(path, item);
583
- const level = path.length - levelOffset;
584
- const isBranch = !!parentOf;
585
- const mode = last ? "last-in-group" : open ? "expanded" : "standard";
586
- const cancelExpand = useCallback3(() => {
587
- if (cancelExpandRef.current) {
588
- clearTimeout(cancelExpandRef.current);
589
- cancelExpandRef.current = null;
590
- }
591
- }, []);
592
- useEffect3(() => {
593
- if (!_draggable) {
594
- return;
486
+ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: draggableProp, renderColumns: Columns, blockInstruction, canDrop, canSelect, onOpenChange, onSelect, onItemHover }) => {
487
+ const rowRef = useRef2(null);
488
+ const buttonRef = useRef2(null);
489
+ const openRef = useRef2(false);
490
+ const cancelExpandRef = useRef2(null);
491
+ const [_state, setState] = useState3("idle");
492
+ const [instruction, setInstruction] = useState3(null);
493
+ const [menuOpen, setMenuOpen] = useState3(false);
494
+ const { itemProps: itemPropsAtom, childIds: childIdsAtom, itemOpen: itemOpenAtom, itemCurrent: itemCurrentAtom } = useTree();
495
+ const path = useMemo(() => [
496
+ ...pathProp,
497
+ item.id
498
+ ], [
499
+ pathProp,
500
+ item.id
501
+ ]);
502
+ const { id, parentOf, draggable: itemDraggable, droppable: itemDroppable, label, className, headingClassName, icon, iconHue, disabled, testId } = useAtomValue(itemPropsAtom(path));
503
+ const childIds = useAtomValue(childIdsAtom(item.id));
504
+ const open = useAtomValue(itemOpenAtom(path));
505
+ const current = useAtomValue(itemCurrentAtom(path));
506
+ const level = path.length - levelOffset;
507
+ const isBranch = !!parentOf;
508
+ const mode = last ? "last-in-group" : open ? "expanded" : "standard";
509
+ const canSelectItem = canSelect?.({
510
+ item,
511
+ path
512
+ }) ?? true;
513
+ const data = {
514
+ id,
515
+ path,
516
+ item
517
+ };
518
+ const cancelExpand = useCallback3(() => {
519
+ if (cancelExpandRef.current) {
520
+ clearTimeout(cancelExpandRef.current);
521
+ cancelExpandRef.current = null;
522
+ }
523
+ }, []);
524
+ const isItemDraggable = draggableProp && itemDraggable !== false;
525
+ const isItemDroppable = itemDroppable !== false;
526
+ useEffect3(() => {
527
+ if (!draggableProp) {
528
+ return;
529
+ }
530
+ invariant2(buttonRef.current, void 0, {
531
+ F: __dxlog_file2,
532
+ L: 148,
533
+ S: void 0,
534
+ A: [
535
+ "buttonRef.current",
536
+ ""
537
+ ]
538
+ });
539
+ const makeDraggable = () => draggable2({
540
+ element: buttonRef.current,
541
+ getInitialData: () => data,
542
+ onDragStart: () => {
543
+ setState("dragging");
544
+ if (open) {
545
+ openRef.current = true;
546
+ onOpenChange?.({
547
+ item,
548
+ path,
549
+ open: false
550
+ });
551
+ }
552
+ },
553
+ onDrop: () => {
554
+ setState("idle");
555
+ if (openRef.current) {
556
+ onOpenChange?.({
557
+ item,
558
+ path,
559
+ open: true
560
+ });
561
+ }
595
562
  }
596
- invariant2(buttonRef.current, void 0, {
597
- F: __dxlog_file2,
598
- L: 105,
599
- S: void 0,
600
- A: [
601
- "buttonRef.current",
602
- ""
603
- ]
604
- });
605
- const data = {
606
- id,
607
- path,
608
- item
609
- };
610
- return combine2(
611
- draggable2({
612
- element: buttonRef.current,
613
- getInitialData: () => data,
614
- onDragStart: () => {
615
- setState("dragging");
616
- if (open) {
617
- openRef.current = true;
618
- onOpenChange?.({
619
- item,
620
- path,
621
- open: false
622
- });
623
- }
624
- },
625
- onDrop: () => {
626
- setState("idle");
627
- if (openRef.current) {
563
+ });
564
+ if (!isItemDroppable) {
565
+ return isItemDraggable ? makeDraggable() : void 0;
566
+ }
567
+ const dropTarget = dropTargetForElements2({
568
+ element: buttonRef.current,
569
+ getData: ({ input, element }) => {
570
+ return attachInstruction(data, {
571
+ input,
572
+ element,
573
+ indentPerLevel: DEFAULT_INDENTATION,
574
+ currentLevel: level,
575
+ mode,
576
+ block: isBranch ? [] : [
577
+ "make-child"
578
+ ]
579
+ });
580
+ },
581
+ canDrop: ({ source }) => {
582
+ const _canDrop = canDrop ?? (() => true);
583
+ return source.element !== buttonRef.current && _canDrop({
584
+ source: source.data,
585
+ target: data
586
+ });
587
+ },
588
+ getIsSticky: () => true,
589
+ onDrag: ({ self, source }) => {
590
+ const desired = extractInstruction(self.data);
591
+ const block = desired && blockInstruction?.({
592
+ instruction: desired,
593
+ source: source.data,
594
+ target: data
595
+ });
596
+ const instruction2 = block && desired.type !== "instruction-blocked" ? {
597
+ type: "instruction-blocked",
598
+ desired
599
+ } : desired;
600
+ if (source.data.id !== id) {
601
+ if (instruction2?.type === "make-child" && isBranch && !open && !cancelExpandRef.current) {
602
+ cancelExpandRef.current = setTimeout(() => {
628
603
  onOpenChange?.({
629
604
  item,
630
605
  path,
631
606
  open: true
632
607
  });
633
- }
608
+ }, 500);
634
609
  }
635
- }),
636
- // https://github.com/atlassian/pragmatic-drag-and-drop/blob/main/packages/hitbox/constellation/index/about.mdx
637
- dropTargetForElements2({
638
- element: buttonRef.current,
639
- getData: ({ input, element }) => {
640
- return attachInstruction(data, {
641
- input,
642
- element,
643
- indentPerLevel: DEFAULT_INDENTATION,
644
- currentLevel: level,
645
- mode,
646
- block: isBranch ? [] : [
647
- "make-child"
648
- ]
649
- });
650
- },
651
- canDrop: ({ source }) => {
652
- const _canDrop = canDrop ?? (() => true);
653
- return source.element !== buttonRef.current && _canDrop({
654
- source: source.data,
655
- target: data
656
- });
657
- },
658
- getIsSticky: () => true,
659
- onDrag: ({ self, source }) => {
660
- const instruction2 = extractInstruction(self.data);
661
- if (source.data.id !== id) {
662
- if (instruction2?.type === "make-child" && isBranch && !open && !cancelExpandRef.current) {
663
- cancelExpandRef.current = setTimeout(() => {
664
- onOpenChange?.({
665
- item,
666
- path,
667
- open: true
668
- });
669
- }, 500);
670
- }
671
- if (instruction2?.type !== "make-child") {
672
- cancelExpand();
673
- }
674
- setInstruction(instruction2);
675
- } else if (instruction2?.type === "reparent") {
676
- setInstruction(instruction2);
677
- } else {
678
- setInstruction(null);
679
- }
680
- },
681
- onDragLeave: () => {
610
+ if (instruction2?.type !== "make-child") {
682
611
  cancelExpand();
683
- setInstruction(null);
684
- },
685
- onDrop: () => {
686
- cancelExpand();
687
- setInstruction(null);
688
612
  }
689
- })
690
- );
691
- }, [
692
- _draggable,
693
- item,
694
- id,
695
- mode,
696
- path,
697
- open,
698
- canDrop
699
- ]);
700
- useEffect3(() => () => cancelExpand(), [
701
- cancelExpand
702
- ]);
703
- const handleOpenChange = useCallback3(() => onOpenChange?.({
704
- item,
705
- path,
706
- open: !open
707
- }), [
708
- onOpenChange,
709
- item,
710
- path,
711
- open
712
- ]);
713
- const handleSelect = useCallback3((option = false) => {
714
- if (isBranch) {
715
- handleOpenChange();
716
- } else {
717
- rowRef.current?.focus();
718
- onSelect?.({
719
- item,
720
- path,
721
- current: !current,
722
- option
723
- });
724
- }
725
- }, [
726
- item,
727
- path,
728
- current,
729
- isBranch,
730
- handleOpenChange,
731
- onSelect
732
- ]);
733
- const handleKeyDown = useCallback3((event) => {
734
- switch (event.key) {
735
- case "ArrowRight":
736
- isBranch && !open && handleOpenChange();
737
- break;
738
- case "ArrowLeft":
739
- isBranch && open && handleOpenChange();
740
- break;
741
- case " ":
742
- handleSelect(event.altKey);
743
- break;
744
- }
745
- }, [
746
- isBranch,
747
- open,
748
- handleOpenChange,
749
- handleSelect
750
- ]);
751
- return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(Treegrid.Row, {
752
- ref: rowRef,
753
- key: id,
754
- id,
755
- "aria-labelledby": `${id}__label`,
756
- parentOf: parentOf?.join(Treegrid.PARENT_OF_SEPARATOR),
757
- classNames: [
758
- "grid grid-cols-subgrid col-[tree-row] mbs-0.5 aria-[current]:bg-activeSurface",
759
- hoverableControls,
760
- hoverableFocusedKeyboardControls,
761
- hoverableFocusedWithinControls,
762
- hoverableDescriptionIcons,
763
- ghostHover,
764
- className
765
- ],
766
- "data-itemid": id,
767
- "data-testid": testId,
768
- // NOTE(thure): This is intentionally an empty string to for descendents to select by in the CSS
769
- // without alerting the user (except for in the correct link element). See also:
770
- // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current#description
771
- "aria-current": current ? "" : void 0,
772
- onKeyDown: handleKeyDown,
773
- onContextMenu: (event) => {
774
- event.preventDefault();
775
- setMenuOpen(true);
613
+ setInstruction(instruction2);
614
+ } else if (instruction2?.type === "reparent") {
615
+ setInstruction(instruction2);
616
+ } else {
617
+ setInstruction(null);
618
+ }
619
+ },
620
+ onDragLeave: () => {
621
+ cancelExpand();
622
+ setInstruction(null);
623
+ },
624
+ onDrop: () => {
625
+ cancelExpand();
626
+ setInstruction(null);
776
627
  }
777
- }, /* @__PURE__ */ React7.createElement(Treegrid.Cell, {
778
- indent: true,
779
- classNames: "relative grid grid-cols-subgrid col-[tree-row]",
780
- style: paddingIndentation(level)
781
- }, /* @__PURE__ */ React7.createElement("div", {
782
- role: "none",
783
- className: "flex items-center"
784
- }, /* @__PURE__ */ React7.createElement(TreeItemToggle, {
785
- isBranch,
786
- open,
787
- onToggle: handleOpenChange
788
- }), /* @__PURE__ */ React7.createElement(TreeItemHeading, {
789
- ref: buttonRef,
790
- label,
791
- icon,
792
- className: headingClassName,
793
- disabled,
794
- current,
795
- onSelect: handleSelect
796
- })), Columns && /* @__PURE__ */ React7.createElement(Columns, {
797
- item,
798
- path,
799
- open,
800
- menuOpen,
801
- setMenuOpen
802
- }), instruction && /* @__PURE__ */ React7.createElement(NaturalTreeItem.DropIndicator, {
803
- instruction,
804
- gap: 2
805
- }))), open && items.map((item2, index) => /* @__PURE__ */ React7.createElement(TreeItem, {
806
- key: item2.id,
807
- item: item2,
808
- path,
809
- last: index === items.length - 1,
810
- draggable: _draggable,
811
- renderColumns: Columns,
812
- canDrop,
813
- onOpenChange,
814
- onSelect
815
- })));
816
- } finally {
817
- _effect.f();
818
- }
628
+ });
629
+ if (!isItemDraggable) {
630
+ return dropTarget;
631
+ }
632
+ return combine2(makeDraggable(), dropTarget);
633
+ }, [
634
+ draggableProp,
635
+ isItemDraggable,
636
+ isItemDroppable,
637
+ item,
638
+ id,
639
+ mode,
640
+ path,
641
+ open,
642
+ blockInstruction,
643
+ canDrop
644
+ ]);
645
+ useEffect3(() => () => cancelExpand(), [
646
+ cancelExpand
647
+ ]);
648
+ const handleOpenToggle = useCallback3(() => onOpenChange?.({
649
+ item,
650
+ path,
651
+ open: !open
652
+ }), [
653
+ onOpenChange,
654
+ item,
655
+ path,
656
+ open
657
+ ]);
658
+ const handleSelect = useCallback3((option = false) => {
659
+ if (isBranch && (option || current)) {
660
+ handleOpenToggle();
661
+ } else if (canSelectItem) {
662
+ canSelect?.({
663
+ item,
664
+ path
665
+ });
666
+ rowRef.current?.focus();
667
+ onSelect?.({
668
+ item,
669
+ path,
670
+ current: !current,
671
+ option
672
+ });
673
+ }
674
+ }, [
675
+ item,
676
+ path,
677
+ current,
678
+ isBranch,
679
+ canSelectItem,
680
+ handleOpenToggle,
681
+ onSelect
682
+ ]);
683
+ const handleKeyDown = useCallback3((event) => {
684
+ switch (event.key) {
685
+ case "ArrowRight":
686
+ case "ArrowLeft":
687
+ isBranch && handleOpenToggle();
688
+ break;
689
+ }
690
+ }, [
691
+ isBranch,
692
+ open,
693
+ handleOpenToggle,
694
+ handleSelect
695
+ ]);
696
+ const handleItemHover = useCallback3(() => {
697
+ onItemHover?.({
698
+ item
699
+ });
700
+ }, [
701
+ onItemHover,
702
+ item
703
+ ]);
704
+ const handleContextMenu = useCallback3((event) => {
705
+ event.preventDefault();
706
+ setMenuOpen(true);
707
+ }, [
708
+ setMenuOpen
709
+ ]);
710
+ const childProps = {
711
+ draggable: draggableProp,
712
+ renderColumns: Columns,
713
+ blockInstruction,
714
+ canDrop,
715
+ canSelect,
716
+ onItemHover,
717
+ onOpenChange,
718
+ onSelect
719
+ };
720
+ return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(Treegrid.Row, {
721
+ ref: rowRef,
722
+ key: id,
723
+ id,
724
+ "aria-labelledby": `${id}__label`,
725
+ parentOf: parentOf?.join(Treegrid.PARENT_OF_SEPARATOR),
726
+ "data-object-id": id,
727
+ "data-testid": testId,
728
+ // NOTE(thure): This is intentionally an empty string to for descendents to select by in the CSS
729
+ // without alerting the user (except for in the correct link element). See also:
730
+ // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current#description
731
+ "aria-current": current ? "" : void 0,
732
+ classNames: mx4("grid grid-cols-subgrid col-[tree-row] mt-0.5 is-current:bg-active-surface", hoverableControls, hoverableFocusedKeyboardControls, hoverableFocusedWithinControls, hoverableDescriptionIcons, ghostFocusWithin, ghostHover, className),
733
+ onKeyDown: handleKeyDown,
734
+ onMouseEnter: handleItemHover,
735
+ onContextMenu: handleContextMenu
736
+ }, /* @__PURE__ */ React7.createElement("div", {
737
+ role: "none",
738
+ className: "indent relative grid grid-cols-subgrid col-[tree-row]",
739
+ style: paddingIndentation(level)
740
+ }, /* @__PURE__ */ React7.createElement(Treegrid.Cell, {
741
+ classNames: "flex items-center"
742
+ }, /* @__PURE__ */ React7.createElement(TreeItemToggle, {
743
+ isBranch,
744
+ open,
745
+ onClick: handleOpenToggle
746
+ }), /* @__PURE__ */ React7.createElement(TreeItemHeading, {
747
+ disabled,
748
+ current,
749
+ label,
750
+ className: headingClassName,
751
+ icon,
752
+ iconHue,
753
+ onSelect: handleSelect,
754
+ ref: buttonRef
755
+ })), Columns && /* @__PURE__ */ React7.createElement(Columns, {
756
+ item,
757
+ path,
758
+ open,
759
+ menuOpen,
760
+ setMenuOpen
761
+ }), instruction && /* @__PURE__ */ React7.createElement(NaturalTreeItem.DropIndicator, {
762
+ instruction,
763
+ gap: 2
764
+ }))), open && childIds.map((childId, index) => /* @__PURE__ */ React7.createElement(TreeItemById, {
765
+ key: childId,
766
+ id: childId,
767
+ path,
768
+ last: index === childIds.length - 1,
769
+ ...childProps
770
+ })));
819
771
  };
820
772
  var TreeItem = /* @__PURE__ */ memo3(RawTreeItem);
773
+ var RawTreeItemById = ({ id, ...props }) => {
774
+ const { item: itemAtom } = useTree();
775
+ const item = useAtomValue(itemAtom(id));
776
+ if (!item) {
777
+ return null;
778
+ }
779
+ return /* @__PURE__ */ React7.createElement(TreeItem, {
780
+ item,
781
+ ...props
782
+ });
783
+ };
784
+ var TreeItemById = /* @__PURE__ */ memo3(RawTreeItemById);
821
785
 
822
786
  // src/components/Tree/Tree.tsx
823
- var Tree = ({ root, path, id, useItems, getProps, isOpen, isCurrent, draggable: draggable3 = false, gridTemplateColumns = "[tree-row-start] 1fr min-content [tree-row-end]", classNames, levelOffset, renderColumns, canDrop, onOpenChange, onSelect }) => {
824
- var _effect = _useSignals8();
825
- try {
826
- const context = useMemo2(() => ({
827
- useItems,
828
- getProps,
829
- isOpen,
830
- isCurrent
831
- }), [
832
- useItems,
833
- getProps,
834
- isOpen,
835
- isCurrent
836
- ]);
837
- const items = useItems(root);
838
- const treePath = useMemo2(() => path ? [
839
- ...path,
840
- id
841
- ] : [
842
- id
843
- ], [
844
- id,
845
- path
846
- ]);
847
- return /* @__PURE__ */ React8.createElement(Treegrid2.Root, {
848
- gridTemplateColumns,
849
- classNames
850
- }, /* @__PURE__ */ React8.createElement(TreeProvider, {
851
- value: context
852
- }, items.map((item, index) => /* @__PURE__ */ React8.createElement(TreeItem, {
853
- key: item.id,
854
- item,
855
- last: index === items.length - 1,
856
- path: treePath,
857
- levelOffset,
858
- draggable: draggable3,
859
- renderColumns,
860
- canDrop,
861
- onOpenChange,
862
- onSelect
863
- }))));
864
- } finally {
865
- _effect.f();
866
- }
787
+ var Tree = ({ model, rootId, path, id, draggable: draggable3 = false, gridTemplateColumns = "[tree-row-start] 1fr min-content [tree-row-end]", classNames, levelOffset, renderColumns, blockInstruction, canDrop, canSelect, onOpenChange, onSelect, onItemHover }) => {
788
+ const childIds = useAtomValue2(model.childIds(rootId));
789
+ const treePath = useMemo2(() => path ? [
790
+ ...path,
791
+ id
792
+ ] : [
793
+ id
794
+ ], [
795
+ id,
796
+ path
797
+ ]);
798
+ const childProps = {
799
+ path: treePath,
800
+ levelOffset,
801
+ draggable: draggable3,
802
+ renderColumns,
803
+ blockInstruction,
804
+ canDrop,
805
+ canSelect,
806
+ onOpenChange,
807
+ onSelect,
808
+ onItemHover
809
+ };
810
+ return /* @__PURE__ */ React8.createElement(Treegrid2.Root, {
811
+ gridTemplateColumns,
812
+ classNames
813
+ }, /* @__PURE__ */ React8.createElement(TreeProvider, {
814
+ value: model
815
+ }, childIds.map((childId, index) => /* @__PURE__ */ React8.createElement(TreeItemById, {
816
+ key: childId,
817
+ id: childId,
818
+ last: index === childIds.length - 1,
819
+ ...childProps
820
+ }))));
867
821
  };
868
822
 
869
823
  // src/util/path.ts
@@ -883,13 +837,17 @@ var Path = {
883
837
  };
884
838
  export {
885
839
  Accordion,
840
+ DEFAULT_INDENTATION,
886
841
  List,
887
842
  Path,
888
843
  Tree,
889
844
  TreeDataSchema,
890
845
  TreeItem,
846
+ TreeItemById,
847
+ TreeItemToggle,
891
848
  TreeProvider,
892
849
  isTreeData,
850
+ paddingIndentation,
893
851
  useTree
894
852
  };
895
853
  //# sourceMappingURL=index.mjs.map