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

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