@dxos/react-ui-list 0.9.1-main.c7dcc2e112 → 0.10.0

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 (101) hide show
  1. package/dist/lib/browser/index.mjs +628 -167
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +628 -167
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/aspects/useListDisclosure.d.ts +4 -4
  8. package/dist/types/src/aspects/useListDisclosure.d.ts.map +1 -1
  9. package/dist/types/src/aspects/useListNavigation.d.ts +9 -7
  10. package/dist/types/src/aspects/useListNavigation.d.ts.map +1 -1
  11. package/dist/types/src/aspects/useListSelection.d.ts +3 -3
  12. package/dist/types/src/aspects/useListSelection.d.ts.map +1 -1
  13. package/dist/types/src/components/Accordion/Accordion.d.ts +1 -1
  14. package/dist/types/src/components/Accordion/AccordionItem.d.ts +3 -1
  15. package/dist/types/src/components/Accordion/AccordionItem.d.ts.map +1 -1
  16. package/dist/types/src/components/Combobox/Combobox.d.ts +10 -3
  17. package/dist/types/src/components/Combobox/Combobox.d.ts.map +1 -1
  18. package/dist/types/src/components/DropIndicator/DropIndicator.d.ts +12 -0
  19. package/dist/types/src/components/DropIndicator/DropIndicator.d.ts.map +1 -0
  20. package/dist/types/src/components/DropIndicator/index.d.ts +2 -0
  21. package/dist/types/src/components/DropIndicator/index.d.ts.map +1 -0
  22. package/dist/types/src/components/Empty/Empty.d.ts +17 -0
  23. package/dist/types/src/components/Empty/Empty.d.ts.map +1 -0
  24. package/dist/types/src/components/Empty/Empty.stories.d.ts +18 -0
  25. package/dist/types/src/components/Empty/Empty.stories.d.ts.map +1 -0
  26. package/dist/types/src/components/Empty/index.d.ts +2 -0
  27. package/dist/types/src/components/Empty/index.d.ts.map +1 -0
  28. package/dist/types/src/components/List.theme.d.ts +193 -0
  29. package/dist/types/src/components/List.theme.d.ts.map +1 -0
  30. package/dist/types/src/components/Listbox/ListItemContent.d.ts +27 -0
  31. package/dist/types/src/components/Listbox/ListItemContent.d.ts.map +1 -0
  32. package/dist/types/src/components/Listbox/ListItemContent.stories.d.ts +24 -0
  33. package/dist/types/src/components/Listbox/ListItemContent.stories.d.ts.map +1 -0
  34. package/dist/types/src/components/Listbox/Listbox.d.ts +19 -2
  35. package/dist/types/src/components/Listbox/Listbox.d.ts.map +1 -1
  36. package/dist/types/src/components/Listbox/Listbox.stories.d.ts +4 -0
  37. package/dist/types/src/components/Listbox/Listbox.stories.d.ts.map +1 -1
  38. package/dist/types/src/components/OrderedList/OrderedList.d.ts +1 -1
  39. package/dist/types/src/components/OrderedList/OrderedList.d.ts.map +1 -1
  40. package/dist/types/src/components/OrderedList/OrderedListItem.d.ts.map +1 -1
  41. package/dist/types/src/components/OrderedList/OrderedListRoot.d.ts +1 -1
  42. package/dist/types/src/components/OrderedList/OrderedListRoot.d.ts.map +1 -1
  43. package/dist/types/src/components/Picker/Picker.d.ts +12 -4
  44. package/dist/types/src/components/Picker/Picker.d.ts.map +1 -1
  45. package/dist/types/src/components/Picker/index.d.ts +1 -1
  46. package/dist/types/src/components/Picker/index.d.ts.map +1 -1
  47. package/dist/types/src/components/Tree/Tree.d.ts +1 -1
  48. package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
  49. package/dist/types/src/components/Tree/Tree.stories.d.ts +5 -2
  50. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
  51. package/dist/types/src/components/Tree/TreeContext.d.ts +2 -0
  52. package/dist/types/src/components/Tree/TreeContext.d.ts.map +1 -1
  53. package/dist/types/src/components/Tree/TreeDropIndicator.d.ts +10 -0
  54. package/dist/types/src/components/Tree/TreeDropIndicator.d.ts.map +1 -0
  55. package/dist/types/src/components/Tree/TreeItem.d.ts.map +1 -1
  56. package/dist/types/src/components/Tree/testing.d.ts +4 -1
  57. package/dist/types/src/components/Tree/testing.d.ts.map +1 -1
  58. package/dist/types/src/components/Treegrid/Treegrid.d.ts +33 -0
  59. package/dist/types/src/components/Treegrid/Treegrid.d.ts.map +1 -0
  60. package/dist/types/src/components/Treegrid/Treegrid.stories.d.ts +11 -0
  61. package/dist/types/src/components/Treegrid/Treegrid.stories.d.ts.map +1 -0
  62. package/dist/types/src/components/Treegrid/Treegrid.theme.d.ts +37 -0
  63. package/dist/types/src/components/Treegrid/Treegrid.theme.d.ts.map +1 -0
  64. package/dist/types/src/components/Treegrid/index.d.ts +2 -0
  65. package/dist/types/src/components/Treegrid/index.d.ts.map +1 -0
  66. package/dist/types/src/components/index.d.ts +3 -0
  67. package/dist/types/src/components/index.d.ts.map +1 -1
  68. package/dist/types/tsconfig.tsbuildinfo +1 -1
  69. package/package.json +23 -22
  70. package/src/aspects/useListDisclosure.ts +8 -8
  71. package/src/aspects/useListNavigation.ts +9 -7
  72. package/src/aspects/useListSelection.ts +4 -4
  73. package/src/components/Accordion/AccordionItem.tsx +31 -13
  74. package/src/components/Combobox/Combobox.tsx +46 -38
  75. package/src/components/DropIndicator/DropIndicator.tsx +74 -0
  76. package/src/components/DropIndicator/index.ts +5 -0
  77. package/src/components/Empty/Empty.stories.tsx +37 -0
  78. package/src/components/Empty/Empty.tsx +41 -0
  79. package/src/components/Empty/index.ts +5 -0
  80. package/src/components/List.theme.ts +99 -0
  81. package/src/components/Listbox/ListItemContent.stories.tsx +41 -0
  82. package/src/components/Listbox/ListItemContent.tsx +49 -0
  83. package/src/components/Listbox/Listbox.stories.tsx +106 -7
  84. package/src/components/Listbox/Listbox.tsx +85 -42
  85. package/src/components/OrderedList/OrderedList.tsx +1 -1
  86. package/src/components/OrderedList/OrderedListItem.tsx +13 -13
  87. package/src/components/OrderedList/OrderedListRoot.tsx +6 -3
  88. package/src/components/Picker/Picker.tsx +25 -15
  89. package/src/components/Picker/index.ts +1 -1
  90. package/src/components/Tree/Tree.stories.tsx +39 -15
  91. package/src/components/Tree/Tree.tsx +13 -3
  92. package/src/components/Tree/TreeContext.tsx +2 -0
  93. package/src/components/Tree/TreeDropIndicator.tsx +72 -0
  94. package/src/components/Tree/TreeItem.tsx +43 -3
  95. package/src/components/Tree/TreeItemHeading.tsx +2 -2
  96. package/src/components/Tree/testing.ts +19 -14
  97. package/src/components/Treegrid/Treegrid.stories.tsx +132 -0
  98. package/src/components/Treegrid/Treegrid.theme.ts +38 -0
  99. package/src/components/Treegrid/Treegrid.tsx +187 -0
  100. package/src/components/Treegrid/index.ts +5 -0
  101. package/src/components/index.ts +3 -0
@@ -65,14 +65,14 @@ var useListDisclosure = (opts) => {
65
65
  triggerId,
66
66
  panelId,
67
67
  triggerProps: {
68
- id: triggerId,
68
+ "id": triggerId,
69
69
  "aria-expanded": expanded,
70
70
  "aria-controls": panelId,
71
- onClick: () => setExpanded(id, !expanded)
71
+ "onClick": () => setExpanded(id, !expanded)
72
72
  },
73
73
  panelProps: {
74
- id: panelId,
75
- role: "region",
74
+ "id": panelId,
75
+ "role": "region",
76
76
  "aria-labelledby": triggerId
77
77
  }
78
78
  };
@@ -259,7 +259,7 @@ var useListSelection = (opts) => {
259
259
  },
