@dxos/react-ui-list 0.6.14-main.2b6a0f3 → 0.6.14-main.69511f5

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 (52) hide show
  1. package/dist/lib/browser/index.mjs +410 -26
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/List/List.d.ts +1 -1
  5. package/dist/types/src/components/List/List.d.ts.map +1 -1
  6. package/dist/types/src/components/List/List.stories.d.ts +1 -1
  7. package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
  8. package/dist/types/src/components/List/ListItem.d.ts +1 -3
  9. package/dist/types/src/components/List/ListItem.d.ts.map +1 -1
  10. package/dist/types/src/components/List/ListRoot.d.ts +5 -4
  11. package/dist/types/src/components/List/ListRoot.d.ts.map +1 -1
  12. package/dist/types/src/components/List/testing.d.ts.map +1 -0
  13. package/dist/types/src/components/Tree/DropIndicator.d.ts +7 -0
  14. package/dist/types/src/components/Tree/DropIndicator.d.ts.map +1 -0
  15. package/dist/types/src/components/Tree/Tree.d.ts +24 -0
  16. package/dist/types/src/components/Tree/Tree.d.ts.map +1 -0
  17. package/dist/types/src/components/Tree/Tree.stories.d.ts +8 -0
  18. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -0
  19. package/dist/types/src/components/Tree/TreeItem.d.ts +34 -0
  20. package/dist/types/src/components/Tree/TreeItem.d.ts.map +1 -0
  21. package/dist/types/src/components/Tree/TreeItemHeading.d.ts +12 -0
  22. package/dist/types/src/components/Tree/TreeItemHeading.d.ts.map +1 -0
  23. package/dist/types/src/components/Tree/TreeItemToggle.d.ts +8 -0
  24. package/dist/types/src/components/Tree/TreeItemToggle.d.ts.map +1 -0
  25. package/dist/types/src/components/Tree/helpers.d.ts +8 -0
  26. package/dist/types/src/components/Tree/helpers.d.ts.map +1 -0
  27. package/dist/types/src/components/Tree/index.d.ts +4 -0
  28. package/dist/types/src/components/Tree/index.d.ts.map +1 -0
  29. package/dist/types/src/components/Tree/testing.d.ts +26 -0
  30. package/dist/types/src/components/Tree/testing.d.ts.map +1 -0
  31. package/dist/types/src/components/Tree/types.d.ts +18 -0
  32. package/dist/types/src/components/Tree/types.d.ts.map +1 -0
  33. package/dist/types/src/components/index.d.ts +1 -0
  34. package/dist/types/src/components/index.d.ts.map +1 -1
  35. package/package.json +19 -15
  36. package/src/components/List/List.stories.tsx +9 -5
  37. package/src/components/List/ListItem.tsx +9 -7
  38. package/src/components/List/ListRoot.tsx +47 -24
  39. package/src/components/Tree/DropIndicator.tsx +79 -0
  40. package/src/components/Tree/Tree.stories.tsx +116 -0
  41. package/src/components/Tree/Tree.tsx +56 -0
  42. package/src/components/Tree/TreeItem.tsx +237 -0
  43. package/src/components/Tree/TreeItemHeading.tsx +62 -0
  44. package/src/components/Tree/TreeItemToggle.tsx +35 -0
  45. package/src/components/Tree/helpers.ts +25 -0
  46. package/src/components/Tree/index.ts +7 -0
  47. package/src/components/Tree/testing.ts +170 -0
  48. package/src/components/Tree/types.ts +34 -0
  49. package/src/components/index.ts +1 -0
  50. package/dist/types/src/testing.d.ts.map +0 -1
  51. /package/dist/types/src/{testing.d.ts → components/List/testing.d.ts} +0 -0
  52. /package/src/{testing.ts → components/List/testing.ts} +0 -0
