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