260
260
  rowProps: {
261
261
  "aria-selected": selected,
262
- onClick: () => {
262
+ "onClick": () => {
263
263
  if (disabled) {
264
264
  return;
265
265
  }
@@ -584,6 +584,82 @@ import React2 from "react";
584
584
  import { Icon } from "@dxos/react-ui";
585
585
  import { mx as mx2 } from "@dxos/ui-theme";
586
586
 
587
+ // src/components/List.theme.ts
588
+ import { tv } from "@dxos/ui-theme";
589
+ var listStyles = tv({
590
+ slots: {
591
+ //
592
+ // Accordion
593
+ //
594
+ accordionItem: "overflow-hidden",
595
+ // Row trigger: spans the full width and pins the trailing caret to the inline-end edge.
596
+ accordionTrigger: "group flex items-start justify-between gap-2 p-2 dx-focus-ring-inset w-full text-start",
597
+ // Leading / trailing icon wrappers: fixed height so they sit on the centerline of the first
598
+ // content line even when the header spans multiple lines.
599
+ accordionTriggerIcon: "flex items-center h-6 shrink-0",
600
+ accordionTriggerContent: "min-w-0 flex-1",
601
+ // Slide animations are driven by Radix Accordion's data-state attribute.
602
+ accordionBody: "overflow-hidden data-[state=closed]:animate-slide-up data-[state=open]:animate-slide-down",
603
+ accordionBodyContent: "p-2",
604
+ //
605
+ // Listbox
606
+ //
607
+ listboxViewport: "dx-container",
608
+ listboxContent: "flex flex-col",
609
+ // `dx-selected` pairs with `aria-selected="true"` set per-option (see
610
+ // `ui-theme/src/css/components/state.md`). `outline-none` removes the native focus
611
+ // ring; Tabster / `dx-focus-ring` handles keyboard focus at the container level.
612
+ listboxItem: "flex items-center dx-hover dx-selected px-3 py-2 cursor-pointer outline-none",
613
+ listboxItemLabel: "grow truncate",
614
+ //
615
+ // OrderedList
616
+ //
617
+ orderedListViewport: "dx-container",
618
+ orderedListContent: "flex flex-col",
619
+ // `dx-current` enables `aria-current` row styling (not listbox/option semantics).
620
+ orderedListItem: "relative dx-current",
621
+ // Bordered column wrapping title + detail panel in the master-detail layout.
622
+ orderedListDetailColumn: "flex flex-col ring-1 ring-subdued-separator rounded-sm overflow-hidden",
623
+ // `min-h` matches the shared rail-item track so handles, title, and caret share a baseline.
624
+ orderedListDetailTitleRow: "flex items-center min-h-[var(--dx-rail-item)]",
625
+ orderedListDetailPanel: "px-2 pb-2",
626
+ orderedListTitle: "flex grow items-center truncate cursor-pointer",
627
+ //
628
+ // Picker
629
+ //
630
+ // `px-[var(--gutter,…)]` aligns padding with sibling `Column.Center` content, falling back to
631
+ // 0.75rem when not nested under `Column.Root`.
632
+ pickerItem: "dx-hover dx-selected px-[var(--gutter,0.75rem)] py-1 cursor-pointer select-none",
633
+ //
634
+ // Combobox
635
+ //
636
+ // `m-form-chrome mb-0` mirrors the rest of the form-chrome padding convention.
637
+ comboboxInput: "m-form-chrome mb-0 w-[calc(100%-2*var(--spacing-form-chrome))]",
638
+ comboboxList: "py-form-chrome",
639
+ // Trigger value / placeholder text — grows and truncates; subdued when placeholder.
640
+ comboboxTriggerText: "font-normal text-start flex-1 min-w-0 truncate me-2",
641
+ // Item row adds flex layout; `dx-hover`/`dx-selected` and padding come from `Picker.Item`.
642
+ comboboxItem: "flex w-full gap-2 items-center",
643
+ comboboxItemDescription: "text-sm text-description truncate",
644
+ //
645
+ // ItemContent
646
+ //
647
+ // Two-column grid: fixed rail-item icon track + flexible content track.
648
+ itemContentRoot: "grid grid-cols-[var(--dx-rail-item)_minmax(0,1fr)] items-center gap-x-2 is-full min-is-0",
649
+ itemContentIcon: "col-start-1 row-start-1 place-self-center",
650
+ itemContentTitle: "col-start-2 row-start-1 min-is-0 truncate",
651
+ itemContentDescription: "col-start-2 row-start-2 min-is-0 truncate text-sm text-description",
652
+ //
653
+ // Empty
654
+ //
655
+ empty: "flex flex-col items-center justify-center gap-2 p-4 text-sm text-center text-description"
656
+ }
657
+ });
658
+ var listTheme = {
659
+ styles: listStyles
660
+ };
661
+ var listSlots = Object.keys(listTheme.styles());
662
+
587
663
  // src/components/Accordion/AccordionRoot.tsx
588
664
  import * as AccordionPrimitive from "@radix-ui/react-accordion";
589
665
  import { createContext } from "@radix-ui/react-context";
@@ -608,6 +684,7 @@ var AccordionRoot = ({ classNames, items, getId = defaultGetId, children, value,
608
684
 
609
685
  // src/components/Accordion/AccordionItem.tsx
610
686
  var ACCORDION_ITEM_NAME = "AccordionItem";
687
+ var styles = listTheme.styles();
611
688
  var [AccordionItemProvider, useDxAccordionItemContext] = createContext2(ACCORDION_ITEM_NAME);
612
689
  var AccordionItem = ({ children, classNames, item }) => {
613
690
  const { getId } = useAccordionContext(ACCORDION_ITEM_NAME);
@@ -615,31 +692,41 @@ var AccordionItem = ({ children, classNames, item }) => {
615
692
  item
616
693
  }, /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Item, {
617
694
  value: getId(item),
618
- className: mx2("overflow-hidden", classNames)
695
+ className: styles.accordionItem({
696
+ class: mx2(classNames)
697
+ })
619
698
  }, children));
620
699
  };
621
- var AccordionItemHeader = ({ classNames, children, icon, ...props }) => {
700
+ var AccordionItemHeader = ({ classNames, children, icon, hover, ...props }) => {
622
701
  return /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Header, {
623
702
  ...props,
624
703
  className: mx2(classNames)
625
704
  }, /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Trigger, {
626
- className: "group flex items-center justify-between gap-2 p-2 dx-focus-ring-inset w-full text-start"
627
- }, icon && /* @__PURE__ */ React2.createElement(Icon, {
705
+ className: styles.accordionTrigger({
706
+ class: hover && "dx-hover"
707
+ })
708
+ }, icon && /* @__PURE__ */ React2.createElement("span", {
709
+ className: styles.accordionTriggerIcon()
710
+ }, /* @__PURE__ */ React2.createElement(Icon, {
628
711
  icon,
629
712
  size: 4
630
- }), /* @__PURE__ */ React2.createElement("span", {
631
- className: "min-w-0 flex-1 truncate"
632
- }, children), /* @__PURE__ */ React2.createElement(Icon, {
713
+ })), /* @__PURE__ */ React2.createElement("div", {
714
+ className: styles.accordionTriggerContent()
715
+ }, children), /* @__PURE__ */ React2.createElement("span", {
716
+ className: styles.accordionTriggerIcon()
717
+ }, /* @__PURE__ */ React2.createElement(Icon, {
633
718
  icon: "ph--caret-right--regular",
634
719
  size: 4,
635
- classNames: "shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-90"
636
- })));
720
+ classNames: "transition-transform duration-200 group-data-[state=open]:rotate-90"
721
+ }))));
637
722
  };
638
723
  var AccordionItemBody = ({ children, classNames }) => {
639
724
  return /* @__PURE__ */ React2.createElement(AccordionPrimitive2.Content, {
640
- className: "overflow-hidden data-[state=closed]:animate-slide-up data-[state=open]:animate-slide-down"
725
+ className: styles.accordionBody()
641
726
  }, /* @__PURE__ */ React2.createElement("div", {
642
- className: mx2("p-2", classNames)
727
+ className: styles.accordionBodyContent({
728
+ class: mx2(classNames)
729
+ })
643
730
  }, children));
644
731
  };
645
732
 