@@ -32,8 +32,8 @@ var edgeStyles = {
32
32
  var strokeSize = 2;
33
33
  var terminalSize = 8;
34
34
  var offsetToAlignTerminalWithLine = (strokeSize - terminalSize) / 2;
35
- var DropIndicator = ({ edge, gap = "0px" }) => {
36
- const lineOffset = `calc(-0.5 * (${gap} + ${strokeSize}px))`;
35
+ var DropIndicator = ({ edge, gap: gap2 = "0px" }) => {
36
+ const lineOffset = `calc(-0.5 * (${gap2} + ${strokeSize}px))`;
37
37
  const orientation = edgeToOrientationMap[edge];
38
38
  return /* @__PURE__ */ React.createElement("div", {
39
39
  style: {
@@ -51,18 +51,31 @@ var DropIndicator = ({ edge, gap = "0px" }) => {
51
51
  // packages/ui/react-ui-list/src/components/List/ListRoot.tsx
52
52
  import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
53
53
  import { extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
54
- import { reorderWithEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/util/reorder-with-edge";
54
+ import { getReorderDestinationIndex } from "@atlaskit/pragmatic-drag-and-drop-hitbox/util/get-reorder-destination-index";
55
55
  import { createContext } from "@radix-ui/react-context";
56
- import React2, { useEffect, useState } from "react";
57
- import { useControlledValue } from "@dxos/react-ui";
56
+ import React2, { useCallback, useEffect, useState } from "react";
58
57
  var LIST_NAME = "List";
59
58
  var [ListProvider, useListContext] = createContext(LIST_NAME);
60
- var ListRoot = ({ classNames, children, items: _items = [], isItem, onMove, ...props }) => {
61
- const [items, setItems] = useControlledValue(_items);
59
+ var defaultGetId = (item) => item?.id;
60
+ var ListRoot = ({ classNames, children, items, isItem: isItem2, getId = defaultGetId, onMove, ...props }) => {
61
+ const isEqual = useCallback((a, b) => {
62
+ const idA = getId?.(a);
63
+ const idB = getId?.(b);
64
+ if (idA !== void 0 && idB !== void 0) {
65
+ return idA === idB;
66
+ } else {
67
+ return a === b;
68
+ }
69
+ }, [
70
+ getId
71
+ ]);
62
72
  const [state, setState] = useState(idle);
63
73
  useEffect(() => {
74
+ if (!items) {
75
+ return;
76
+ }
64
77
  return monitorForElements({
65
- canMonitor: ({ source }) => isItem(source.data),
78
+ canMonitor: ({ source }) => isItem2(source.data),
66
79
  onDrop: ({ location, source }) => {
67
80
  const target = location.current.dropTargets[0];
68
81
  if (!target) {
@@ -70,36 +83,37 @@ var ListRoot = ({ classNames, children, items: _items = [], isItem, onMove, ...p
70
83
  }
71
84
  const sourceData = source.data;
72
85
  const targetData = target.data;
73
- if (!isItem(sourceData) || !isItem(targetData)) {
86
+ if (!isItem2(sourceData) || !isItem2(targetData)) {
74
87
  return;
75
88
  }
76
- const sourceIdx = items.findIndex((item) => item.id === sourceData.id);
77
- const targetIdx = items.findIndex((item) => item.id === targetData.id);
89
+ const sourceIdx = items.findIndex((item) => isEqual(item, sourceData));
90
+ const targetIdx = items.findIndex((item) => isEqual(item, targetData));
78
91
  if (targetIdx < 0 || sourceIdx < 0) {
79
92
  return;
80
93
  }
81
94
  const closestEdgeOfTarget = extractClosestEdge(targetData);
82
- setItems(reorderWithEdge({
83
- list: items,
95
+ const destinationIndex = getReorderDestinationIndex({
96
+ closestEdgeOfTarget,
84
97
  startIndex: sourceIdx,
85
98
  indexOfTarget: targetIdx,
86
- axis: "vertical",
87
- closestEdgeOfTarget
88
- }));
89
- onMove?.(sourceData, targetIdx);
99
+ axis: "vertical"
100
+ });
101
+ onMove?.(sourceIdx, destinationIndex);
90
102
  }
91
103
  });
92
104
  }, [
93
- items
105
+ items,
106
+ isEqual,
107
+ onMove
94
108
  ]);
95
109
  return /* @__PURE__ */ React2.createElement(ListProvider, {
96
- isItem,
110
+ isItem: isItem2,
97
111
  state,
98
112
  setState,
99
113
  ...props
100
114
  }, children?.({
101
115
  state,
102
- items
116
+ items: items ?? []
103
117
  }));
104
118
  };
105
119
 
@@ -115,7 +129,7 @@ var defaultContext = {};
115
129
  var LIST_ITEM_NAME = "ListItem";
116
130
  var [ListItemProvider, useListItemContext] = createContext2(LIST_ITEM_NAME, defaultContext);
117
131
  var ListItem = ({ children, classNames, item }) => {
118
- const { isItem, dragPreview, setState: setRootState } = useListContext(LIST_ITEM_NAME);
132
+ const { isItem: isItem2, dragPreview, setState: setRootState } = useListContext(LIST_ITEM_NAME);
119
133
  const ref = useRef(null);
120
134
  const dragHandleRef = useRef(null);
121
135
  const [state, setState] = useState2(idle);
@@ -123,7 +137,7 @@ var ListItem = ({ children, classNames, item }) => {
123
137
  const element = ref.current;
124
138
  invariant(element, void 0, {
125
139
  F: __dxlog_file,
126
- L: 89,
140
+ L: 91,
127
141
  S: void 0,
128
142
  A: [
129
143
  "element",
@@ -183,7 +197,7 @@ var ListItem = ({ children, classNames, item }) => {
183
197
  dropTargetForElements({
184
198
  element,
185
199
  canDrop: ({ source }) => {
186
- return source.element !== element && isItem(source.data);
200
+ return source.element !== element && isItem2(source.data);
187
201
  },
188
202
  getData: ({ input }) => {
189
203
  return attachClosestEdge(item, {
@@ -267,7 +281,7 @@ var ListItemDragHandle = () => {
267
281
  const { dragHandleRef } = useListItemContext("DRAG_HANDLE");
268
282
  return /* @__PURE__ */ React3.createElement(IconButton, {
269
283
  ref: dragHandleRef,
270
- icon: "ph--dots-six--regular"
284
+ icon: "ph--dots-six-vertical--regular"
271
285
  });
272
286
  };
273
287
  var ListItemDragPreview = ({ children }) => {
@@ -277,7 +291,7 @@ var ListItemDragPreview = ({ children }) => {
277
291
  }), state.container) : null;
278
292
  };
279
293
  var ListItemWrapper = ({ classNames, children }) => /* @__PURE__ */ React3.createElement("div", {
280
- className: mx2("flex w-full", classNames)
294
+ className: mx2("flex is-full gap-2", classNames)
281
295
  }, children);
282
296
  var ListItemTitle = ({ classNames, children, ...props }) => /* @__PURE__ */ React3.createElement("div", {
283
297
  className: mx2("flex grow items-center truncate", classNames),
@@ -295,7 +309,377 @@ var List = {
295
309
  ItemTitle: ListItemTitle,
296
310
  IconButton
297
311
  };
312
+
313
+ // packages/ui/react-ui-list/src/components/Tree/Tree.tsx
314
+ import React8 from "react";
315
+ import { Treegrid as Treegrid2 } from "@dxos/react-ui";
316
+ import { Path } from "@dxos/react-ui-mosaic";
317
+
318
+ // packages/ui/react-ui-list/src/components/Tree/TreeItem.tsx
319
+ import { combine as combine2 } from "@atlaskit/pragmatic-drag-and-drop/combine";
320
+ import { draggable as draggable2, dropTargetForElements as dropTargetForElements2 } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
321
+ import { attachInstruction, extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
322
+ import React7, { memo as memo3, useCallback as useCallback3, useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
323
+ import { invariant as invariant2 } from "@dxos/invariant";
324
+ import { Treegrid } from "@dxos/react-ui";
325
+ import { focusRing, hoverableControls, hoverableFocusedKeyboardControls, hoverableFocusedWithinControls, mx as mx6 } from "@dxos/react-ui-theme";
326
+
327
+ // packages/ui/react-ui-list/src/components/Tree/DropIndicator.tsx
328
+ import React4 from "react";
329
+ import { mx as mx3 } from "@dxos/react-ui-theme";
330
+ var edgeToOrientationMap2 = {
331
+ "reorder-above": "sibling",
332
+ "reorder-below": "sibling",
333
+ "make-child": "child",
334
+ reparent: "child"
335
+ };
336
+ var orientationStyles2 = {
337
+ // TODO(wittjosiah): Stop using left/right here.
338
+ sibling: "bs-[--line-thickness] left-[--horizontal-indent] right-0 bg-accentSurface before:left-[--negative-terminal-size]",
339
+ child: "is-full block-start-0 block-end-0 border-[length:--line-thickness] before:invisible"
340
+ };
341
+ var instructionStyles = {
342
+ "reorder-above": "block-start-[--line-offset] before:block-start-[--offset-terminal]",
343
+ "reorder-below": "block-end-[--line-offset] before:block-end-[--offset-terminal]",
344
+ "make-child": "border-accentSurface",
345
+ // TODO(wittjosiah): This is not occurring in the current implementation.
346
+ reparent: ""
347
+ };
348
+ var strokeSize2 = 2;
349
+ var terminalSize2 = 8;
350
+ var offsetToAlignTerminalWithLine2 = (strokeSize2 - terminalSize2) / 2;
351
+ var gap = "0px";
352
+ var DropIndicator2 = ({ instruction }) => {
353
+ const lineOffset = `calc(-0.5 * (${gap} + ${strokeSize2}px))`;
354
+ const isBlocked = instruction.type === "instruction-blocked";
355
+ const desiredInstruction = isBlocked ? instruction.desired : instruction;
356
+ const orientation = edgeToOrientationMap2[desiredInstruction.type];
357
+ if (isBlocked) {
358
+ return null;
359
+ }
360
+ return /* @__PURE__ */ React4.createElement("div", {
361
+ style: {
362
+ "--line-thickness": `${strokeSize2}px`,
363
+ "--line-offset": `${lineOffset}`,
364
+ "--terminal-size": `${terminalSize2}px`,
365
+ "--terminal-radius": `${terminalSize2 / 2}px`,
366
+ "--negative-terminal-size": `-${terminalSize2}px`,
367
+ "--offset-terminal": `${offsetToAlignTerminalWithLine2}px`,
368
+ "--horizontal-indent": `${desiredInstruction.currentLevel * desiredInstruction.indentPerLevel + 4}px`
369
+ },
370
+ className: mx3("absolute z-10 pointer-events-none", "before:is-[--terminal-size] before:bs-[--terminal-size] box-border before:absolute", "before:border-[length:--line-thickness] before:border-solid before:border-accentSurface before:rounded-full", orientationStyles2[orientation], instructionStyles[desiredInstruction.type])
371
+ });
372
+ };
373
+
374
+ // packages/ui/react-ui-list/src/components/Tree/TreeItemHeading.tsx
375
+ import React5, { forwardRef as forwardRef2, memo, useCallback as useCallback2 } from "react";
376
+ import { Button, Icon as Icon2, toLocalizedString, useTranslation } from "@dxos/react-ui";
377
+ import { TextTooltip } from "@dxos/react-ui-text-tooltip";
378
+ import { mx as mx4 } from "@dxos/react-ui-theme";
379
+ var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef2(({ label, icon, className, disabled, current, onSelect }, forwardedRef) => {
380
+ const { t } = useTranslation();
381
+ const handleButtonKeydown = useCallback2((event) => {
382
+ if (event.key === " " || event.key === "Enter") {
383
+ event.preventDefault();
384
+ event.stopPropagation();
385
+ onSelect?.();
386
+ }
387
+ }, [
388
+ onSelect
389
+ ]);
390
+ return /* @__PURE__ */ React5.createElement(TextTooltip, {
391
+ text: toLocalizedString(label, t),
392
+ side: "bottom",
393
+ truncateQuery: "span[data-tooltip]",
394
+ onlyWhenTruncating: true,
395
+ asChild: true,
396
+ ref: forwardedRef
397
+ }, /* @__PURE__ */ React5.createElement(Button, {
398
+ "data-testid": "treeItem.heading",
399
+ variant: "ghost",
400
+ density: "fine",
401
+ classNames: mx4("grow gap-1 !pis-0.5 hover:!bg-transparent dark:hover:!bg-transparent", className),
402
+ disabled,
403
+ onClick: onSelect,
404
+ onKeyDown: handleButtonKeydown,
405
+ ...current && {
406
+ "aria-current": "location"
407
+ }
408
+ }, icon && /* @__PURE__ */ React5.createElement(Icon2, {
409
+ icon: icon ?? "ph--placeholder--regular",
410
+ size: 4,
411
+ classNames: "is-[1em] bs-[1em] mlb-1"
412
+ }), /* @__PURE__ */ React5.createElement("span", {
413
+ className: "flex-1 is-0 truncate text-start text-sm font-normal"
414
+ }, toLocalizedString(label, t))));
415
+ }));
416
+
417
+ // packages/ui/react-ui-list/src/components/Tree/TreeItemToggle.tsx
418
+ import React6, { forwardRef as forwardRef3, memo as memo2 } from "react";
419
+ import { Button as Button2, Icon as Icon3 } from "@dxos/react-ui";
420
+ import { mx as mx5 } from "@dxos/react-ui-theme";
421
+ var TreeItemToggle = /* @__PURE__ */ memo2(/* @__PURE__ */ forwardRef3(({ open, isBranch, onToggle }, forwardedRef) => {
422
+ return /* @__PURE__ */ React6.createElement(Button2, {
423
+ ref: forwardedRef,
424
+ "data-testid": "treeItem.toggle",
425
+ variant: "ghost",
426
+ density: "fine",
427
+ classNames: mx5("!pli-1", !isBranch && "invisible"),
428
+ onClick: onToggle
429
+ }, /* @__PURE__ */ React6.createElement(Icon3, {
430
+ icon: "ph--caret-right--regular",
431
+ size: 3,
432
+ classNames: mx5("transition duration-200", open && "rotate-90")
433
+ }));
434
+ }));
435
+
436
+ // packages/ui/react-ui-list/src/components/Tree/helpers.ts
437
+ var DEFAULT_INDENTATION = 8;
438
+ var paddingIndendation = (level, indentation = DEFAULT_INDENTATION) => ({
439
+ paddingInlineStart: `${(level - 1) * indentation}px`
440
+ });
441
+ var getMode = (items, index) => {
442
+ const item = items[index];
443
+ const next = items[index + 1];
444
+ if (!next || item.path.length > next.path.length) {
445
+ return "last-in-group";
446
+ } else if (item.path.length < next.path.length) {
447
+ return "expanded";
448
+ } else {
449
+ return "standard";
450
+ }
451
+ };
452
+
453
+ // packages/ui/react-ui-list/src/components/Tree/TreeItem.tsx
454
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-list/src/components/Tree/TreeItem.tsx";
455
+ var hoverableDescriptionIcons = "[--icons-color:inherit] hover-hover:[--icons-color:var(--description-text)] hover-hover:hover:[--icons-color:inherit] focus-within:[--icons-color:inherit]";
456
+ var RawTreeItem = ({ item, mode, open, current, draggable: _draggable, renderColumns: Columns, canDrop, onOpenChange, onSelect }) => {
457
+ const { id, label, icon, className, headingClassName, disabled, path, parentOf } = item;
458
+ const level = path.length - 2;
459
+ const isBranch = !!parentOf;
460
+ const rowRef = useRef2(null);
461
+ const buttonRef = useRef2(null);
462
+ const openRef = useRef2(false);
463
+ const cancelExpandRef = useRef2(null);
464
+ const [_state, setState] = useState3("idle");
465
+ const [instruction, setInstruction] = useState3(null);
466
+ const [menuOpen, setMenuOpen] = useState3(false);
467
+ const cancelExpand = useCallback3(() => {
468
+ if (cancelExpandRef.current) {
469
+ clearTimeout(cancelExpandRef.current);
470
+ cancelExpandRef.current = null;
471
+ }
472
+ }, []);
473
+ useEffect3(() => {
474
+ if (!_draggable) {
475
+ return;
476
+ }
477
+ invariant2(buttonRef.current, void 0, {
478
+ F: __dxlog_file2,
479
+ L: 86,
480
+ S: void 0,
481
+ A: [
482
+ "buttonRef.current",
483
+ ""
484
+ ]
485
+ });
486
+ return combine2(draggable2({
487
+ element: buttonRef.current,
488
+ getInitialData: () => item,
489
+ onDragStart: () => {
490
+ setState("dragging");
491
+ if (open) {
492
+ openRef.current = true;
493
+ onOpenChange?.(item, false);
494
+ }
495
+ },
496
+ onDrop: () => {
497
+ setState("idle");
498
+ if (openRef.current) {
499
+ onOpenChange?.(item, true);
500
+ }
501
+ }
502
+ }), dropTargetForElements2({
503
+ element: buttonRef.current,
504
+ getData: ({ input, element }) => {
505
+ return attachInstruction(item, {
506
+ input,
507
+ element,
508
+ indentPerLevel: DEFAULT_INDENTATION,
509
+ currentLevel: level,
510
+ mode,
511
+ block: isBranch ? [] : [
512
+ "make-child"
513
+ ]
514
+ });
515
+ },
516
+ canDrop: ({ source }) => {
517
+ const _canDrop = canDrop ?? (() => true);
518
+ return source.element !== buttonRef.current && _canDrop(source.data, item);
519
+ },
520
+ getIsSticky: () => true,
521
+ onDrag: ({ self, source }) => {
522
+ const instruction2 = extractInstruction(self.data);
523
+ if (source.data.id !== item.id) {
524
+ if (instruction2?.type === "make-child" && isBranch && !open && !cancelExpandRef.current) {
525
+ cancelExpandRef.current = setTimeout(() => {
526
+ onOpenChange?.(item, true);
527
+ }, 500);
528
+ }
529
+ if (instruction2?.type !== "make-child") {
530
+ cancelExpand();
531
+ }
532
+ setInstruction(instruction2);
533
+ } else if (instruction2?.type === "reparent") {
534
+ setInstruction(instruction2);
535
+ } else {
536
+ setInstruction(null);
537
+ }
538
+ },
539
+ onDragLeave: () => {
540
+ cancelExpand();
541
+ setInstruction(null);
542
+ },
543
+ onDrop: () => {
544
+ cancelExpand();
545
+ setInstruction(null);
546
+ }
547
+ }));
548
+ }, [
549
+ draggable2,
550
+ item,
551
+ mode,
552
+ open,
553
+ canDrop
554
+ ]);
555
+ useEffect3(() => () => cancelExpand(), [
556
+ cancelExpand
557
+ ]);
558
+ const handleOpenChange = useCallback3(() => onOpenChange?.(item, !open), [
559
+ onOpenChange,
560
+ item,
561
+ open
562
+ ]);
563
+ const handleSelect = useCallback3(() => {
564
+ rowRef.current?.focus();
565
+ onSelect?.(item, !current);
566
+ }, [
567
+ onSelect,
568
+ item,
569
+ current
570
+ ]);
571
+ const handleKeyDown = useCallback3((event) => {
572
+ switch (event.key) {
573
+ case "ArrowRight":
574
+ isBranch && !open && handleOpenChange();
575
+ break;
576
+ case "ArrowLeft":
577
+ isBranch && open && handleOpenChange();
578
+ break;
579
+ case " ":
580
+ handleSelect();
581
+ break;
582
+ }
583
+ }, [
584
+ isBranch,
585
+ open,
586
+ handleOpenChange,
587
+ handleSelect
588
+ ]);
589
+ return /* @__PURE__ */ React7.createElement(Treegrid.Row, {
590
+ ref: rowRef,
591
+ key: id,
592
+ id,
593
+ "aria-labelledby": `${id}__label`,
594
+ parentOf: parentOf?.join(Treegrid.PARENT_OF_SEPARATOR),
595
+ classNames: mx6("grid grid-cols-subgrid col-[tree-row] aria-[current]:bg-input", hoverableControls, hoverableFocusedKeyboardControls, hoverableFocusedWithinControls, hoverableDescriptionIcons, focusRing, className),
596
+ "data-itemid": item.id,
597
+ "data-testid": item.testId,
598
+ // NOTE(thure): This is intentionally an empty string to for descendents to select by in the CSS
599
+ // without alerting the user (except for in the correct link element). See also:
600
+ // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current#description
601
+ "aria-current": current ? "" : void 0,
602
+ onKeyDown: handleKeyDown,
603
+ onContextMenu: (event) => {
604
+ event.preventDefault();
605
+ setMenuOpen(true);
606
+ }
607
+ }, /* @__PURE__ */ React7.createElement(Treegrid.Cell, {
608
+ indent: true,
609
+ classNames: "relative grid grid-cols-subgrid col-[tree-row]",
610
+ style: paddingIndendation(level)
611
+ }, /* @__PURE__ */ React7.createElement("div", {
612
+ role: "none",
613
+ className: "flex items-center"
614
+ }, /* @__PURE__ */ React7.createElement(TreeItemToggle, {
615
+ open,
616
+ isBranch,
617
+ onToggle: handleOpenChange
618
+ }), /* @__PURE__ */ React7.createElement(TreeItemHeading, {
619
+ ref: buttonRef,
620
+ label,
621
+ icon,
622
+ className: headingClassName,
623
+ disabled,
624
+ current,
625
+ onSelect: handleSelect
626
+ })), Columns && /* @__PURE__ */ React7.createElement(Columns, {
627
+ item,
628
+ menuOpen,
629
+ setMenuOpen
630
+ }), instruction && /* @__PURE__ */ React7.createElement(DropIndicator2, {
631
+ instruction
632
+ })));
633
+ };
634
+ var TreeItem = /* @__PURE__ */ memo3(RawTreeItem);
635
+
636
+ // packages/ui/react-ui-list/src/components/Tree/Tree.tsx
637
+ var Tree = ({ items, open, current, draggable: draggable3 = false, gridTemplateColumns = "[tree-row-start] 1fr min-content [tree-row-end]", classNames, renderColumns, canDrop, onOpenChange, onSelect }) => {
638
+ return /* @__PURE__ */ React8.createElement(Treegrid2.Root, {
639
+ gridTemplateColumns,
640
+ classNames
641
+ }, items.map((item, i) => {
642
+ const path = Path.create(...item.path);
643
+ return /* @__PURE__ */ React8.createElement(TreeItem, {
644
+ key: item.id,
645
+ item,
646
+ mode: getMode(items, i),
647
+ open: open.includes(path),
648
+ // TODO(wittjosiah): This should also be path-based.
649
+ current: current.includes(item.id),
650
+ draggable: draggable3,
651
+ renderColumns,
652
+ canDrop,
653
+ onOpenChange,
654
+ onSelect
655
+ });
656
+ }));
657
+ };
658
+
659
+ // packages/ui/react-ui-list/src/components/Tree/types.ts
660
+ import { S } from "@dxos/echo-schema";
661
+ var LabelSchema = S.Union(S.String, S.Tuple(S.String, S.Struct({
662
+ ns: S.String,
663
+ count: S.optional(S.Number)
664
+ })));
665
+ var ItemSchema = S.mutable(S.Struct({
666
+ id: S.String,
667
+ label: S.mutable(LabelSchema),
668
+ icon: S.optional(S.String),
669
+ disabled: S.optional(S.Boolean),
670
+ className: S.optional(S.String),
671
+ headingClassName: S.optional(S.String),
672
+ testId: S.optional(S.String),
673
+ path: S.Array(S.String),
674
+ parentOf: S.optional(S.Array(S.String))
675
+ }));
676
+ var isItem = S.is(ItemSchema);
298
677
  export {
299
- List
678
+ ItemSchema,
679
+ List,
680
+ RawTreeItem,
681
+ Tree,
682
+ TreeItem,
683
+ isItem
300
684
  };
301
685
  //# sourceMappingURL=index.mjs.map