@dxos/react-ui-list 0.6.14-main.7bd9c89 → 0.6.14-main.f49f251

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