@dxos/react-ui-list 0.8.4-main.7ace549 → 0.8.4-main.8360d9e660

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