@@ -671,14 +758,18 @@ var [PickerItemContextProvider, usePickerItemContext] = createContext3("PickerIt
671
758
  var [PickerInputContextProvider, usePickerInputContext] = createContext3("PickerInput");
672
759
 
673
760
  // src/components/Picker/Picker.tsx
674
- var PickerRoot = ({ children }) => {
761
+ var styles2 = listTheme.styles();
762
+ var PickerRoot = ({ children, resetSelectionOnChange = false }) => {
675
763
  const [selectedValue, setSelectedValue] = useState4(void 0);
676
764
  const itemsRef = useRef4(/* @__PURE__ */ new Map());
677
765
  const [itemVersion, setItemVersion] = useState4(0);
766
+ const prevItemVersionRef = useRef4(itemVersion);
678
767
  useEffect4(() => {
768
+ const itemsChanged = prevItemVersionRef.current !== itemVersion;
769
+ prevItemVersionRef.current = itemVersion;
679
770
  const current = selectedValue !== void 0 ? itemsRef.current.get(selectedValue) : void 0;
680
771
  const isValid = current !== void 0 && !current.disabled;
681
- if (!isValid && itemsRef.current.size > 0) {
772
+ if ((!isValid || resetSelectionOnChange && itemsChanged) && itemsRef.current.size > 0) {
682
773
  const entries = Array.from(itemsRef.current.entries()).filter(([, data]) => !data.disabled);
683
774
  if (entries.length > 0) {
684
775
  entries.sort(([, a], [, b]) => {
@@ -701,7 +792,8 @@ var PickerRoot = ({ children }) => {
701
792
  }
702
793
  }, [
703
794
  itemVersion,
704
- selectedValue
795
+ selectedValue,
796
+ resetSelectionOnChange
705
797
  ]);
706
798
  const registerItem = useCallback5((value, element, onSelect, disabled) => {
707
799
  if (element) {
@@ -910,7 +1002,9 @@ var PickerItem = /* @__PURE__ */ forwardRef(({ classNames, value, onSelect, disa
910
1002
  "data-value": value,
911
1003
  // Browser focus stays on the input; highlight is via `aria-selected`.
912
1004
  tabIndex: -1,
913
- className: mx3("dx-hover dx-selected px-[var(--gutter,0.75rem)] py-1 cursor-pointer select-none", disabled && "opacity-50 cursor-not-allowed", classNames),
1005
+ className: styles2.pickerItem({
1006
+ class: mx3(disabled && "opacity-50 cursor-not-allowed", classNames)
1007
+ }),
914
1008
  onMouseDown: handleMouseDown,
915
1009
  onClick: handleClick
916
1010
  }, children);
@@ -923,6 +1017,7 @@ var Picker = {
923
1017
  };
924
1018
 
925
1019
  // src/components/Combobox/Combobox.tsx
1020
+ var styles3 = listTheme.styles();
926
1021
  var COMBOBOX_NAME = "Combobox";
927
1022
  var COMBOBOX_CONTENT_NAME = "ComboboxContent";
928
1023
  var COMBOBOX_ITEM_NAME = "ComboboxItem";
@@ -954,7 +1049,7 @@ var ComboboxRoot = ({ children, modal, modalId: modalIdProp, open: openProp, def
954
1049
  onValueChange
955
1050
  }, children));
956
1051
  };
957
- var ComboboxContent = composable(({ children, ...props }, forwardedRef) => {
1052
+ var ComboboxContent = composable(({ children, resetSelectionOnChange, ...props }, forwardedRef) => {
958
1053
  const { modalId } = useComboboxContext(COMBOBOX_CONTENT_NAME);
959
1054
  return /* @__PURE__ */ React4.createElement(Popover.Content, {
960
1055
  ...composableProps(props, {
@@ -963,7 +1058,9 @@ var ComboboxContent = composable(({ children, ...props }, forwardedRef) => {
963
1058
  ref: forwardedRef
964
1059
  }, /* @__PURE__ */ React4.createElement(Popover.Viewport, {
965
1060
  classNames: "w-(--radix-popover-trigger-width)"
966
- }, /* @__PURE__ */ React4.createElement(Picker.Root, null, children)));
1061
+ }, /* @__PURE__ */ React4.createElement(Picker.Root, {
1062
+ resetSelectionOnChange
1063
+ }, children)));
967
1064
  });
968
1065
  ComboboxContent.displayName = COMBOBOX_CONTENT_NAME;
969
1066
  var ComboboxTrigger = /* @__PURE__ */ forwardRef2(({ children, onClick, ...props }, forwardedRef) => {
@@ -986,7 +1083,9 @@ var ComboboxTrigger = /* @__PURE__ */ forwardRef2(({ children, onClick, ...props
986
1083
  onClick: handleClick,
987
1084
  ref: forwardedRef
988
1085
  }, children ?? /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement("span", {
989
- className: mx4("font-normal text-start flex-1 min-w-0 truncate me-2", !value && "text-subdued")
1086
+ className: styles3.comboboxTriggerText({
1087
+ class: !value && "text-subdued"
1088
+ })
990
1089
  }, value || placeholder), /* @__PURE__ */ React4.createElement(Icon2, {
991
1090
  icon: "ph--caret-down--bold",
992
1091
  size: 3
@@ -997,10 +1096,9 @@ var ComboboxVirtualTrigger = Popover.VirtualTrigger;
997
1096
  var ComboboxInput = /* @__PURE__ */ forwardRef2(({ classNames, ...props }, forwardedRef) => {
998
1097
  return /* @__PURE__ */ React4.createElement(Picker.Input, {
999
1098
  ...props,
1000
- classNames: [
1001
- "m-form-chrome mb-0 w-[calc(100%-2*var(--spacing-form-chrome))]",
1002
- classNames
1003
- ],
1099
+ classNames: styles3.comboboxInput({
1100
+ class: classNames
1101
+ }),
1004
1102
  ref: forwardedRef
1005
1103
  });
1006
1104
  });
@@ -1008,10 +1106,9 @@ ComboboxInput.displayName = "Combobox.Input";
1008
1106
  var ComboboxList = /* @__PURE__ */ forwardRef2(({ classNames, children, ...props }, forwardedRef) => {
1009
1107
  return /* @__PURE__ */ React4.createElement(ScrollArea.Root, {
1010
1108
  ...composableProps(props, {
1011
- classNames: [
1012
- "py-form-chrome",
1013
- classNames
1014
- ]
1109
+ classNames: styles3.comboboxList({
1110
+ class: classNames
1111
+ })
1015
1112
  }),
1016
1113
  role: "listbox",
1017
1114
  centered: true,
@@ -1021,7 +1118,7 @@ var ComboboxList = /* @__PURE__ */ forwardRef2(({ classNames, children, ...props
1021
1118
  }, /* @__PURE__ */ React4.createElement(ScrollArea.Viewport, null, children));
1022
1119
  });
1023
1120
  ComboboxList.displayName = "Combobox.List";
1024
- var ComboboxItem = /* @__PURE__ */ forwardRef2(({ classNames, onSelect, value, label, icon, iconClassNames, checked, suffix, disabled, closeOnSelect = true, children }, forwardedRef) => {
1121
+ var ComboboxItem = /* @__PURE__ */ forwardRef2(({ classNames, onSelect, value, label, description, icon, iconClassNames, checked, suffix, disabled, closeOnSelect = true, children }, forwardedRef) => {
1025
1122
  const { onValueChange, onOpenChange } = useComboboxContext(COMBOBOX_ITEM_NAME);
1026
1123
  const handleSelect = useCallback6(() => {
1027
1124
  onSelect?.();
@@ -1043,20 +1140,22 @@ var ComboboxItem = /* @__PURE__ */ forwardRef2(({ classNames, onSelect, value, l
1043
1140
  disabled,
1044
1141
  onSelect: handleSelect,
1045
1142
  ref: forwardedRef,
1046
- classNames: [
1047
- // Full width inside the viewport (no horizontal margin).
1048
- // `px-3 py-1`, `cursor-pointer`, `select-none` and the
1049
- // `dx-hover` / `dx-selected` pairing come from `Picker.Item`'s
1050
- // defaults; we only add the row-shape (flex / icons + label)
1051
- // and the disabled overrides on top.
1052
- "flex w-full gap-2 items-center",
1053
- disabled && "hover:bg-transparent data-[selected=true]:bg-transparent",
1054
- classNames
1055
- ]
1143
+ classNames: styles3.comboboxItem({
1144
+ // `px-3 py-1`, `cursor-pointer`, `select-none` and the `dx-hover` / `dx-selected`
1145
+ // pairing come from `Picker.Item`'s defaults; the slot only adds row-shape (flex /
1146
+ // icons + label). Disabled overrides are layered on per-instance.
1147
+ class: mx4(disabled && "hover:bg-transparent data-[selected=true]:bg-transparent", classNames)
1148
+ })
1056
1149
  }, children ?? /* @__PURE__ */ React4.createElement(React4.Fragment, null, icon && /* @__PURE__ */ React4.createElement(Icon2, {
1057
1150
  icon,
1058
1151
  classNames: iconClassNames
1059
- }), /* @__PURE__ */ React4.createElement("span", {
1152
+ }), description ? /* @__PURE__ */ React4.createElement("span", {
1153
+ className: "w-0 grow flex flex-col"
1154
+ }, /* @__PURE__ */ React4.createElement("span", {
1155
+ className: "truncate"
1156
+ }, label), /* @__PURE__ */ React4.createElement("span", {
1157
+ className: styles3.comboboxItemDescription()
1158
+ }, description)) : /* @__PURE__ */ React4.createElement("span", {
1060
1159
  className: "w-0 grow truncate"
1061
1160
  }, label), suffix && /* @__PURE__ */ React4.createElement("span", {
1062
1161
  className: "shrink-0 text-description"
@@ -1088,12 +1187,97 @@ var Combobox = {
1088
1187
  Empty: ComboboxEmpty
1089
1188
  };
1090
1189
 
1190
+ // src/components/DropIndicator/DropIndicator.tsx
1191
+ import React5 from "react";
1192
+ var edgeToOrientationMap = {
1193
+ top: "horizontal",
1194
+ bottom: "horizontal",
1195
+ left: "vertical",
1196
+ right: "vertical"
1197
+ };
1198
+ var orientationStyles = {
1199
+ horizontal: "h-(--line-thickness) left-[calc(var(--line-inset)+var(--terminal-radius))] right-(--line-inset) before:left-(--terminal-inset)",
1200
+ vertical: "w-(--line-thickness) top-[calc(var(--line-inset)+var(--terminal-radius))] bottom-(--line-inset) before:top-(--terminal-inset)"
1201
+ };
1202
+ var edgeStyles = {
1203
+ top: "top-(--line-offset) before:top-(--offset-terminal)",
1204
+ right: "right-(--line-offset) before:right-(--offset-terminal)",
1205
+ bottom: "bottom-(--line-offset) before:bottom-(--offset-terminal)",
1206
+ left: "left-(--line-offset) before:left-(--offset-terminal)"
1207
+ };
1208
+ var strokeSize = 2;
1209
+ var terminalSize = 8;
1210
+ var offsetToAlignTerminalWithLine = (strokeSize - terminalSize) / 2;
1211
+ var DropIndicator = ({ edge, gap = 0, lineInset = 0, terminalInset = lineInset - terminalSize }) => {
1212
+ const orientation = edgeToOrientationMap[edge];
1213
+ return /* @__PURE__ */ React5.createElement("div", {
1214
+ style: {
1215
+ "--line-thickness": `${strokeSize}px`,
1216
+ "--line-offset": `calc(-0.5 * (${gap}px + ${strokeSize}px))`,
1217
+ "--line-inset": `${lineInset}px`,
1218
+ "--terminal-size": `${terminalSize}px`,
1219
+ "--terminal-radius": `${terminalSize / 2}px`,
1220
+ "--terminal-inset": `${terminalInset}px`,
1221
+ "--offset-terminal": `${offsetToAlignTerminalWithLine}px`
1222
+ },
1223
+ className: `absolute z-10 pointer-events-none bg-accent-bg before:content-[''] before:w-(--terminal-size) before:h-(--terminal-size) box-border before:box-border before:absolute before:border-[length:--line-thickness] before:border-solid before:border-accent-bg before:rounded-full ${orientationStyles[orientation]} ${edgeStyles[edge]}`
1224
+ });
1225
+ };
1226
+
1227
+ // src/components/Empty/Empty.tsx
1228
+ import React6 from "react";
1229
+ import { Icon as Icon3, composable as composable2, composableProps as composableProps2, useTranslation } from "@dxos/react-ui";
1230
+ import { osTranslations } from "@dxos/ui-theme";
1231
+ var Empty = composable2(({ label, icon, ...props }, forwardedRef) => {
1232
+ const { t } = useTranslation(osTranslations);
1233
+ const message = label ?? t("empty.label", {
1234
+ defaultValue: "No items"
1235
+ });
1236
+ return /* @__PURE__ */ React6.createElement("div", {
1237
+ ...composableProps2(props, {
1238
+ classNames: "flex flex-col items-center justify-center gap-2 p-4 text-sm text-center text-description",
1239
+ role: "status"
1240
+ }),
1241
+ ref: forwardedRef
1242
+ }, icon && /* @__PURE__ */ React6.createElement(Icon3, {
1243
+ icon,
1244
+ size: 6,
1245
+ classNames: "text-subdued"
1246
+ }), /* @__PURE__ */ React6.createElement("span", null, message));
1247
+ });
1248
+ Empty.displayName = "Empty";
1249
+
1091
1250
  // src/components/Listbox/Listbox.tsx
1092
1251
  import { createContext as createContext5 } from "@radix-ui/react-context";
1093
- import React5, { forwardRef as forwardRef3, useCallback as useCallback7, useMemo as useMemo5 } from "react";
1252
+ import React8, { forwardRef as forwardRef4, useCallback as useCallback7, useMemo as useMemo5 } from "react";
1094
1253
  import { List, ListItem } from "@dxos/react-list";
1095
- import { Icon as Icon3, ScrollArea as ScrollArea2, composable as composable2, composableProps as composableProps2 } from "@dxos/react-ui";
1254
+ import { Icon as Icon5, ScrollArea as ScrollArea2, composable as composable3, composableProps as composableProps3 } from "@dxos/react-ui";
1255
+ import { mx as mx6 } from "@dxos/ui-theme";
1256
+
1257
+ // src/components/Listbox/ListItemContent.tsx
1258
+ import React7, { forwardRef as forwardRef3 } from "react";
1259
+ import { Icon as Icon4 } from "@dxos/react-ui";
1096
1260
  import { mx as mx5 } from "@dxos/ui-theme";
1261
+ var styles4 = listTheme.styles();
1262
+ var ListItemContent = /* @__PURE__ */ forwardRef3(({ classNames, icon, title, description }, forwardedRef) => /* @__PURE__ */ React7.createElement("div", {
1263
+ ref: forwardedRef,
1264
+ className: styles4.itemContentRoot({
1265
+ class: mx5(classNames)
1266
+ })
1267
+ }, icon != null && /* @__PURE__ */ React7.createElement("div", {
1268
+ className: styles4.itemContentIcon()
1269
+ }, typeof icon === "string" ? /* @__PURE__ */ React7.createElement(Icon4, {
1270
+ icon,
1271
+ size: 5
1272
+ }) : icon), /* @__PURE__ */ React7.createElement("span", {
1273
+ className: styles4.itemContentTitle()
1274
+ }, title), description != null && /* @__PURE__ */ React7.createElement("span", {
1275
+ className: styles4.itemContentDescription()
1276
+ }, description)));
1277
+ ListItemContent.displayName = "ItemContent";
1278
+
1279
+ // src/components/Listbox/Listbox.tsx
1280
+ var styles5 = listTheme.styles();
1097
1281
  var LISTBOX_NAME = "Listbox";
1098
1282
  var LISTBOX_ROOT_NAME = "Listbox.Root";
1099
1283
  var LISTBOX_VIEWPORT_NAME = "Listbox.Viewport";
@@ -1104,6 +1288,7 @@ var LISTBOX_INDICATOR_NAME = "Listbox.Indicator";
1104
1288
  var [ListboxProvider, useListboxContext] = createContext5(LISTBOX_NAME);
1105
1289
  var [ListboxItemProvider, useListboxItemContext] = createContext5(LISTBOX_ITEM_NAME);
1106
1290
  var Root2 = ({ value, defaultValue, onValueChange, autoFocus: _autoFocus, children }) => {
1291
+ const selectable = value !== void 0 || defaultValue !== void 0 || onValueChange !== void 0;
1107
1292
  const selection = useListSelection({
1108
1293
  mode: "single",
1109
1294
  value,
@@ -1115,37 +1300,39 @@ var Root2 = ({ value, defaultValue, onValueChange, autoFocus: _autoFocus, childr
1115
1300
  }
1116
1301
  });
1117
1302
  const context = useMemo5(() => ({
1303
+ selectable,
1118
1304
  selection
1119
1305
  }), [
1306
+ selectable,
1120
1307
  selection
1121
1308
  ]);
1122
- return /* @__PURE__ */ React5.createElement(ListboxProvider, context, children);
1309
+ return /* @__PURE__ */ React8.createElement(ListboxProvider, context, children);
1123
1310
  };
1124
1311
  Root2.displayName = LISTBOX_ROOT_NAME;
1125
- var Viewport = composable2((props, forwardedRef) => {
1312
+ var Viewport = composable3((props, forwardedRef) => {
1126
1313
  const { thin, padding, centered, children, ...rest } = props;
1127
- return /* @__PURE__ */ React5.createElement(ScrollArea2.Root, {
1128
- ...composableProps2(rest, {
1129
- classNames: "dx-container"
1314
+ return /* @__PURE__ */ React8.createElement(ScrollArea2.Root, {
1315
+ ...composableProps3(rest, {
1316
+ classNames: styles5.listboxViewport()
1130
1317
  }),
1131
1318
  thin,
1132
1319
  padding,
1133
1320
  centered,
1134
1321
  orientation: "vertical",
1135
1322
  ref: forwardedRef
1136
- }, /* @__PURE__ */ React5.createElement(ScrollArea2.Viewport, null, children));
1323
+ }, /* @__PURE__ */ React8.createElement(ScrollArea2.Viewport, null, children));
1137
1324
  });
1138
1325
  Viewport.displayName = LISTBOX_VIEWPORT_NAME;
1139
- var Content2 = composable2((props, forwardedRef) => {
1140
- useListboxContext(LISTBOX_CONTENT_NAME);
1326
+ var Content2 = composable3((props, forwardedRef) => {
1327
+ const { selectable } = useListboxContext(LISTBOX_CONTENT_NAME);
1141
1328
  const navigation = useListNavigation({
1142
- mode: "listbox"
1329
+ mode: selectable ? "listbox" : "list"
1143
1330
  });
1144
1331
  const { children, ...rest } = props;
1145
- const composed = composableProps2(rest, {
1146
- classNames: "flex flex-col"
1332
+ const composed = composableProps3(rest, {
1333
+ classNames: styles5.listboxContent()
1147
1334
  });
1148
- return /* @__PURE__ */ React5.createElement(List, {
1335
+ return /* @__PURE__ */ React8.createElement(List, {
1149
1336
  variant: "unordered",
1150
1337
  ...composed,
1151
1338
  ...navigation.containerProps,
@@ -1153,67 +1340,79 @@ var Content2 = composable2((props, forwardedRef) => {
1153
1340
  }, children);
1154
1341
  });
1155
1342
  Content2.displayName = LISTBOX_CONTENT_NAME;
1156
- var ITEM_BASE = "flex items-center dx-hover dx-selected px-3 py-2 cursor-pointer outline-none";
1157
- var Item2 = composable2((props, forwardedRef) => {
1158
- const { id, disabled, onClick, onFocus, children, ...rest } = props;
1159
- const { selection } = useListboxContext(LISTBOX_ITEM_NAME);
1343
+ var Item2 = composable3((props, forwardedRef) => {
1344
+ const { id, disabled, onClick, onFocus, onMouseDown, children, ...rest } = props;
1345
+ const { selectable, selection } = useListboxContext(LISTBOX_ITEM_NAME);
1160
1346
  const binding = selection.bind(id, {
1161
1347
  disabled
1162
1348
  });
1349
+ const selected = selectable && binding.selected;
1350
+ const interactive = selectable || onClick != null;
1163
1351
  const handleClick = useCallback7((event) => {
1164
- binding.rowProps.onClick(event);
1352
+ if (selectable) {
1353
+ binding.rowProps.onClick(event);
1354
+ }
1165
1355
  if (!disabled) {
1166
1356
  onClick?.(event);
1167
1357
  }
1168
1358
  }, [
1359
+ selectable,
1169
1360
  binding,
1170
1361
  disabled,
1171
1362
  onClick
1172
1363
  ]);
1173
1364
  const handleFocus = useCallback7((event) => {
1174
- binding.rowProps.onFocus?.(event);
1365
+ if (selectable) {
1366
+ binding.rowProps.onFocus?.(event);
1367
+ }
1175
1368
  onFocus?.(event);
1176
1369
  }, [
1370
+ selectable,
1177
1371
  binding,
1178
1372
  onFocus
1179
1373
  ]);
1180
- const composed = composableProps2(rest, {
1181
- classNames: [
1182
- ITEM_BASE,
1183
- disabled && "opacity-50 cursor-not-allowed"
1184
- ]
1374
+ const composed = composableProps3(rest, {
1375
+ classNames: styles5.listboxItem({
1376
+ class: [
1377
+ !interactive && "cursor-default",
1378
+ disabled && "opacity-50 cursor-not-allowed"
1379
+ ]
1380
+ })
1185
1381
  });
1186
- return /* @__PURE__ */ React5.createElement(ListItemProviderHost, {
1382
+ return /* @__PURE__ */ React8.createElement(ListItemProviderHost, {
1187
1383
  id,
1188
- selected: binding.selected
1189
- }, /* @__PURE__ */ React5.createElement(ListItem, {
1384
+ selected
1385
+ }, /* @__PURE__ */ React8.createElement(ListItem, {
1190
1386
  ...composed,
1191
- role: "option",
1192
- tabIndex: 0,
1193
- "aria-selected": binding.selected,
1387
+ role: selectable ? "option" : "listitem",
1388
+ tabIndex: selectable ? 0 : -1,
1389
+ "aria-selected": selectable ? selected : void 0,
1194
1390
  "aria-disabled": disabled || void 0,
1195
1391
  onClick: handleClick,
1196
1392
  onFocus: handleFocus,
1393
+ onMouseDown,
1197
1394
  ref: forwardedRef
1198
1395
  }, children));
1199
1396
  });
1200
1397
  Item2.displayName = LISTBOX_ITEM_NAME;
1201
- var ListItemProviderHost = ({ id, selected, children }) => /* @__PURE__ */ React5.createElement(ListboxItemProvider, {
1398
+ var ListItemProviderHost = ({ id, selected, children }) => /* @__PURE__ */ React8.createElement(ListboxItemProvider, {
1202
1399
  id,
1203
1400
  selected
1204
1401
  }, children);
1205
- var ItemLabel = /* @__PURE__ */ forwardRef3(({ classNames, children, ...rest }, forwardedRef) => /* @__PURE__ */ React5.createElement("span", {
1402
+ var ItemLabel = /* @__PURE__ */ forwardRef4(({ classNames, children, ...rest }, forwardedRef) => /* @__PURE__ */ React8.createElement("span", {
1206
1403
  ...rest,
1207
- className: mx5("grow truncate", classNames),
1404
+ className: styles5.listboxItemLabel({
1405
+ class: mx6(classNames)
1406
+ }),
1208
1407
  ref: forwardedRef
1209
1408
  }, children));
1210
1409
  ItemLabel.displayName = LISTBOX_ITEM_LABEL_NAME;
1211
- var Indicator = /* @__PURE__ */ forwardRef3(({ classNames, ...rootProps }, forwardedRef) => {
1410
+ var Indicator = /* @__PURE__ */ forwardRef4(({ classNames, ...rootProps }, forwardedRef) => {
1212
1411
  const { selected } = useListboxItemContext(LISTBOX_INDICATOR_NAME);
1213
- return /* @__PURE__ */ React5.createElement(Icon3, {
1412
+ return /* @__PURE__ */ React8.createElement(Icon5, {
1214
1413
  icon: "ph--check--regular",
1215
1414
  ...rootProps,
1216
- classNames: mx5(!selected && "invisible", classNames),
1415
+ classNames: mx6(!selected && "invisible", classNames),
1217
1416
  ref: forwardedRef
1218
1417
  });
1219
1418
  });
@@ -1228,20 +1427,22 @@ var Listbox = {
1228
1427
  Content: Content2,
1229
1428
  Item: Item2,
1230
1429
  ItemLabel,
1430
+ ItemContent: ListItemContent,
1231
1431
  Indicator
1232
1432
  };
1233
1433
 
1234
1434
  // src/components/OrderedList/OrderedListItem.tsx
1235
1435
  import { createContext as createContext7 } from "@radix-ui/react-context";
1236
- import React7, { useCallback as useCallback8 } from "react";
1237
- import { IconBlock, IconButton, ListItem as NaturalListItem, ToggleIconButton, useTranslation } from "@dxos/react-ui";
1238
- import { mx as mx7, osTranslations } from "@dxos/ui-theme";
1436
+ import React10, { useCallback as useCallback8 } from "react";
1437
+ import { IconBlock, IconButton, ToggleIconButton, useTranslation as useTranslation2 } from "@dxos/react-ui";
1438
+ import { mx as mx8, osTranslations as osTranslations2 } from "@dxos/ui-theme";
1239
1439
 
1240
1440
  // src/components/OrderedList/OrderedListRoot.tsx
1241
1441
  import { createContext as createContext6 } from "@radix-ui/react-context";
1242
- import React6, { useMemo as useMemo6 } from "react";
1243
- import { ScrollArea as ScrollArea3, composable as composable3, composableProps as composableProps3 } from "@dxos/react-ui";
1244
- import { mx as mx6 } from "@dxos/ui-theme";
1442
+ import React9, { useMemo as useMemo6 } from "react";
1443
+ import { ScrollArea as ScrollArea3, composable as composable4, composableProps as composableProps4 } from "@dxos/react-ui";
1444
+ import { mx as mx7 } from "@dxos/ui-theme";
1445
+ var styles6 = listTheme.styles();
1245
1446
  var ORDERED_LIST_NAME = "OrderedList";
1246
1447
  var [OrderedListProvider, useOrderedListContext] = createContext6(ORDERED_LIST_NAME);
1247
1448
  var defaultGetId2 = (item) => item?.id;
@@ -1278,43 +1479,46 @@ var OrderedListRoot = ({ items, getId = defaultGetId2, onMove = noopMove, readon
1278
1479
  active,
1279
1480
  getId
1280
1481
  ]);
1281
- return /* @__PURE__ */ React6.createElement(OrderedListProvider, context, children({
1482
+ return /* @__PURE__ */ React9.createElement(OrderedListProvider, context, children({
1282
1483
  items
1283
1484
  }));
1284
1485
  };
1285
1486
  var OrderedListContent = ({ classNames, children }) => {
1286
1487
  const { navigation } = useOrderedListContext("OrderedList.Content");
1287
- return /* @__PURE__ */ React6.createElement("div", {
1488
+ return /* @__PURE__ */ React9.createElement("div", {
1288
1489
  ...navigation.containerProps,
1289
- className: mx6("flex flex-col", classNames)
1490
+ className: styles6.orderedListContent({
1491
+ class: mx7(classNames)
1492
+ })
1290
1493
  }, children);
1291
1494
  };
1292
- var OrderedListViewport = composable3((props, forwardedRef) => {
1495
+ var OrderedListViewport = composable4((props, forwardedRef) => {
1293
1496
  const { thin, padding, centered, children, ...rest } = props;
1294
1497
  const autoScrollRef = useReorderAutoScroll();
1295
- return /* @__PURE__ */ React6.createElement(ScrollArea3.Root, {
1296
- ...composableProps3(rest, {
1297
- classNames: "dx-container"
1498
+ return /* @__PURE__ */ React9.createElement(ScrollArea3.Root, {
1499
+ ...composableProps4(rest, {
1500
+ classNames: styles6.orderedListViewport()
1298
1501
  }),
1299
1502
  thin,
1300
1503
  padding,
1301
1504
  centered,
1302
1505
  orientation: "vertical",
1303
1506
  ref: forwardedRef
1304
- }, /* @__PURE__ */ React6.createElement(ScrollArea3.Viewport, {
1507
+ }, /* @__PURE__ */ React9.createElement(ScrollArea3.Viewport, {
1305
1508
  ref: autoScrollRef
1306
1509
  }, children));
1307
1510
  });
1308
1511
  OrderedListViewport.displayName = "OrderedList.Viewport";
1309
1512
 
1310
1513
  // src/components/OrderedList/OrderedListItem.tsx
1514
+ var styles7 = listTheme.styles();
1311
1515
  var ORDERED_LIST_ITEM_NAME = "OrderedListItem";
1312
1516
  var [OrderedListItemProvider, useOrderedListItemContext] = createContext7(ORDERED_LIST_ITEM_NAME);
1313
1517
  var OrderedListItem = ({ id, canDrag = true, hover = false, selected, onClick, classNames, style, children }) => {
1314
1518
  const { reorder, disclosure, navigation } = useOrderedListContext(ORDERED_LIST_ITEM_NAME);
1315
1519
  const { rowRef, handleRef, closestEdge, state } = useReorderItem(reorder, id);
1316
1520
  const { expanded, toggle, triggerProps, panelProps } = disclosure.bind(id);
1317
- return /* @__PURE__ */ React7.createElement(OrderedListItemProvider, {
1521
+ return /* @__PURE__ */ React10.createElement(OrderedListItemProvider, {
1318
1522
  id,
1319
1523
  expanded,
1320
1524
  toggle,
@@ -1322,23 +1526,25 @@ var OrderedListItem = ({ id, canDrag = true, hover = false, selected, onClick, c
1322
1526
  handleRef,
1323
1527
  triggerProps,
1324
1528
  panelProps
1325
- }, /* @__PURE__ */ React7.createElement("div", {
1529
+ }, /* @__PURE__ */ React10.createElement("div", {
1326
1530
  ref: rowRef,
1327
1531
  ...navigation.itemProps(),
1328
1532
  style,
1329
1533
  "aria-current": selected || void 0,
1330
1534
  onClick,
1331
- className: mx7("relative dx-current", hover && "dx-hover", state.type === "dragging" && "opacity-50", classNames)
1332
- }, children, closestEdge && /* @__PURE__ */ React7.createElement(NaturalListItem.DropIndicator, {
1535
+ className: styles7.orderedListItem({
1536
+ class: mx8(hover && "dx-hover", state.type === "dragging" && "opacity-50", classNames)
1537
+ })
1538
+ }, children, closestEdge && /* @__PURE__ */ React10.createElement(DropIndicator, {
1333
1539
  edge: closestEdge
1334
1540
  })));
1335
1541
  };
1336
1542
  var OrderedListDragHandle = () => {
1337
1543
  const { readonly } = useOrderedListContext("OrderedListDragHandle");
1338
1544
  const { canDrag, handleRef } = useOrderedListItemContext("OrderedListDragHandle");
1339
- const { t } = useTranslation(osTranslations);
1545
+ const { t } = useTranslation2(osTranslations2);
1340
1546
  const disabled = readonly || !canDrag;
1341
- return /* @__PURE__ */ React7.createElement(IconButton, {
1547
+ return /* @__PURE__ */ React10.createElement(IconButton, {
1342
1548
  variant: "ghost",
1343
1549
  disabled,
1344
1550
  noTooltip: true,
@@ -1357,18 +1563,20 @@ var OrderedListTitle = ({ classNames, children, onClick, ...props }) => {
1357
1563
  onClick,
1358
1564
  triggerProps
1359
1565
  ]);
1360
- return /* @__PURE__ */ React7.createElement("div", {
1566
+ return /* @__PURE__ */ React10.createElement("div", {
1361
1567
  ...props,
1362
1568
  // The title row is also the disclosure trigger, so it carries the trigger's
1363
1569
  // `id` + `aria-expanded` + `aria-controls` for assistive tech.
1364
1570
  id: triggerProps.id,
1365
1571
  "aria-expanded": triggerProps["aria-expanded"],
1366
1572
  "aria-controls": triggerProps["aria-controls"],
1367
- className: mx7("flex grow items-center truncate cursor-pointer", classNames),
1573
+ className: styles7.orderedListTitle({
1574
+ class: mx8(classNames)
1575
+ }),
1368
1576
  onClick: handleClick
1369
1577
  }, children);
1370
1578
  };
1371
- var OrderedListIconButton = ({ autoHide = false, disabled, classNames, ...props }) => /* @__PURE__ */ React7.createElement(IconBlock, null, /* @__PURE__ */ React7.createElement(IconButton, {
1579
+ var OrderedListIconButton = ({ autoHide = false, disabled, classNames, ...props }) => /* @__PURE__ */ React10.createElement(IconBlock, null, /* @__PURE__ */ React10.createElement(IconButton, {
1372
1580
  ...props,
1373
1581
  variant: "ghost",
1374
1582
  iconOnly: true,
@@ -1379,8 +1587,8 @@ var OrderedListIconButton = ({ autoHide = false, disabled, classNames, ...props
1379
1587
  ]
1380
1588
  }));
1381
1589
  var OrderedListDeleteButton = ({ autoHide = false, icon = "ph--x--regular", label, disabled, classNames, ...props }) => {
1382
- const { t } = useTranslation(osTranslations);
1383
- return /* @__PURE__ */ React7.createElement(OrderedListIconButton, {
1590
+ const { t } = useTranslation2(osTranslations2);
1591
+ return /* @__PURE__ */ React10.createElement(OrderedListIconButton, {
1384
1592
  ...props,
1385
1593
  autoHide,
1386
1594
  disabled,
@@ -1390,7 +1598,7 @@ var OrderedListDeleteButton = ({ autoHide = false, icon = "ph--x--regular", labe
1390
1598
  });
1391
1599
  };
1392
1600
  var OrderedListExpandCaret = ({ onClick, ...props }) => {
1393
- const { t } = useTranslation(osTranslations);
1601
+ const { t } = useTranslation2(osTranslations2);
1394
1602
  const { expanded, toggle, triggerProps } = useOrderedListItemContext("OrderedListExpandCaret");
1395
1603
  const handleClick = useCallback8((event) => {
1396
1604
  toggle();
@@ -1399,7 +1607,7 @@ var OrderedListExpandCaret = ({ onClick, ...props }) => {
1399
1607
  toggle,
1400
1608
  onClick
1401
1609
  ]);
1402
- return /* @__PURE__ */ React7.createElement(ToggleIconButton, {
1610
+ return /* @__PURE__ */ React10.createElement(ToggleIconButton, {
1403
1611
  iconOnly: true,
1404
1612
  variant: "ghost",
1405
1613
  active: expanded,
@@ -1417,7 +1625,7 @@ var OrderedListDetailItem = ({ id, item, canDrag, title, titleClassNames, action
1417
1625
  const grid = useListGrid({
1418
1626
  trailing: !!trailing
1419
1627
  });
1420
- return /* @__PURE__ */ React7.createElement(OrderedListItem, {
1628
+ return /* @__PURE__ */ React10.createElement(OrderedListItem, {
1421
1629
  id,
1422
1630
  item,
1423
1631
  canDrag,
@@ -1425,30 +1633,32 @@ var OrderedListDetailItem = ({ id, item, canDrag, title, titleClassNames, action
1425
1633
  // land in fixed-width tracks that share a baseline with the title row inside the card.
1426
1634
  // See useListGrid for the rationale.
1427
1635
  style: grid.rowProps.style,
1428
- classNames: mx7(grid.rowProps.className, "pb-1", classNames)
1429
- }, /* @__PURE__ */ React7.createElement(OrderedListDragHandle, null), /* @__PURE__ */ React7.createElement("div", {
1430
- className: "flex flex-col ring-1 ring-subdued-separator rounded-sm overflow-hidden"
1431
- }, /* @__PURE__ */ React7.createElement("div", {
1432
- className: "flex items-center min-h-[var(--dx-rail-item)]"
1433
- }, expandable ? /* @__PURE__ */ React7.createElement(OrderedListTitle, {
1434
- classNames: mx7("px-2", titleClassNames)
1636
+ classNames: mx8(grid.rowProps.className, "pb-1", classNames)
1637
+ }, /* @__PURE__ */ React10.createElement(OrderedListDragHandle, null), /* @__PURE__ */ React10.createElement("div", {
1638
+ className: styles7.orderedListDetailColumn()
1639
+ }, /* @__PURE__ */ React10.createElement("div", {
1640
+ className: styles7.orderedListDetailTitleRow()
1641
+ }, expandable ? /* @__PURE__ */ React10.createElement(OrderedListTitle, {
1642
+ classNames: mx8("px-2", titleClassNames)
1435
1643
  }, title) : (
1436
1644
  // When the row is not expandable, render a plain (non-toggling) title so a click
1437
1645
  // doesn't mutate hidden disclosure state. Mirrors `OrderedListTitle`'s structure
1438
1646
  // minus the trigger plumbing.
1439
- /* @__PURE__ */ React7.createElement("div", {
1440
- className: mx7("flex grow items-center truncate px-2", titleClassNames)
1647
+ /* @__PURE__ */ React10.createElement("div", {
1648
+ className: styles7.orderedListTitle({
1649
+ class: mx8("cursor-auto px-2", titleClassNames)
1650
+ })
1441
1651
  }, title)
1442
- ), actions, expandable && /* @__PURE__ */ React7.createElement(OrderedListExpandCaret, null)), expandable && /* @__PURE__ */ React7.createElement(DetailPanel, null, children)), trailing);
1652
+ ), actions, expandable && /* @__PURE__ */ React10.createElement(OrderedListExpandCaret, null)), expandable && /* @__PURE__ */ React10.createElement(DetailPanel, null, children)), trailing);
1443
1653
  };
1444
1654
  var DetailPanel = ({ children }) => {
1445
1655
  const { expanded, panelProps } = useOrderedListItemContext("OrderedListDetailItem.Panel");
1446
1656
  if (!expanded || !children) {
1447
1657
  return null;
1448
1658
  }
1449
- return /* @__PURE__ */ React7.createElement("div", {
1659
+ return /* @__PURE__ */ React10.createElement("div", {
1450
1660
  ...panelProps,
1451
- className: "px-2 pb-2"
1661
+ className: styles7.orderedListDetailPanel()
1452
1662
  }, children);
1453
1663
  };
1454
1664
 
@@ -1468,8 +1678,180 @@ var OrderedList = {
1468
1678
 
1469
1679
  // src/components/Tree/Tree.tsx
1470
1680
  import { useAtomValue as useAtomValue2 } from "@effect-atom/atom-react";
1471
- import React11, { useMemo as useMemo8 } from "react";
1472
- import { Treegrid as Treegrid2 } from "@dxos/react-ui";
1681
+ import React16, { useMemo as useMemo8 } from "react";
1682
+
1683
+ // src/components/Treegrid/Treegrid.tsx
1684
+ import { useFocusFinders } from "@fluentui/react-tabster";
1685
+ import { createContextScope } from "@radix-ui/react-context";
1686
+ import { Primitive } from "@radix-ui/react-primitive";
1687
+ import { Slot as Slot2 } from "@radix-ui/react-slot";
1688
+ import { useControllableState as useControllableState2 } from "@radix-ui/react-use-controllable-state";
1689
+ import React11, { forwardRef as forwardRef5, useCallback as useCallback9 } from "react";
1690
+ import { composable as composable5, composableProps as composableProps5 } from "@dxos/react-ui";
1691
+ import { mx as mx9 } from "@dxos/ui-theme";
1692
+
1693
+ // src/components/Treegrid/Treegrid.theme.ts
1694
+ import { tv as tv2 } from "@dxos/ui-theme";
1695
+ var levelStyles = /* @__PURE__ */ new Map([
1696
+ [
1697
+ 1,
1698
+ "[&>.indent:first-of-type]:pl-0 font-medium"
1699
+ ],
1700
+ [
1701
+ 2,
1702
+ "[&>.indent:first-of-type]:pl-0"
1703
+ ],
1704
+ [
1705
+ 3,
1706
+ "[&>.indent:first-of-type]:pl-1"
1707
+ ],
1708
+ [
1709
+ 4,
1710
+ "[&>.indent:first-of-type]:pl-2"
1711
+ ],
1712
+ [
1713
+ 5,
1714
+ "[&>.indent:first-of-type]:pl-3"
1715
+ ],
1716
+ [
1717
+ 6,
1718
+ "[&>.indent:first-of-type]:pl-4"
1719
+ ],
1720
+ [
1721
+ 7,
1722
+ "[&>.indent:first-of-type]:pl-5"
1723
+ ],
1724
+ [
1725
+ 8,
1726
+ "[&>.indent:first-of-type]:pl-6"
1727
+ ]
1728
+ ]);
1729
+ var treegridStyles = tv2({
1730
+ slots: {
1731
+ root: "grid",
1732
+ row: "",
1733
+ cell: ""
1734
+ },
1735
+ variants: {
1736
+ // `indent` marks the cell that carries the per-level left padding (selected via `.indent`).
1737
+ indent: {
1738
+ true: {
1739
+ cell: "indent"
1740
+ }
1741
+ }
1742
+ }
1743
+ });
1744
+ var treegridTheme = {
1745
+ styles: treegridStyles,
1746
+ /** Row class for a 1-based depth level (clamped to 1–8). */
1747
+ rowLevel: (level) => levelStyles.get(Math.min(Math.max(Math.round(level), 1), 8)) ?? ""
1748
+ };
1749
+
1750
+ // src/components/Treegrid/Treegrid.tsx
1751
+ var styles8 = treegridTheme.styles();
1752
+ var TREEGRID_ROW_NAME = "Treegrid.Row";
1753
+ var [createTreegridRowContext, createTreegridRowScope] = createContextScope(TREEGRID_ROW_NAME, []);
1754
+ var [TreegridRowProvider, useTreegridRowContext] = createTreegridRowContext(TREEGRID_ROW_NAME);
1755
+ var TREEGRID_PATH_SEPARATOR = "~";
1756
+ var TREEGRID_PARENT_OF_SEPARATOR = " ";
1757
+ var TreegridRoot = composable5(({ asChild, classNames, children, style, gridTemplateColumns, onKeyDown: onKeyDownProp, ...props }, forwardedRef) => {
1758
+ const { className, role: _role, ...rest } = composableProps5(props, {
1759
+ classNames
1760
+ });
1761
+ const Comp = asChild ? Slot2 : Primitive.div;
1762
+ const { findFirstFocusable } = useFocusFinders();
1763
+ const handleKeyDown = useCallback9((event) => {
1764
+ switch (event.key) {
1765
+ case "ArrowDown":
1766
+ case "ArrowUp": {
1767
+ const direction = event.key === "ArrowDown" ? "down" : "up";
1768
+ const target = event.target;
1769
+ const ancestorWithArrowKeys = target.closest(`[data-arrow-keys*="${direction}"], [data-arrow-keys="all"]`);
1770
+ if (!ancestorWithArrowKeys) {
1771
+ const currentRow = target.closest('[role="row"]');
1772
+ if (currentRow) {
1773
+ const treegrid = currentRow.closest('[role="treegrid"]');
1774
+ if (treegrid) {
1775
+ const rows = Array.from(treegrid.querySelectorAll('[role="row"]'));
1776
+ const currentIndex = rows.indexOf(currentRow);
1777
+ const nextIndex = direction === "down" ? currentIndex + 1 : currentIndex - 1;
1778
+ const targetRow = rows[nextIndex];
1779
+ if (targetRow) {
1780
+ const firstFocusable = findFirstFocusable(targetRow);
1781
+ if (firstFocusable) {
1782
+ event.preventDefault();
1783
+ firstFocusable.focus();
1784
+ }
1785
+ }
1786
+ }
1787
+ }
1788
+ }
1789
+ break;
1790
+ }
1791
+ }
1792
+ onKeyDownProp?.(event);
1793
+ }, [
1794
+ findFirstFocusable,
1795
+ onKeyDownProp
1796
+ ]);
1797
+ return /* @__PURE__ */ React11.createElement(Comp, {
1798
+ role: "treegrid",
1799
+ ...rest,
1800
+ className: styles8.root({
1801
+ class: mx9(className)
1802
+ }),
1803
+ style: {
1804
+ ...style,
1805
+ gridTemplateColumns
1806
+ },
1807
+ onKeyDown: handleKeyDown,
1808
+ ref: forwardedRef
1809
+ }, children);
1810
+ });
1811
+ var TreegridRow = /* @__PURE__ */ forwardRef5(({ __treegridRowScope, asChild, classNames, children, id, parentOf, open: propsOpen, defaultOpen, onOpenChange: propsOnOpenChange, ...props }, forwardedRef) => {
1812
+ const Comp = asChild ? Slot2 : Primitive.div;
1813
+ const pathParts = id.split(TREEGRID_PATH_SEPARATOR);
1814
+ const level = pathParts.length - 1;
1815
+ const [open, onOpenChange] = useControllableState2({
1816
+ prop: propsOpen,
1817
+ onChange: propsOnOpenChange,
1818
+ defaultProp: defaultOpen
1819
+ });
1820
+ return /* @__PURE__ */ React11.createElement(TreegridRowProvider, {
1821
+ open,
1822
+ onOpenChange,
1823
+ scope: __treegridRowScope
1824
+ }, /* @__PURE__ */ React11.createElement(Comp, {
1825
+ role: "row",
1826
+ "aria-level": level,
1827
+ className: styles8.row({
1828
+ class: mx9(treegridTheme.rowLevel(level), classNames)
1829
+ }),
1830
+ ...parentOf && {
1831
+ "aria-expanded": open,
1832
+ "aria-owns": parentOf
1833
+ },
1834
+ ...props,
1835
+ id,
1836
+ ref: forwardedRef
1837
+ }, children));
1838
+ });
1839
+ var TreegridCell = /* @__PURE__ */ forwardRef5(({ classNames, children, indent, ...props }, forwardedRef) => {
1840
+ return /* @__PURE__ */ React11.createElement("div", {
1841
+ role: "gridcell",
1842
+ className: styles8.cell({
1843
+ indent,
1844
+ class: mx9(classNames)
1845
+ }),
1846
+ ...props,
1847
+ ref: forwardedRef
1848
+ }, children);
1849
+ });
1850
+ var Treegrid = {
1851
+ Root: TreegridRoot,
1852
+ Row: TreegridRow,
1853
+ Cell: TreegridCell
1854
+ };
1473
1855
 
1474
1856
  // src/components/Tree/TreeContext.tsx
1475
1857
  import { createContext as createContext8, useContext } from "react";
@@ -1484,10 +1866,10 @@ import { combine as combine2 } from "@atlaskit/pragmatic-drag-and-drop/combine";
1484
1866
  import { draggable as draggable2, dropTargetForElements as dropTargetForElements2 } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
1485
1867
  import { useAtomValue } from "@effect-atom/atom-react";
1486
1868
  import * as Schema from "effect/Schema";
1487
- import React10, { memo as memo3, useCallback as useCallback10, useEffect as useEffect5, useMemo as useMemo7, useRef as useRef5, useState as useState5 } from "react";
1869
+ import React15, { memo as memo3, useCallback as useCallback11, useEffect as useEffect5, useMemo as useMemo7, useRef as useRef5, useState as useState5 } from "react";
1488
1870
  import { invariant } from "@dxos/invariant";
1489
- import { TreeItem as NaturalTreeItem, Treegrid, TREEGRID_PARENT_OF_SEPARATOR } from "@dxos/react-ui";
1490
- import { ghostFocusWithin, ghostHover, hoverableControls, hoverableFocusedKeyboardControls, hoverableFocusedWithinControls, mx as mx8 } from "@dxos/ui-theme";
1871
+ import { toLocalizedString as toLocalizedString2, useTranslation as useTranslation4 } from "@dxos/react-ui";
1872
+ import { ghostFocusWithin, ghostHover, hoverableControls, hoverableFocusedKeyboardControls, hoverableFocusedWithinControls, mx as mx10 } from "@dxos/ui-theme";
1491
1873
 
1492
1874
  // src/components/Tree/helpers.ts
1493
1875
  var DEFAULT_INDENTATION = 8;
@@ -1495,19 +1877,62 @@ var paddingIndentation = (level, indentation = DEFAULT_INDENTATION) => ({
1495
1877
  paddingInlineStart: `${(level - 1) * indentation}px`
1496
1878
  });
1497
1879
 
1880
+ // src/components/Tree/TreeDropIndicator.tsx
1881
+ import React12 from "react";
1882
+ var edgeToOrientationMap2 = {
1883
+ "reorder-above": "sibling",
1884
+ "reorder-below": "sibling",
1885
+ "make-child": "child",
1886
+ "reparent": "child"
1887
+ };
1888
+ var orientationStyles2 = {
1889
+ sibling: "h-(--line-thickness) left-(--horizontal-indent) right-0 bg-accent-bg before:left-(--negative-terminal-size)",
1890
+ child: "inset-0 border-[length:var(--line-thickness)] before:invisible"
1891
+ };
1892
+ var instructionStyles = {
1893
+ "reorder-above": "top-(--line-offset) before:top-(--offset-terminal)",
1894
+ "reorder-below": "bottom-(--line-offset) before:bottom-(--offset-terminal)",
1895
+ "make-child": "border-accent-bg",
1896
+ "reparent": ""
1897
+ };
1898
+ var strokeSize2 = 2;
1899
+ var terminalSize2 = 8;
1900
+ var offsetToAlignTerminalWithLine2 = (strokeSize2 - terminalSize2) / 2;
1901
+ var TreeDropIndicator = ({ instruction, gap = 0 }) => {
1902
+ const lineOffset = `calc(-0.5 * (${gap}px + ${strokeSize2}px))`;
1903
+ const isBlocked = instruction.type === "instruction-blocked";
1904
+ const desiredInstruction = isBlocked ? instruction.desired : instruction;
1905
+ const orientation = edgeToOrientationMap2[desiredInstruction.type];
1906
+ if (isBlocked) {
1907
+ return null;
1908
+ }
1909
+ return /* @__PURE__ */ React12.createElement("div", {
1910
+ style: {
1911
+ "--line-thickness": `${strokeSize2}px`,
1912
+ "--line-offset": `${lineOffset}`,
1913
+ "--terminal-size": `${terminalSize2}px`,
1914
+ "--terminal-radius": `${terminalSize2 / 2}px`,
1915
+ "--negative-terminal-size": `-${terminalSize2}px`,
1916
+ "--offset-terminal": `${offsetToAlignTerminalWithLine2}px`,
1917
+ "--horizontal-indent": `${desiredInstruction.currentLevel * desiredInstruction.indentPerLevel + 4}px`
1918
+ },
1919
+ className: `absolute z-10 pointer-events-none before:w-(--terminal-size) before:h-(--terminal-size) box-border before:absolute before:border-[length:--line-thickness] before:border-solid before:border-accent-bg before:rounded-full ${orientationStyles2[orientation]} ${instructionStyles[desiredInstruction.type]}`
1920
+ });
1921
+ };
1922
+
1498
1923
  // src/components/Tree/TreeItemHeading.tsx
1499
- import React8, { forwardRef as forwardRef4, memo, useCallback as useCallback9 } from "react";
1500
- import { Button as Button2, Icon as Icon4, Tag, TextTooltip, toLocalizedString, useTranslation as useTranslation2 } from "@dxos/react-ui";
1924
+ import React13, { forwardRef as forwardRef6, memo, useCallback as useCallback10 } from "react";
1925
+ import { Button as Button2, Icon as Icon6, Tag, TextTooltip, toLocalizedString, useTranslation as useTranslation3 } from "@dxos/react-ui";
1501
1926
  import { getStyles } from "@dxos/ui-theme";
1502
- var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef4(({ label, className, icon, iconHue, disabled, current, count, modifiedCount, onSelect }, forwardedRef) => {
1503
- const { t } = useTranslation2();
1504
- const styles = iconHue ? getStyles(iconHue) : void 0;
1505
- const handleSelect = useCallback9((event) => {
1927
+ var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef6(({ label, className, icon, iconHue, disabled, current, count, modifiedCount, onSelect }, forwardedRef) => {
1928
+ const { t } = useTranslation3();
1929
+ const styles9 = iconHue ? getStyles(iconHue) : void 0;
1930
+ const handleSelect = useCallback10((event) => {
1506
1931
  onSelect?.(event.altKey);
1507
1932
  }, [
1508
1933
  onSelect
1509
1934
  ]);
1510
- const handleButtonKeydown = useCallback9((event) => {
1935
+ const handleButtonKeydown = useCallback10((event) => {
1511
1936
  if (event.key === " " || event.key === "Enter") {
1512
1937
  event.preventDefault();
1513
1938
  event.stopPropagation();
@@ -1516,14 +1941,14 @@ var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef4(({ label,
1516
1941
  }, [
1517
1942
  onSelect
1518
1943
  ]);
1519
- return /* @__PURE__ */ React8.createElement(TextTooltip, {
1944
+ return /* @__PURE__ */ React13.createElement(TextTooltip, {
1520
1945
  text: toLocalizedString(label, t),
1521
1946
  side: "bottom",
1522
1947
  truncateQuery: "span[data-tooltip]",
1523
1948
  onlyWhenTruncating: true,
1524
1949
  asChild: true,
1525
1950
  ref: forwardedRef
1526
- }, /* @__PURE__ */ React8.createElement(Button2, {
1951
+ }, /* @__PURE__ */ React13.createElement(Button2, {
1527
1952
  "data-testid": "treeItem.heading",
1528
1953
  variant: "ghost",
1529
1954
  classNames: [
@@ -1537,31 +1962,31 @@ var TreeItemHeading = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef4(({ label,
1537
1962
  ...current && {
1538
1963
  "aria-current": "location"
1539
1964
  }
1540
- }, icon && /* @__PURE__ */ React8.createElement(Icon4, {
1965
+ }, icon && /* @__PURE__ */ React13.createElement(Icon6, {
1541
1966
  size: 5,
1542
1967
  icon: icon ?? "ph--circle-dashed--regular",
1543
1968
  classNames: [
1544
1969
  "my-1",
1545
- styles?.text
1970
+ styles9?.text
1546
1971
  ]
1547
- }), /* @__PURE__ */ React8.createElement("span", {
1972
+ }), /* @__PURE__ */ React13.createElement("span", {
1548
1973
  className: "min-w-0 truncate text-start font-normal",
1549
1974
  "data-tooltip": true
1550
- }, toLocalizedString(label, t)), /* @__PURE__ */ React8.createElement(CountBadge, {
1975
+ }, toLocalizedString(label, t)), /* @__PURE__ */ React13.createElement(CountBadge, {
1551
1976
  count,
1552
1977
  modifiedCount
1553
1978
  })));
1554
1979
  }));
1555
1980
  var CountBadge = ({ count, modifiedCount }) => {
1556
1981
  if (typeof modifiedCount === "number" && modifiedCount > 0) {
1557
- return /* @__PURE__ */ React8.createElement(Tag, {
1558
- palette: "rose",
1982
+ return /* @__PURE__ */ React13.createElement(Tag, {
1983
+ hue: "rose",
1559
1984
  classNames: "shrink-0 text-center [min-inline-size:1.5rem] tabular-nums"
1560
1985
  }, modifiedCount);
1561
1986
  }
1562
1987
  if (typeof count === "number") {
1563
- return /* @__PURE__ */ React8.createElement(Tag, {
1564
- palette: "neutral",
1988
+ return /* @__PURE__ */ React13.createElement(Tag, {
1989
+ hue: "neutral",
1565
1990
  classNames: "shrink-0 text-center [min-inline-size:1.5rem] tabular-nums"
1566
1991
  }, count);
1567
1992
  }
@@ -1569,10 +1994,10 @@ var CountBadge = ({ count, modifiedCount }) => {
1569
1994
  };
1570
1995
 
1571
1996
  // src/components/Tree/TreeItemToggle.tsx
1572
- import React9, { forwardRef as forwardRef5, memo as memo2 } from "react";
1997
+ import React14, { forwardRef as forwardRef7, memo as memo2 } from "react";
1573
1998
  import { IconButton as IconButton2 } from "@dxos/react-ui";
1574
- var TreeItemToggle = /* @__PURE__ */ memo2(/* @__PURE__ */ forwardRef5(({ classNames, open, isBranch, hidden, ...props }, forwardedRef) => {
1575
- return /* @__PURE__ */ React9.createElement(IconButton2, {
1999
+ var TreeItemToggle = /* @__PURE__ */ memo2(/* @__PURE__ */ forwardRef7(({ classNames, open, isBranch, hidden, ...props }, forwardedRef) => {
2000
+ return /* @__PURE__ */ React14.createElement(IconButton2, {
1576
2001
  ref: forwardedRef,
1577
2002
  "data-testid": "treeItem.toggle",
1578
2003
  "aria-expanded": open,
@@ -1598,6 +2023,14 @@ var TreeItemToggle = /* @__PURE__ */ memo2(/* @__PURE__ */ forwardRef5(({ classN
1598
2023
  // src/components/Tree/TreeItem.tsx
1599
2024
  var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-list/src/components/Tree/TreeItem.tsx";
1600
2025
  var hoverableDescriptionIcons = "[--icons-color:inherit] hover-hover:[--icons-color:var(--description-text)] hover-hover:hover:[--icons-color:inherit] focus-within:[--icons-color:inherit]";
2026
+ var NavTreeSectionHeader = ({ label }) => {
2027
+ const { t } = useTranslation4();
2028
+ return /* @__PURE__ */ React15.createElement("div", {
2029
+ role: "heading",
2030
+ "aria-level": 2,
2031
+ className: "col-[tree-row] pl-7 pt-3 pb-0.5 text-xs uppercase tracking-widest text-subdued hover:text-description select-none"
2032
+ }, toLocalizedString2(label, t));
2033
+ };
1601
2034
  var TreeDataSchema = Schema.Struct({
1602
2035
  id: Schema.String,
1603
2036
  path: Schema.Array(Schema.String),
@@ -1620,7 +2053,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1620
2053
  pathProp,
1621
2054
  item.id
1622
2055
  ]);
1623
- const { id, parentOf, draggable: itemDraggable, droppable: itemDroppable, label, className, headingClassName, icon, iconHue, disabled, testId, count, modifiedCount } = useAtomValue(itemPropsAtom(path));
2056
+ const { id, parentOf, disposition, draggable: itemDraggable, droppable: itemDroppable, label, className, headingClassName, icon, iconHue, disabled, testId, count, modifiedCount } = useAtomValue(itemPropsAtom(path));
1624
2057
  const childIds = useAtomValue(childIdsAtom(item.id));
1625
2058
  const open = useAtomValue(itemOpenAtom(path));
1626
2059
  const current = useAtomValue(itemCurrentAtom(path));
@@ -1637,7 +2070,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1637
2070
  item
1638
2071
  };
1639
2072
  const shouldSeedNativeDragData = typeof document !== "undefined" && document.body.hasAttribute("data-platform");
1640
- const cancelExpand = useCallback10(() => {
2073
+ const cancelExpand = useCallback11(() => {
1641
2074
  if (cancelExpandRef.current) {
1642
2075
  clearTimeout(cancelExpandRef.current);
1643
2076
  cancelExpandRef.current = null;
@@ -1647,10 +2080,10 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1647
2080
  const isItemDroppable = itemDroppable !== false;
1648
2081
  const nativeDragText = id;
1649
2082
  useEffect5(() => {
1650
- if (!draggableProp) {
2083
+ if (!draggableProp || !isItemDraggable && !isItemDroppable) {
1651
2084
  return;
1652
2085
  }
1653
- invariant(buttonRef.current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 70, S: void 0, A: ["buttonRef.current", ""] });
2086
+ invariant(buttonRef.current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 80, S: void 0, A: ["buttonRef.current", ""] });
1654
2087
  const makeDraggable = () => draggable2({
1655
2088
  element: buttonRef.current,
1656
2089
  getInitialData: () => data,
@@ -1768,7 +2201,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1768
2201
  useEffect5(() => () => cancelExpand(), [
1769
2202
  cancelExpand
1770
2203
  ]);
1771
- const handleOpenToggle = useCallback10(() => onOpenChange?.({
2204
+ const handleOpenToggle = useCallback11(() => onOpenChange?.({
1772
2205
  item,
1773
2206
  path,
1774
2207
  open: !open
@@ -1778,7 +2211,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1778
2211
  path,
1779
2212
  open
1780
2213
  ]);
1781
- const handleSelect = useCallback10((option = false) => {
2214
+ const handleSelect = useCallback11((option = false) => {
1782
2215
  if (isBranch && (option || current)) {
1783
2216
  handleOpenToggle();
1784
2217
  } else if (canSelectItem) {
@@ -1803,7 +2236,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1803
2236
  handleOpenToggle,
1804
2237
  onSelect
1805
2238
  ]);
1806
- const handleKeyDown = useCallback10((event) => {
2239
+ const handleKeyDown = useCallback11((event) => {
1807
2240
  switch (event.key) {
1808
2241
  case "ArrowRight":
1809
2242
  case "ArrowLeft":
@@ -1816,7 +2249,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1816
2249
  handleOpenToggle,
1817
2250
  handleSelect
1818
2251
  ]);
1819
- const handleItemHover = useCallback10(() => {
2252
+ const handleItemHover = useCallback11(() => {
1820
2253
  onItemHover?.({
1821
2254
  item
1822
2255
  });
@@ -1824,7 +2257,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1824
2257
  onItemHover,
1825
2258
  item
1826
2259
  ]);
1827
- const handleContextMenu = useCallback10((event) => {
2260
+ const handleContextMenu = useCallback11((event) => {
1828
2261
  event.preventDefault();
1829
2262
  setMenuOpen(true);
1830
2263
  }, [
@@ -1840,7 +2273,22 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1840
2273
  onOpenChange,
1841
2274
  onSelect
1842
2275
  };
1843
- return /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(Treegrid.Row, {
2276
+ if (disposition === "group") {
2277
+ if (childIds.length === 0) {
2278
+ return null;
2279
+ }
2280
+ return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(NavTreeSectionHeader, {
2281
+ label
2282
+ }), childIds.map((childId, index) => /* @__PURE__ */ React15.createElement(TreeItemById, {
2283
+ key: childId,
2284
+ id: childId,
2285
+ path,
2286
+ last: index === childIds.length - 1,
2287
+ levelOffset: levelOffset + 1,
2288
+ ...childProps
2289
+ })));
2290
+ }
2291
+ return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(Treegrid.Row, {
1844
2292
  ref: rowRef,
1845
2293
  key: id,
1846
2294
  id,
@@ -1852,7 +2300,7 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1852
2300
  // without alerting the user (except for in the correct link element). See also:
1853
2301
  // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current#description
1854
2302
  "aria-current": current ? "" : void 0,
1855
- classNames: mx8(
2303
+ classNames: mx10(
1856
2304
  "grid grid-cols-subgrid col-[tree-row] mt-0.5 is-current:bg-current-surface",
1857
2305
  // Highlight the row while a descendant marks an open popover anchor (e.g. inline rename).
1858
2306
  "has-[[data-popover-anchor]]:bg-current-surface",
@@ -1867,16 +2315,16 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1867
2315
  onKeyDown: handleKeyDown,
1868
2316
  onMouseEnter: handleItemHover,
1869
2317
  onContextMenu: handleContextMenu
1870
- }, /* @__PURE__ */ React10.createElement("div", {
2318
+ }, /* @__PURE__ */ React15.createElement("div", {
1871
2319
  className: "indent relative grid grid-cols-subgrid col-[tree-row]",
1872
2320
  style: paddingIndentation(level)
1873
- }, /* @__PURE__ */ React10.createElement(Treegrid.Cell, {
2321
+ }, /* @__PURE__ */ React15.createElement(Treegrid.Cell, {
1874
2322
  classNames: "flex items-center"
1875
- }, /* @__PURE__ */ React10.createElement(TreeItemToggle, {
2323
+ }, /* @__PURE__ */ React15.createElement(TreeItemToggle, {
1876
2324
  isBranch,
1877
2325
  open,
1878
2326
  onClick: handleOpenToggle
1879
- }), /* @__PURE__ */ React10.createElement(TreeItemHeading, {
2327
+ }), /* @__PURE__ */ React15.createElement(TreeItemHeading, {
1880
2328
  disabled,
1881
2329
  current,
1882
2330
  label,
@@ -1887,16 +2335,16 @@ var RawTreeItem = ({ item, path: pathProp, levelOffset = 2, last, draggable: dra
1887
2335
  modifiedCount,
1888
2336
  onSelect: handleSelect,
1889
2337
  ref: buttonRef
1890
- })), Columns && /* @__PURE__ */ React10.createElement(Columns, {
2338
+ })), Columns && /* @__PURE__ */ React15.createElement(Columns, {
1891
2339
  item,
1892
2340
  path,
1893
2341
  open,
1894
2342
  menuOpen,
1895
2343
  setMenuOpen
1896
- }), instruction && /* @__PURE__ */ React10.createElement(NaturalTreeItem.DropIndicator, {
2344
+ }), instruction && /* @__PURE__ */ React15.createElement(TreeDropIndicator, {
1897
2345
  instruction,
1898
2346
  gap: 2
1899
- }))), open && childIds.map((childId, index) => /* @__PURE__ */ React10.createElement(TreeItemById, {
2347
+ }))), open && childIds.map((childId, index) => /* @__PURE__ */ React15.createElement(TreeItemById, {
1900
2348
  key: childId,
1901
2349
  id: childId,
1902
2350
  path,
@@ -1911,7 +2359,7 @@ var RawTreeItemById = ({ id, ...props }) => {
1911
2359
  if (!item) {
1912
2360
  return null;
1913
2361
  }
1914
- return /* @__PURE__ */ React10.createElement(TreeItem, {
2362
+ return /* @__PURE__ */ React15.createElement(TreeItem, {
1915
2363
  item,
1916
2364
  ...props
1917
2365
  });
@@ -1919,6 +2367,14 @@ var RawTreeItemById = ({ id, ...props }) => {
1919
2367
  var TreeItemById = /* @__PURE__ */ memo3(RawTreeItemById);
1920
2368
 
1921
2369
  // src/components/Tree/Tree.tsx
2370
+ var TreeChild = ({ id, path: parentPath, last, ...childProps }) => {
2371
+ return /* @__PURE__ */ React16.createElement(TreeItemById, {
2372
+ id,
2373
+ path: parentPath,
2374
+ last,
2375
+ ...childProps
2376
+ });
2377
+ };
1922
2378
  var Tree = ({ classNames, model, rootId, path, id, draggable: draggable3 = false, gridTemplateColumns = "[tree-row-start] minmax(0, 1fr) min-content [tree-row-end]", levelOffset, renderColumns, blockInstruction, canDrop, canSelect, onOpenChange, onSelect, onItemHover }) => {
1923
2379
  const childIds = useAtomValue2(model.childIds(rootId));
1924
2380
  const treePath = useMemo8(() => path ? [
@@ -1942,12 +2398,12 @@ var Tree = ({ classNames, model, rootId, path, id, draggable: draggable3 = false
1942
2398
  onSelect,
1943
2399
  onItemHover
1944
2400
  };
1945
- return /* @__PURE__ */ React11.createElement(Treegrid2.Root, {
2401
+ return /* @__PURE__ */ React16.createElement(Treegrid.Root, {
1946
2402
  gridTemplateColumns,
1947
2403
  classNames
1948
- }, /* @__PURE__ */ React11.createElement(TreeProvider, {
2404
+ }, /* @__PURE__ */ React16.createElement(TreeProvider, {
1949
2405
  value: model
1950
- }, childIds.map((childId, index) => /* @__PURE__ */ React11.createElement(TreeItemById, {
2406
+ }, childIds.map((childId, index) => /* @__PURE__ */ React16.createElement(TreeChild, {
1951
2407
  key: childId,
1952
2408
  id: childId,
1953
2409
  last: index === childIds.length - 1,
@@ -1974,16 +2430,21 @@ export {
1974
2430
  Accordion,
1975
2431
  Combobox,
1976
2432
  DEFAULT_INDENTATION,
2433
+ DropIndicator,
2434
+ Empty,
1977
2435
  Listbox,
1978
2436
  OrderedList,
1979
2437
  Path,
1980
2438
  Picker,
2439
+ TREEGRID_PARENT_OF_SEPARATOR,
2440
+ TREEGRID_PATH_SEPARATOR,
1981
2441
  Tree,
1982
2442
  TreeDataSchema,
1983
2443
  TreeItem,
1984
2444
  TreeItemById,
1985
2445
  TreeItemToggle,
1986
2446
  TreeProvider,
2447
+ Treegrid,
1987
2448
  isTreeData,
1988
2449
  paddingIndentation,
1989
2450
  useListDisclosure,