@dxos/react-ui-list 0.8.4-main.f9ba587 → 0.8.4-main.fcfe5033a5

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