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