@dxos/react-ui-list 0.8.4-main.dedc0f3 → 0.8.4-main.e00bdcdb52

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