@dxos/react-ui-list 0.8.4-main.f5c0578 → 0.8.4-main.fcc0d83b33

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