@dxos/react-ui-list 0.6.13-main.548ca8d → 0.6.14-main.1366248

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 +413 -31
  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 +6 -10
  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 -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 +20 -15
  36. package/src/components/List/List.stories.tsx +25 -19
  37. package/src/components/List/ListItem.tsx +11 -9
  38. package/src/components/List/ListRoot.tsx +47 -23
  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,19 +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 { flushSync } from "react-dom";
58
- import { useControlledValue } from "@dxos/react-ui";
56
+ import React2, { useCallback, useEffect, useState } from "react";
59
57
  var LIST_NAME = "List";
60
58
  var [ListProvider, useListContext] = createContext(LIST_NAME);
61
- var ListRoot = ({ classNames, children, items: _items = [], isItem, ...props }) => {
62
- 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
+ ]);
63
72
  const [state, setState] = useState(idle);
64
73
  useEffect(() => {
74
+ if (!items) {
75
+ return;
76
+ }
65
77
  return monitorForElements({
66
- canMonitor: ({ source }) => isItem(source.data),
78
+ canMonitor: ({ source }) => isItem2(source.data),
67
79
  onDrop: ({ location, source }) => {
68
80
  const target = location.current.dropTargets[0];
69
81
  if (!target) {
@@ -71,37 +83,37 @@ var ListRoot = ({ classNames, children, items: _items = [], isItem, ...props })
71
83
  }
72
84
  const sourceData = source.data;
73
85
  const targetData = target.data;
74
- if (!isItem(sourceData) || !isItem(targetData)) {
86
+ if (!isItem2(sourceData) || !isItem2(targetData)) {
75
87
  return;
76
88
  }
77
- const sourceIdx = items.findIndex((item) => item.id === sourceData.id);
78
- 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));
79
91
  if (targetIdx < 0 || sourceIdx < 0) {
80
92
  return;
81
93
  }
82
94
  const closestEdgeOfTarget = extractClosestEdge(targetData);
83
- flushSync(() => {
84
- setItems(reorderWithEdge({
85
- list: items,
86
- startIndex: sourceIdx,
87
- indexOfTarget: targetIdx,
88
- axis: "vertical",
89
- closestEdgeOfTarget
90
- }));
95
+ const destinationIndex = getReorderDestinationIndex({
96
+ closestEdgeOfTarget,
97
+ startIndex: sourceIdx,
98
+ indexOfTarget: targetIdx,
99
+ axis: "vertical"
91
100
  });
101
+ onMove?.(sourceIdx, destinationIndex);
92
102
  }
93
103
  });
94
104
  }, [
95
- items
105
+ items,
106
+ isEqual,
107
+ onMove
96
108
  ]);
97
109
  return /* @__PURE__ */ React2.createElement(ListProvider, {
98
- isItem,
110
+ isItem: isItem2,
99
111
  state,
100
112
  setState,
101
113
  ...props
102
114
  }, children?.({
103
115
  state,
104
- items
116
+ items: items ?? []
105
117
  }));
106
118
  };
107
119
 
@@ -117,7 +129,7 @@ var defaultContext = {};
117
129
  var LIST_ITEM_NAME = "ListItem";
118
130
  var [ListItemProvider, useListItemContext] = createContext2(LIST_ITEM_NAME, defaultContext);
119
131
  var ListItem = ({ children, classNames, item }) => {
120
- const { isItem, dragPreview, setState: setRootState } = useListContext(LIST_ITEM_NAME);
132
+ const { isItem: isItem2, dragPreview, setState: setRootState } = useListContext(LIST_ITEM_NAME);
121
133
  const ref = useRef(null);
122
134
  const dragHandleRef = useRef(null);
123
135
  const [state, setState] = useState2(idle);
@@ -125,7 +137,7 @@ var ListItem = ({ children, classNames, item }) => {
125
137
  const element = ref.current;
126
138
  invariant(element, void 0, {
127
139
  F: __dxlog_file,
128
- L: 89,
140
+ L: 91,
129
141
  S: void 0,
130
142
  A: [
131
143
  "element",
@@ -185,7 +197,7 @@ var ListItem = ({ children, classNames, item }) => {
185
197
  dropTargetForElements({
186
198
  element,
187
199
  canDrop: ({ source }) => {
188
- return source.element !== element && isItem(source.data);
200
+ return source.element !== element && isItem2(source.data);
189
201
  },
190
202
  getData: ({ input }) => {
191
203
  return attachClosestEdge(item, {
@@ -236,7 +248,7 @@ var ListItem = ({ children, classNames, item }) => {
236
248
  }, /* @__PURE__ */ React3.createElement("div", {
237
249
  ref,
238
250
  role: "listitem",
239
- className: mx2("flex", classNames, stateStyles[state.type])
251
+ className: mx2("flex overflow-hidden", classNames, stateStyles[state.type])
240
252
  }, children), state.type === "is-dragging-over" && state.closestEdge && /* @__PURE__ */ React3.createElement(DropIndicator, {
241
253
  edge: state.closestEdge
242
254
  })));
@@ -269,7 +281,7 @@ var ListItemDragHandle = () => {
269
281
  const { dragHandleRef } = useListItemContext("DRAG_HANDLE");
270
282
  return /* @__PURE__ */ React3.createElement(IconButton, {
271
283
  ref: dragHandleRef,
272
- icon: "ph--dots-six--regular"
284
+ icon: "ph--dots-six-vertical--regular"
273
285
  });
274
286
  };
275
287
  var ListItemDragPreview = ({ children }) => {
@@ -279,10 +291,10 @@ var ListItemDragPreview = ({ children }) => {
279
291
  }), state.container) : null;
280
292
  };
281
293
  var ListItemWrapper = ({ classNames, children }) => /* @__PURE__ */ React3.createElement("div", {
282
- className: mx2("flex w-full", classNames)
294
+ className: mx2("flex is-full gap-2", classNames)
283
295
  }, children);
284
296
  var ListItemTitle = ({ classNames, children, ...props }) => /* @__PURE__ */ React3.createElement("div", {
285
- className: mx2("flex w-full items-center", classNames),
297
+ className: mx2("flex grow items-center truncate", classNames),
286
298
  ...props
287
299
  }, children);
288
300
 
@@ -297,7 +309,377 @@ var List = {
297
309
  ItemTitle: ListItemTitle,
298
310
  IconButton
299
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);
300
677
  export {
301
- List
678
+ ItemSchema,
679
+ List,
680
+ RawTreeItem,
681
+ Tree,
682
+ TreeItem,
683
+ isItem
302
684
  };
303
685
  //# sourceMappingURL=index.mjs.map