@estiva-app/ui 0.50.4 → 0.51.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.
package/dist/index.js CHANGED
@@ -321,6 +321,7 @@ var CHIP_TEXT_CLASSES = "text-chip signal:font-mono signal:text-small signal:fon
321
321
  var BARE_INPUT_CLASSES = "bg-transparent text-text-primary placeholder:text-text-muted outline-none";
322
322
  var SIDEBAR_ROW_CLASSES = "rounded-md transition-colors";
323
323
  var SIDEBAR_ROW_TEXT_CLASSES = "text-text-secondary hover:text-text-primary";
324
+ var COLLAPSIBLE_PANEL_CLASSES = "h-[var(--collapsible-panel-height)] overflow-hidden transition-[height] duration-150 ease-out motion-reduce:transition-none data-[starting-style]:h-0 data-[ending-style]:h-0";
324
325
 
325
326
  // src/Tooltip.tsx
326
327
  import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
@@ -1100,6 +1101,7 @@ function SectionLabel({
1100
1101
  children,
1101
1102
  tone = "primary",
1102
1103
  truncate = false,
1104
+ folds = false,
1103
1105
  className
1104
1106
  }) {
1105
1107
  return /* @__PURE__ */ jsx19(
@@ -1107,8 +1109,9 @@ function SectionLabel({
1107
1109
  {
1108
1110
  className: cn(
1109
1111
  "text-h5 leading-3 signal:font-mono signal:text-small signal:uppercase signal:tracking-widest",
1110
- // Leaf's section labels are Signal's type (Katerina, 28 September).
1111
- "leaf:font-mono leaf:text-small leaf:uppercase leaf:tracking-widest",
1112
+ // Leaf's section labels are Signal's type (Katerina, 28 September),
1113
+ // but a group that folds keeps Ship's (Katerina, 2 October).
1114
+ !folds && "leaf:font-mono leaf:text-small leaf:uppercase leaf:tracking-widest",
1112
1115
  tone === "secondary" ? "text-text-secondary" : tone === "muted" ? "text-text-muted" : "text-text-primary",
1113
1116
  truncate && "min-w-0 truncate",
1114
1117
  className
@@ -2794,9 +2797,36 @@ function Breadcrumb({ items, className }) {
2794
2797
  }
2795
2798
 
2796
2799
  // src/NavItem.tsx
2797
- import { IconDotsVertical } from "@tabler/icons-react";
2800
+ import { useId, useState as useState7 } from "react";
2801
+ import { Collapsible } from "@base-ui/react/collapsible";
2802
+ import { IconChevronRight as IconChevronRight2, IconDotsVertical } from "@tabler/icons-react";
2798
2803
  import { jsx as jsx43, jsxs as jsxs29 } from "react/jsx-runtime";
2799
- function NavItem({ label, href, count, countLabel, active = false, icon, menu, menuLabel, className, ...props }) {
2804
+ function NavItem({
2805
+ label,
2806
+ href,
2807
+ count,
2808
+ countLabel,
2809
+ active = false,
2810
+ icon,
2811
+ menu,
2812
+ menuLabel,
2813
+ hint,
2814
+ children,
2815
+ defaultOpen = true,
2816
+ open: openProp,
2817
+ onOpenChange,
2818
+ className,
2819
+ ...props
2820
+ }) {
2821
+ const [openState, setOpenState] = useState7(defaultOpen);
2822
+ const panelId = useId();
2823
+ const hasRows = children != null && children !== false;
2824
+ const open = openProp ?? openState;
2825
+ const setOpen = (next) => {
2826
+ setOpenState(next);
2827
+ onOpenChange?.(next);
2828
+ };
2829
+ const besides = menu != null || hasRows;
2800
2830
  const row = /* @__PURE__ */ jsxs29(
2801
2831
  "a",
2802
2832
  {
@@ -2810,21 +2840,35 @@ function NavItem({ label, href, count, countLabel, active = false, icon, menu, m
2810
2840
  SIDEBAR_ROW_CLASSES,
2811
2841
  active ? "bg-bg-active text-text-primary" : cn(SIDEBAR_ROW_TEXT_CLASSES, "hover:bg-bg-hover"),
2812
2842
  // With a menu the ⋮ sits beside the link, so the row keeps its hover
2813
- // look while the ⋮ is pointed at and while its menu is open.
2814
- menu != null && !active && "group-hover/nav:bg-bg-hover group-hover/nav:text-text-primary group-has-[[aria-expanded=true]]/nav:bg-bg-hover group-has-[[aria-expanded=true]]/nav:text-text-primary",
2843
+ // look while the ⋮ is pointed at and while its menu is open. The same
2844
+ // for the arrow.
2845
+ besides && !active && "group-hover/nav:bg-bg-hover group-hover/nav:text-text-primary",
2846
+ menu != null && !active && "group-has-[[data-nav-menu]_[aria-expanded=true]]/nav:bg-bg-hover group-has-[[data-nav-menu]_[aria-expanded=true]]/nav:text-text-primary",
2815
2847
  className
2816
2848
  ),
2817
2849
  ...props,
2818
2850
  children: [
2819
- icon && /* @__PURE__ */ jsx43("span", { className: "flex shrink-0 items-center", children: icon }),
2851
+ (icon || hasRows) && /* @__PURE__ */ jsx43(
2852
+ "span",
2853
+ {
2854
+ className: cn(
2855
+ // With rows under it the slot is kept even with no icon: the arrow lands in it.
2856
+ "flex min-w-4 shrink-0 items-center",
2857
+ hasRows && "transition-opacity group-hover/nav:opacity-0 group-focus-within/nav:opacity-0"
2858
+ ),
2859
+ children: icon
2860
+ }
2861
+ ),
2820
2862
  /* @__PURE__ */ jsx43("span", { className: "flex-1 truncate", children: label }),
2863
+ hint != null && // Takes room only while it shows, so the label gives way to it.
2864
+ /* @__PURE__ */ jsx43("span", { className: "hidden shrink-0 items-center group-hover/nav:flex group-focus-within/nav:flex", children: hint }),
2821
2865
  count ? /* @__PURE__ */ jsx43(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx43(
2822
2866
  "span",
2823
2867
  {
2824
2868
  className: cn(
2825
2869
  "min-w-4 shrink-0 text-center font-mono text-caption tabular-nums text-text-muted",
2826
2870
  // With a menu, the ⋮ takes this place while it shows.
2827
- menu != null && "transition-opacity group-hover/nav:opacity-0 group-focus-within/nav:opacity-0 group-has-[[aria-expanded=true]]/nav:opacity-0"
2871
+ menu != null && "transition-opacity group-hover/nav:opacity-0 group-focus-within/nav:opacity-0 group-has-[[data-nav-menu]_[aria-expanded=true]]/nav:opacity-0"
2828
2872
  ),
2829
2873
  children: count
2830
2874
  }
@@ -2836,11 +2880,26 @@ function NavItem({ label, href, count, countLabel, active = false, icon, menu, m
2836
2880
  ]
2837
2881
  }
2838
2882
  );
2839
- if (menu == null) return row;
2883
+ if (!besides && hint == null) return row;
2840
2884
  const name = menuLabel ?? `More options for ${label}`;
2841
- return /* @__PURE__ */ jsxs29("div", { className: "group/nav relative shrink-0", children: [
2885
+ const line = /* @__PURE__ */ jsxs29("div", { className: "group/nav relative shrink-0", children: [
2842
2886
  row,
2843
- /* @__PURE__ */ jsx43("div", { className: "absolute inset-y-0 right-1 flex items-center opacity-0 transition-opacity focus-within:opacity-100 group-hover/nav:opacity-100 has-[[aria-expanded=true]]:opacity-100", children: /* @__PURE__ */ jsx43(
2887
+ hasRows && // `left-1`: the 24px button's 16px arrow then sits where the icon
2888
+ // sits (the row's px-2), so the icon turns into the arrow in place.
2889
+ /* @__PURE__ */ jsx43("div", { className: "absolute inset-y-0 left-1 flex items-center opacity-0 transition-opacity focus-within:opacity-100 group-hover/nav:opacity-100", children: /* @__PURE__ */ jsx43(
2890
+ IconButton,
2891
+ {
2892
+ tooltip: open ? "Collapse" : "Expand",
2893
+ "aria-label": open ? `Hide what is under ${label}` : `Show what is under ${label}`,
2894
+ "aria-expanded": open,
2895
+ "aria-controls": panelId,
2896
+ onClick: () => setOpen(!open),
2897
+ children: /* @__PURE__ */ jsx43(IconChevronRight2, { size: 16, stroke: 1.5, className: cn("transition-transform duration-150", open && "rotate-90") })
2898
+ }
2899
+ ) }),
2900
+ menu != null && // `right-1`: the 24px button's 16px icon then ends 8px from the row's
2901
+ // edge, where the count ends (px-2), so the ⋮ lands on the number.
2902
+ /* @__PURE__ */ jsx43("div", { "data-nav-menu": true, className: "absolute inset-y-0 right-1 flex items-center opacity-0 transition-opacity focus-within:opacity-100 group-hover/nav:opacity-100 has-[[aria-expanded=true]]:opacity-100", children: /* @__PURE__ */ jsx43(
2844
2903
  Menu,
2845
2904
  {
2846
2905
  align: "right",
@@ -2849,12 +2908,177 @@ function NavItem({ label, href, count, countLabel, active = false, icon, menu, m
2849
2908
  }
2850
2909
  ) })
2851
2910
  ] });
2911
+ if (!hasRows) return line;
2912
+ return /* @__PURE__ */ jsxs29(Collapsible.Root, { open, onOpenChange: setOpen, className: "flex shrink-0 flex-col", children: [
2913
+ line,
2914
+ /* @__PURE__ */ jsx43(
2915
+ Collapsible.Panel,
2916
+ {
2917
+ id: panelId,
2918
+ hiddenUntilFound: true,
2919
+ className: COLLAPSIBLE_PANEL_CLASSES,
2920
+ children: /* @__PURE__ */ jsx43("div", { className: "flex flex-col gap-px pl-6", children })
2921
+ }
2922
+ )
2923
+ ] });
2924
+ }
2925
+
2926
+ // src/CollapsibleSection.tsx
2927
+ import { useState as useState8 } from "react";
2928
+ import { Collapsible as Collapsible2 } from "@base-ui/react/collapsible";
2929
+
2930
+ // src/SectionHeader.tsx
2931
+ import { IconChevronRight as IconChevronRight3 } from "@tabler/icons-react";
2932
+ import { useRender } from "@base-ui/react/use-render";
2933
+ import { Fragment as Fragment11, jsx as jsx44, jsxs as jsxs30 } from "react/jsx-runtime";
2934
+ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", hover = "fill", look = "heading", render, className }) {
2935
+ const row = look === "row";
2936
+ const titleElement = useRender({
2937
+ render: render ?? (chevron ? /* @__PURE__ */ jsx44("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx44("span", {})),
2938
+ props: {
2939
+ // `text-left`: a button centres its text. `h-full` and `flex-1`: the
2940
+ // whole row up to the actions is the hit target, as it was when the
2941
+ // row itself carried the click.
2942
+ className: cn("flex h-full min-w-0 flex-1 items-center text-left", row ? "gap-2" : "gap-1"),
2943
+ children: /* @__PURE__ */ jsxs30(Fragment11, { children: [
2944
+ chevron && /* @__PURE__ */ jsx44(
2945
+ IconChevronRight3,
2946
+ {
2947
+ size: row ? 16 : 12,
2948
+ stroke: 1.5,
2949
+ className: cn("shrink-0 transition-transform duration-150", !row && "text-text-secondary", isExpanded && "rotate-90")
2950
+ }
2951
+ ),
2952
+ look === "quiet" ? /* @__PURE__ */ jsx44("span", { className: "min-w-0 truncate text-caption text-text-muted", children: title }) : row ? (
2953
+ // A row's words: NavItem's size and colour, brightening under the pointer with the row.
2954
+ /* @__PURE__ */ jsx44("span", { className: "min-w-0 flex-1 truncate text-body-2", children: title })
2955
+ ) : /* @__PURE__ */ jsx44(SectionLabel, { folds: chevron, children: title })
2956
+ ] })
2957
+ }
2958
+ });
2959
+ return /* @__PURE__ */ jsxs30(
2960
+ "div",
2961
+ {
2962
+ className: cn(
2963
+ "group flex h-[32px] shrink-0 items-center gap-1 px-2",
2964
+ !row && "transition-colors",
2965
+ // A row is NavItem's shape and colour: 6px corners, secondary words that brighten on hover.
2966
+ row ? cn(SIDEBAR_ROW_CLASSES, SIDEBAR_ROW_TEXT_CLASSES) : "rounded-lg",
2967
+ // The fill says "this does something": a row with a toggle or actions
2968
+ // lights up, a fixed heading over rows does not (2026-09-09, the
2969
+ // Sidebar's fixed group).
2970
+ // A quiet label never lights up: it is a label; its button does.
2971
+ hover === "fill" && look !== "quiet" && (chevron || actions && actions.length > 0) && "hover:bg-bg-hover",
2972
+ className
2973
+ ),
2974
+ children: [
2975
+ titleElement,
2976
+ trailing != null && /* @__PURE__ */ jsx44("div", { className: "flex shrink-0 items-center", children: trailing }),
2977
+ actions && actions.length > 0 && /* @__PURE__ */ jsx44(
2978
+ "div",
2979
+ {
2980
+ className: cn(
2981
+ "-mr-1 flex shrink-0 items-center gap-1",
2982
+ showActions === "hover" && "opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100"
2983
+ ),
2984
+ children: actions.map((action) => /* @__PURE__ */ jsx44(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
2985
+ }
2986
+ )
2987
+ ]
2988
+ }
2989
+ );
2990
+ }
2991
+
2992
+ // src/CollapsibleSection.tsx
2993
+ import { jsx as jsx45, jsxs as jsxs31 } from "react/jsx-runtime";
2994
+ var OPEN = "open";
2995
+ var CLOSED = "closed";
2996
+ function readStored(key) {
2997
+ if (!key) return void 0;
2998
+ try {
2999
+ const value = window.localStorage.getItem(key);
3000
+ return value === OPEN ? true : value === CLOSED ? false : void 0;
3001
+ } catch {
3002
+ return void 0;
3003
+ }
3004
+ }
3005
+ function writeStored(key, open) {
3006
+ if (!key) return;
3007
+ try {
3008
+ window.localStorage.setItem(key, open ? OPEN : CLOSED);
3009
+ } catch {
3010
+ }
3011
+ }
3012
+ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenChange, storageKey, trailing, actions, showActions, look = "heading", indent = false, children, className, contentClassName }) {
3013
+ const [openState, setOpenState] = useState8(() => readStored(storageKey) ?? defaultOpen);
3014
+ const open = openProp ?? openState;
3015
+ const setOpen = (next) => {
3016
+ setOpenState(next);
3017
+ writeStored(storageKey, next);
3018
+ onOpenChange?.(next);
3019
+ };
3020
+ return /* @__PURE__ */ jsxs31(Collapsible2.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
3021
+ /* @__PURE__ */ jsx45(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, look, className: "shrink-0", render: /* @__PURE__ */ jsx45(Collapsible2.Trigger, {}) }),
3022
+ /* @__PURE__ */ jsx45(
3023
+ Collapsible2.Panel,
3024
+ {
3025
+ hiddenUntilFound: true,
3026
+ className: COLLAPSIBLE_PANEL_CLASSES,
3027
+ children: /* @__PURE__ */ jsx45("div", { className: cn("flex flex-col", look === "row" ? "pl-6" : indent && "pl-4", contentClassName), children })
3028
+ }
3029
+ )
3030
+ ] });
3031
+ }
3032
+
3033
+ // src/NavTree.tsx
3034
+ import { Fragment as Fragment12, jsx as jsx46, jsxs as jsxs32 } from "react/jsx-runtime";
3035
+ function holds(nodes, id) {
3036
+ return id !== void 0 && nodes.some((node) => node.id === id || holds(node.children ?? [], id));
3037
+ }
3038
+ function Row({ node, selected, onSelect }) {
3039
+ return /* @__PURE__ */ jsx46(
3040
+ NavItem,
3041
+ {
3042
+ href: node.href,
3043
+ label: node.label,
3044
+ icon: node.icon,
3045
+ count: node.count,
3046
+ countLabel: node.countLabel,
3047
+ hint: node.hint,
3048
+ menu: node.menu,
3049
+ active: node.id === selected,
3050
+ defaultOpen: node.defaultOpen ?? true,
3051
+ onClick: onSelect ? (event) => onSelect(node, event) : void 0,
3052
+ children: node.children?.length ? node.children.map((child) => /* @__PURE__ */ jsx46(Row, { node: child, selected, onSelect }, child.id)) : void 0
3053
+ }
3054
+ );
3055
+ }
3056
+ function NavTree({ title, groups, selected, onSelect, emptyMessage, storageKey }) {
3057
+ return /* @__PURE__ */ jsxs32(Fragment12, { children: [
3058
+ title && /* @__PURE__ */ jsx46(SectionHeader, { title, look: "quiet", className: "mt-4 shrink-0" }),
3059
+ groups === null ? /* @__PURE__ */ jsx46(SkeletonList, { rows: 5 }) : groups.length === 0 ? (
3060
+ // Level with the rows: a row pads itself, so the line takes a row's inset (Katerina, 14 September).
3061
+ /* @__PURE__ */ jsx46("div", { className: "px-2 py-1", children: /* @__PURE__ */ jsx46(EmptyState, { scope: "section", message: emptyMessage }) })
3062
+ ) : groups.map((group) => /* @__PURE__ */ jsx46(
3063
+ CollapsibleSection,
3064
+ {
3065
+ title: group.title,
3066
+ indent: true,
3067
+ defaultOpen: holds(group.nodes, selected),
3068
+ storageKey: storageKey ? `${storageKey}.${group.id}` : void 0,
3069
+ className: "mt-2 shrink-0",
3070
+ contentClassName: "gap-px",
3071
+ children: group.nodes.map((node) => /* @__PURE__ */ jsx46(Row, { node, selected, onSelect }, node.id))
3072
+ },
3073
+ group.id
3074
+ ))
3075
+ ] });
2852
3076
  }
2853
3077
 
2854
3078
  // src/Popover.tsx
2855
3079
  import { useMemo as useMemo3 } from "react";
2856
3080
  import { Popover as BasePopover } from "@base-ui/react/popover";
2857
- import { jsx as jsx44, jsxs as jsxs30 } from "react/jsx-runtime";
3081
+ import { jsx as jsx47, jsxs as jsxs33 } from "react/jsx-runtime";
2858
3082
  var GAP5 = 4;
2859
3083
  var VIEWPORT_PAD5 = 8;
2860
3084
  function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpenChange, finalFocus, actionsRef, ariaLabel, children, className, contentClassName, maxHeight }) {
@@ -2863,7 +3087,7 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2863
3087
  if (anchor instanceof Element) return anchor;
2864
3088
  return { getBoundingClientRect: () => anchor };
2865
3089
  }, [anchor]);
2866
- return /* @__PURE__ */ jsxs30(
3090
+ return /* @__PURE__ */ jsxs33(
2867
3091
  BasePopover.Root,
2868
3092
  {
2869
3093
  open,
@@ -2871,8 +3095,8 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2871
3095
  actionsRef,
2872
3096
  modal: false,
2873
3097
  children: [
2874
- trigger && /* @__PURE__ */ jsx44(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
2875
- /* @__PURE__ */ jsx44(BasePopover.Portal, { children: /* @__PURE__ */ jsx44(
3098
+ trigger && /* @__PURE__ */ jsx47(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
3099
+ /* @__PURE__ */ jsx47(BasePopover.Portal, { children: /* @__PURE__ */ jsx47(
2876
3100
  BasePopover.Positioner,
2877
3101
  {
2878
3102
  anchor: anchorTarget,
@@ -2881,20 +3105,20 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2881
3105
  sideOffset: GAP5,
2882
3106
  collisionPadding: VIEWPORT_PAD5,
2883
3107
  className: "z-50 data-[anchor-hidden]:hidden",
2884
- children: /* @__PURE__ */ jsx44(
3108
+ children: /* @__PURE__ */ jsx47(
2885
3109
  BasePopover.Popup,
2886
3110
  {
2887
3111
  "aria-label": ariaLabel,
2888
3112
  initialFocus: trigger ? void 0 : false,
2889
3113
  finalFocus,
2890
3114
  className: cn("min-w-[180px] outline-none p-0", className),
2891
- render: /* @__PURE__ */ jsx44(MenuPanel, {}),
2892
- children: /* @__PURE__ */ jsx44(
3115
+ render: /* @__PURE__ */ jsx47(MenuPanel, {}),
3116
+ children: /* @__PURE__ */ jsx47(
2893
3117
  ScrollArea,
2894
3118
  {
2895
3119
  viewportClassName: maxHeight ?? "max-h-[var(--available-height)]",
2896
3120
  contentClassName: cn("flex flex-col p-2", contentClassName),
2897
- children: /* @__PURE__ */ jsx44(DividerInPanel.Provider, { value: true, children })
3121
+ children: /* @__PURE__ */ jsx47(DividerInPanel.Provider, { value: true, children })
2898
3122
  }
2899
3123
  )
2900
3124
  }
@@ -2907,14 +3131,14 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2907
3131
  }
2908
3132
 
2909
3133
  // src/SuggestionMenu.tsx
2910
- import { useCallback as useCallback3, useEffect as useEffect4, useId, useImperativeHandle, useMemo as useMemo4, useState as useState7 } from "react";
2911
- import { jsx as jsx45, jsxs as jsxs31 } from "react/jsx-runtime";
3134
+ import { useCallback as useCallback3, useEffect as useEffect4, useId as useId2, useImperativeHandle, useMemo as useMemo4, useState as useState9 } from "react";
3135
+ import { jsx as jsx48, jsxs as jsxs34 } from "react/jsx-runtime";
2912
3136
  function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sections, itemKey, row, onSelect, handle }) {
2913
3137
  const shown = useMemo4(() => sections.filter((section) => section.items.length > 0), [sections]);
2914
3138
  const items = useMemo4(() => shown.flatMap((section) => section.items), [shown]);
2915
3139
  const keys = items.map(itemKey).join("\n");
2916
- const [highlight, setHighlight] = useState7(0);
2917
- const base = useId();
3140
+ const [highlight, setHighlight] = useState9(0);
3141
+ const base = useId2();
2918
3142
  const listboxId = `${base}-list`;
2919
3143
  useEffect4(() => setHighlight(0), [keys]);
2920
3144
  useImperativeHandle(handle, () => ({
@@ -2961,7 +3185,7 @@ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sect
2961
3185
  const { label, description, leading, shortcut, hint, size } = row(item);
2962
3186
  return (
2963
3187
  // A row of a list the editor drives from its caret: focus stays in the text, so the row is no Tab stop.
2964
- /* @__PURE__ */ jsx45(
3188
+ /* @__PURE__ */ jsx48(
2965
3189
  MenuItem,
2966
3190
  {
2967
3191
  role: "option",
@@ -2986,17 +3210,17 @@ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sect
2986
3210
  )
2987
3211
  );
2988
3212
  };
2989
- return /* @__PURE__ */ jsx45(Popover, { anchor: rect, open: rect !== null, side: "top", align: "left", className: width, maxHeight, ariaLabel, children: /* @__PURE__ */ jsx45("div", { id: listboxId, role: "listbox", "aria-label": ariaLabel, className: "flex flex-col", children: shown.map((section, i) => /* @__PURE__ */ jsxs31("div", { className: "contents", children: [
2990
- i > 0 && /* @__PURE__ */ jsx45(MenuSeparator, {}),
2991
- section.label ? /* @__PURE__ */ jsx45("div", { role: "group", "aria-label": section.label, children: /* @__PURE__ */ jsx45(MenuSection, { label: section.label, className: section.className, children: section.items.map(drawRow) }) }) : section.items.map(drawRow)
3213
+ return /* @__PURE__ */ jsx48(Popover, { anchor: rect, open: rect !== null, side: "top", align: "left", className: width, maxHeight, ariaLabel, children: /* @__PURE__ */ jsx48("div", { id: listboxId, role: "listbox", "aria-label": ariaLabel, className: "flex flex-col", children: shown.map((section, i) => /* @__PURE__ */ jsxs34("div", { className: "contents", children: [
3214
+ i > 0 && /* @__PURE__ */ jsx48(MenuSeparator, {}),
3215
+ section.label ? /* @__PURE__ */ jsx48("div", { role: "group", "aria-label": section.label, children: /* @__PURE__ */ jsx48(MenuSection, { label: section.label, className: section.className, children: section.items.map(drawRow) }) }) : section.items.map(drawRow)
2992
3216
  ] }, section.label ?? i)) }) });
2993
3217
  }
2994
3218
 
2995
3219
  // src/Toolbar.tsx
2996
3220
  import { Toolbar as BaseToolbar } from "@base-ui/react/toolbar";
2997
- import { jsx as jsx46 } from "react/jsx-runtime";
3221
+ import { jsx as jsx49 } from "react/jsx-runtime";
2998
3222
  function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocus = true, surface = true, children, className }) {
2999
- const strip = /* @__PURE__ */ jsx46(
3223
+ const strip = /* @__PURE__ */ jsx49(
3000
3224
  BaseToolbar.Root,
3001
3225
  {
3002
3226
  "aria-label": ariaLabel,
@@ -3007,27 +3231,27 @@ function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocu
3007
3231
  }
3008
3232
  );
3009
3233
  if (!surface) return strip;
3010
- return /* @__PURE__ */ jsx46(MenuPanel, { className: "w-fit p-1", children: strip });
3234
+ return /* @__PURE__ */ jsx49(MenuPanel, { className: "w-fit p-1", children: strip });
3011
3235
  }
3012
3236
  function ToolbarButton({ ref, disabled, disabledReason, ...props }) {
3013
- return /* @__PURE__ */ jsx46(
3237
+ return /* @__PURE__ */ jsx49(
3014
3238
  BaseToolbar.Button,
3015
3239
  {
3016
3240
  ref,
3017
3241
  disabled: disabled || !!disabledReason,
3018
3242
  focusableWhenDisabled: true,
3019
- render: /* @__PURE__ */ jsx46(IconButton, { disabled, disabledReason, ...props })
3243
+ render: /* @__PURE__ */ jsx49(IconButton, { disabled, disabledReason, ...props })
3020
3244
  }
3021
3245
  );
3022
3246
  }
3023
3247
  function ToolbarLink({ ref, href, ...props }) {
3024
- return /* @__PURE__ */ jsx46(BaseToolbar.Link, { ref, render: /* @__PURE__ */ jsx46(IconButton, { href, ...props }) });
3248
+ return /* @__PURE__ */ jsx49(BaseToolbar.Link, { ref, render: /* @__PURE__ */ jsx49(IconButton, { href, ...props }) });
3025
3249
  }
3026
3250
  function ToolbarInput({ size, ...props }) {
3027
- return /* @__PURE__ */ jsx46(BaseToolbar.Input, { render: /* @__PURE__ */ jsx46(TextInput, { size }), ...props });
3251
+ return /* @__PURE__ */ jsx49(BaseToolbar.Input, { render: /* @__PURE__ */ jsx49(TextInput, { size }), ...props });
3028
3252
  }
3029
3253
  function ToolbarSeparator({ className }) {
3030
- return /* @__PURE__ */ jsx46(
3254
+ return /* @__PURE__ */ jsx49(
3031
3255
  BaseToolbar.Separator,
3032
3256
  {
3033
3257
  orientation: "vertical",
@@ -3037,9 +3261,9 @@ function ToolbarSeparator({ className }) {
3037
3261
  }
3038
3262
 
3039
3263
  // src/ReactionPicker.tsx
3040
- import { jsx as jsx47 } from "react/jsx-runtime";
3264
+ import { jsx as jsx50 } from "react/jsx-runtime";
3041
3265
  function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reactions", surface = true, className }) {
3042
- return /* @__PURE__ */ jsx47(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
3266
+ return /* @__PURE__ */ jsx50(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
3043
3267
  /*
3044
3268
  A `ToolbarButton`, not a button in a tooltip wrapper. The wrapper
3045
3269
  would become the toolbar's item and the button inside it would never
@@ -3049,14 +3273,14 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
3049
3273
  The tooltip names it for a pointer, `aria-label` for everything else,
3050
3274
  and both say the meaning rather than the glyph.
3051
3275
  */
3052
- /* @__PURE__ */ jsx47(
3276
+ /* @__PURE__ */ jsx50(
3053
3277
  ToolbarButton,
3054
3278
  {
3055
3279
  "aria-label": option.label,
3056
3280
  tooltip: option.label,
3057
3281
  onClick: () => onSelect(option.emoji),
3058
3282
  className: "size-7",
3059
- children: /* @__PURE__ */ jsx47("span", { "aria-hidden": "true", className: "text-h3 leading-none", children: option.emoji })
3283
+ children: /* @__PURE__ */ jsx50("span", { "aria-hidden": "true", className: "text-h3 leading-none", children: option.emoji })
3060
3284
  },
3061
3285
  option.emoji
3062
3286
  )
@@ -3065,23 +3289,23 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
3065
3289
 
3066
3290
  // src/PreviewCard.tsx
3067
3291
  import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
3068
- import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
3292
+ import { jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
3069
3293
  var GAP6 = 12;
3070
3294
  var VIEWPORT_PAD6 = 8;
3071
3295
  var OPEN_DELAY2 = 350;
3072
3296
  var CLOSE_DELAY = 200;
3073
3297
  function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, contentClassName, wrapperClassName }) {
3074
- return /* @__PURE__ */ jsxs32(BasePreviewCard.Root, { children: [
3075
- /* @__PURE__ */ jsx48(
3298
+ return /* @__PURE__ */ jsxs35(BasePreviewCard.Root, { children: [
3299
+ /* @__PURE__ */ jsx51(
3076
3300
  BasePreviewCard.Trigger,
3077
3301
  {
3078
3302
  delay,
3079
3303
  closeDelay,
3080
- render: /* @__PURE__ */ jsx48("span", { className: cn("inline-flex", wrapperClassName) }),
3304
+ render: /* @__PURE__ */ jsx51("span", { className: cn("inline-flex", wrapperClassName) }),
3081
3305
  children
3082
3306
  }
3083
3307
  ),
3084
- /* @__PURE__ */ jsx48(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx48(
3308
+ /* @__PURE__ */ jsx51(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx51(
3085
3309
  BasePreviewCard.Positioner,
3086
3310
  {
3087
3311
  side,
@@ -3089,12 +3313,12 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
3089
3313
  sideOffset: GAP6,
3090
3314
  collisionPadding: VIEWPORT_PAD6,
3091
3315
  className: "z-50 data-[anchor-hidden]:hidden",
3092
- children: /* @__PURE__ */ jsx48(
3316
+ children: /* @__PURE__ */ jsx51(
3093
3317
  BasePreviewCard.Popup,
3094
3318
  {
3095
3319
  className: cn("w-[360px] p-0 outline-none", className),
3096
- render: /* @__PURE__ */ jsx48(MenuPanel, {}),
3097
- children: /* @__PURE__ */ jsx48(ScrollArea, { viewportClassName: "max-h-[min(300px,var(--available-height))]", contentClassName: cn("flex flex-col gap-3 p-3", contentClassName), children: content })
3320
+ render: /* @__PURE__ */ jsx51(MenuPanel, {}),
3321
+ children: /* @__PURE__ */ jsx51(ScrollArea, { viewportClassName: "max-h-[min(300px,var(--available-height))]", contentClassName: cn("flex flex-col gap-3 p-3", contentClassName), children: content })
3098
3322
  }
3099
3323
  )
3100
3324
  }
@@ -3103,15 +3327,15 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
3103
3327
  }
3104
3328
 
3105
3329
  // src/Rail.tsx
3106
- import { jsx as jsx49 } from "react/jsx-runtime";
3330
+ import { jsx as jsx52 } from "react/jsx-runtime";
3107
3331
  function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
3108
- return /* @__PURE__ */ jsx49("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
3332
+ return /* @__PURE__ */ jsx52("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
3109
3333
  }
3110
3334
 
3111
3335
  // src/RailItem.tsx
3112
- import { jsx as jsx50, jsxs as jsxs33 } from "react/jsx-runtime";
3336
+ import { jsx as jsx53, jsxs as jsxs36 } from "react/jsx-runtime";
3113
3337
  function RailItem({ href, icon, label, active = false, className, ...props }) {
3114
- return /* @__PURE__ */ jsxs33(
3338
+ return /* @__PURE__ */ jsxs36(
3115
3339
  "a",
3116
3340
  {
3117
3341
  href,
@@ -3119,14 +3343,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
3119
3343
  className: cn("group flex h-12 w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
3120
3344
  ...props,
3121
3345
  children: [
3122
- /* @__PURE__ */ jsx50(
3346
+ /* @__PURE__ */ jsx53(
3123
3347
  "div",
3124
3348
  {
3125
3349
  className: cn(
3126
3350
  "flex items-center justify-center rounded-lg p-2 transition-colors",
3127
3351
  active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
3128
3352
  ),
3129
- children: /* @__PURE__ */ jsx50(
3353
+ children: /* @__PURE__ */ jsx53(
3130
3354
  "span",
3131
3355
  {
3132
3356
  className: cn(
@@ -3138,14 +3362,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
3138
3362
  )
3139
3363
  }
3140
3364
  ),
3141
- /* @__PURE__ */ jsx50("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
3365
+ /* @__PURE__ */ jsx53("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
3142
3366
  ]
3143
3367
  }
3144
3368
  );
3145
3369
  }
3146
3370
 
3147
3371
  // src/Property.tsx
3148
- import { jsx as jsx51, jsxs as jsxs34 } from "react/jsx-runtime";
3372
+ import { jsx as jsx54, jsxs as jsxs37 } from "react/jsx-runtime";
3149
3373
  var VALUE_CLASSES = "contents";
3150
3374
  function Property({ label, layout = "row", children, className }) {
3151
3375
  if (layout === "stacked") {
@@ -3153,25 +3377,25 @@ function Property({ label, layout = "row", children, className }) {
3153
3377
  // gap-3 — the one label-above-content distance (Katerina, 2026-09-01):
3154
3378
  // Peek's topic-details sections already sit at 12px, Ship's rail was
3155
3379
  // 6px, and unifying means the bigger, calmer one.
3156
- /* @__PURE__ */ jsxs34("dl", { className: cn("flex flex-col gap-3", className), children: [
3157
- /* @__PURE__ */ jsx51("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
3158
- /* @__PURE__ */ jsx51("dd", { className: VALUE_CLASSES, children })
3380
+ /* @__PURE__ */ jsxs37("dl", { className: cn("flex flex-col gap-3", className), children: [
3381
+ /* @__PURE__ */ jsx54("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
3382
+ /* @__PURE__ */ jsx54("dd", { className: VALUE_CLASSES, children })
3159
3383
  ] })
3160
3384
  );
3161
3385
  }
3162
- return /* @__PURE__ */ jsxs34("dl", { className: cn("flex items-center gap-2", className), children: [
3163
- /* @__PURE__ */ jsx51("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
3164
- /* @__PURE__ */ jsx51("dd", { className: VALUE_CLASSES, children })
3386
+ return /* @__PURE__ */ jsxs37("dl", { className: cn("flex items-center gap-2", className), children: [
3387
+ /* @__PURE__ */ jsx54("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
3388
+ /* @__PURE__ */ jsx54("dd", { className: VALUE_CLASSES, children })
3165
3389
  ] });
3166
3390
  }
3167
3391
 
3168
3392
  // src/Reaction.tsx
3169
3393
  import { Toggle } from "@base-ui/react/toggle";
3170
- import { jsx as jsx52, jsxs as jsxs35 } from "react/jsx-runtime";
3394
+ import { jsx as jsx55, jsxs as jsxs38 } from "react/jsx-runtime";
3171
3395
  function Reaction({ emoji, count, pressed = false, className, ...props }) {
3172
3396
  return (
3173
3397
  // @estiva-escape(no-copied-look): W1 (Katerina, 24 September: leave alone): a reaction pill shares four words with a field's box by coincidence
3174
- /* @__PURE__ */ jsxs35(
3398
+ /* @__PURE__ */ jsxs38(
3175
3399
  Toggle,
3176
3400
  {
3177
3401
  pressed,
@@ -3193,8 +3417,8 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
3193
3417
  ),
3194
3418
  ...props,
3195
3419
  children: [
3196
- /* @__PURE__ */ jsx52("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
3197
- /* @__PURE__ */ jsx52("span", { className: CHIP_TEXT_CLASSES, children: count })
3420
+ /* @__PURE__ */ jsx55("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
3421
+ /* @__PURE__ */ jsx55("span", { className: CHIP_TEXT_CLASSES, children: count })
3198
3422
  ]
3199
3423
  }
3200
3424
  )
@@ -3204,9 +3428,9 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
3204
3428
  // src/SearchInput.tsx
3205
3429
  import "react";
3206
3430
  import { Input as Input3 } from "@base-ui/react/input";
3207
- import { jsx as jsx53, jsxs as jsxs36 } from "react/jsx-runtime";
3431
+ import { jsx as jsx56, jsxs as jsxs39 } from "react/jsx-runtime";
3208
3432
  function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
3209
- return /* @__PURE__ */ jsxs36(
3433
+ return /* @__PURE__ */ jsxs39(
3210
3434
  "div",
3211
3435
  {
3212
3436
  className: cn(
@@ -3218,7 +3442,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
3218
3442
  className
3219
3443
  ),
3220
3444
  children: [
3221
- /* @__PURE__ */ jsx53(
3445
+ /* @__PURE__ */ jsx56(
3222
3446
  Input3,
3223
3447
  {
3224
3448
  className: cn("flex-1 min-w-0 text-input-value", BARE_INPUT_CLASSES),
@@ -3226,104 +3450,42 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
3226
3450
  ...props
3227
3451
  }
3228
3452
  ),
3229
- shortcut && /* @__PURE__ */ jsx53(Kbd, { children: shortcut })
3230
- ]
3231
- }
3232
- );
3233
- }
3234
-
3235
- // src/SectionHeader.tsx
3236
- import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
3237
- import { useRender } from "@base-ui/react/use-render";
3238
- import { Fragment as Fragment11, jsx as jsx54, jsxs as jsxs37 } from "react/jsx-runtime";
3239
- function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", hover = "fill", look = "heading", render, className }) {
3240
- const row = look === "row";
3241
- const titleElement = useRender({
3242
- render: render ?? (chevron ? /* @__PURE__ */ jsx54("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx54("span", {})),
3243
- props: {
3244
- // `text-left`: a button centres its text. `h-full` and `flex-1`: the
3245
- // whole row up to the actions is the hit target, as it was when the
3246
- // row itself carried the click.
3247
- className: cn("flex h-full min-w-0 flex-1 items-center text-left", row ? "gap-2" : "gap-1"),
3248
- children: /* @__PURE__ */ jsxs37(Fragment11, { children: [
3249
- chevron && /* @__PURE__ */ jsx54(
3250
- IconChevronRight2,
3251
- {
3252
- size: row ? 16 : 12,
3253
- stroke: 1.5,
3254
- className: cn("shrink-0 transition-transform duration-150", !row && "text-text-secondary", isExpanded && "rotate-90")
3255
- }
3256
- ),
3257
- look === "quiet" ? /* @__PURE__ */ jsx54("span", { className: "min-w-0 truncate text-caption text-text-muted", children: title }) : row ? (
3258
- // A row's words: NavItem's size and colour, brightening under the pointer with the row.
3259
- /* @__PURE__ */ jsx54("span", { className: "min-w-0 flex-1 truncate text-body-2", children: title })
3260
- ) : /* @__PURE__ */ jsx54(SectionLabel, { children: title })
3261
- ] })
3262
- }
3263
- });
3264
- return /* @__PURE__ */ jsxs37(
3265
- "div",
3266
- {
3267
- className: cn(
3268
- "group flex h-[32px] shrink-0 items-center gap-1 px-2",
3269
- !row && "transition-colors",
3270
- // A row is NavItem's shape and colour: 6px corners, secondary words that brighten on hover.
3271
- row ? cn(SIDEBAR_ROW_CLASSES, SIDEBAR_ROW_TEXT_CLASSES) : "rounded-lg",
3272
- // The fill says "this does something": a row with a toggle or actions
3273
- // lights up, a fixed heading over rows does not (2026-09-09, the
3274
- // Sidebar's fixed group).
3275
- // A quiet label never lights up: it is a label; its button does.
3276
- hover === "fill" && look !== "quiet" && (chevron || actions && actions.length > 0) && "hover:bg-bg-hover",
3277
- className
3278
- ),
3279
- children: [
3280
- titleElement,
3281
- trailing != null && /* @__PURE__ */ jsx54("div", { className: "flex shrink-0 items-center", children: trailing }),
3282
- actions && actions.length > 0 && /* @__PURE__ */ jsx54(
3283
- "div",
3284
- {
3285
- className: cn(
3286
- "-mr-1 flex shrink-0 items-center gap-1",
3287
- showActions === "hover" && "opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100"
3288
- ),
3289
- children: actions.map((action) => /* @__PURE__ */ jsx54(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
3290
- }
3291
- )
3453
+ shortcut && /* @__PURE__ */ jsx56(Kbd, { children: shortcut })
3292
3454
  ]
3293
3455
  }
3294
3456
  );
3295
3457
  }
3296
3458
 
3297
3459
  // src/Panel.tsx
3298
- import { jsx as jsx55, jsxs as jsxs38 } from "react/jsx-runtime";
3460
+ import { jsx as jsx57, jsxs as jsxs40 } from "react/jsx-runtime";
3299
3461
  function Frame({ title, chevron = false, actions, children, footer, bodyClassName, bodyRef, onBodyScroll, className, broken = false }) {
3300
- return /* @__PURE__ */ jsxs38("div", { className: cn("flex h-full min-h-0 flex-1 flex-col", className), children: [
3301
- /* @__PURE__ */ jsx55(ContainerHeader, { title, chevron, actions }),
3462
+ return /* @__PURE__ */ jsxs40("div", { className: cn("flex h-full min-h-0 flex-1 flex-col", className), children: [
3463
+ /* @__PURE__ */ jsx57(ContainerHeader, { title, chevron, actions }),
3302
3464
  broken ? (
3303
3465
  // The message takes the room the body had and centres itself in it.
3304
- /* @__PURE__ */ jsx55("div", { className: "flex min-h-0 flex-1 flex-col px-4", children })
3305
- ) : /* @__PURE__ */ jsx55(ScrollArea, { className: "min-h-0 flex-1", contentClassName: bodyClassName, viewportRef: bodyRef, onScroll: onBodyScroll, children }),
3306
- !broken && footer && /* @__PURE__ */ jsx55("div", { className: "shrink-0", children: footer })
3466
+ /* @__PURE__ */ jsx57("div", { className: "flex min-h-0 flex-1 flex-col px-4", children })
3467
+ ) : /* @__PURE__ */ jsx57(ScrollArea, { className: "min-h-0 flex-1", contentClassName: bodyClassName, viewportRef: bodyRef, onScroll: onBodyScroll, children }),
3468
+ !broken && footer && /* @__PURE__ */ jsx57("div", { className: "shrink-0", children: footer })
3307
3469
  ] });
3308
3470
  }
3309
3471
  function Panel(props) {
3310
- return /* @__PURE__ */ jsx55(
3472
+ return /* @__PURE__ */ jsx57(
3311
3473
  ErrorBoundary,
3312
3474
  {
3313
3475
  label: "panel",
3314
3476
  frame: (message) => (
3315
3477
  // Only the name comes back with the message: the actions and the footer may be what threw.
3316
- /* @__PURE__ */ jsx55(Frame, { title: props.title, chevron: props.chevron, className: props.className, broken: true, children: message })
3478
+ /* @__PURE__ */ jsx57(Frame, { title: props.title, chevron: props.chevron, className: props.className, broken: true, children: message })
3317
3479
  ),
3318
- children: /* @__PURE__ */ jsx55(Frame, { ...props })
3480
+ children: /* @__PURE__ */ jsx57(Frame, { ...props })
3319
3481
  }
3320
3482
  );
3321
3483
  }
3322
3484
 
3323
3485
  // src/ListColumn.tsx
3324
- import { jsx as jsx56, jsxs as jsxs39 } from "react/jsx-runtime";
3486
+ import { jsx as jsx58, jsxs as jsxs41 } from "react/jsx-runtime";
3325
3487
  function Column({ title, chevron = false, actions, above, collapsed = false, children, className, broken = false }) {
3326
- return /* @__PURE__ */ jsxs39(
3488
+ return /* @__PURE__ */ jsxs41(
3327
3489
  "div",
3328
3490
  {
3329
3491
  className: cn(
@@ -3334,78 +3496,35 @@ function Column({ title, chevron = false, actions, above, collapsed = false, chi
3334
3496
  ),
3335
3497
  "data-collapsed": collapsed || void 0,
3336
3498
  children: [
3337
- /* @__PURE__ */ jsx56(ContainerHeader, { title, chevron, actions }),
3499
+ /* @__PURE__ */ jsx58(ContainerHeader, { title, chevron, actions }),
3338
3500
  above,
3339
3501
  broken ? (
3340
3502
  // The message takes the room the list had and centres itself in it (Katerina, 19 September).
3341
- /* @__PURE__ */ jsx56("div", { className: "flex min-h-0 flex-1 flex-col px-3", children })
3342
- ) : /* @__PURE__ */ jsx56(ScrollArea, { className: "flex-1", contentClassName: "flex flex-col gap-0.5 px-3 pt-4 pb-3", children })
3503
+ /* @__PURE__ */ jsx58("div", { className: "flex min-h-0 flex-1 flex-col px-3", children })
3504
+ ) : /* @__PURE__ */ jsx58(ScrollArea, { className: "flex-1", contentClassName: "flex flex-col gap-0.5 px-3 pt-4 pb-3", children })
3343
3505
  ]
3344
3506
  }
3345
3507
  );
3346
3508
  }
3347
3509
  function ListColumn(props) {
3348
- return /* @__PURE__ */ jsx56(
3510
+ return /* @__PURE__ */ jsx58(
3349
3511
  ErrorBoundary,
3350
3512
  {
3351
3513
  label: "list panel",
3352
3514
  frame: (message) => (
3353
3515
  // Only the name comes back with the message: the actions and the row above may be what threw.
3354
- /* @__PURE__ */ jsx56(Column, { title: props.title, chevron: props.chevron, collapsed: props.collapsed, className: props.className, broken: true, children: message })
3516
+ /* @__PURE__ */ jsx58(Column, { title: props.title, chevron: props.chevron, collapsed: props.collapsed, className: props.className, broken: true, children: message })
3355
3517
  ),
3356
- children: /* @__PURE__ */ jsx56(Column, { ...props })
3518
+ children: /* @__PURE__ */ jsx58(Column, { ...props })
3357
3519
  }
3358
3520
  );
3359
3521
  }
3360
3522
 
3361
- // src/CollapsibleSection.tsx
3362
- import { useState as useState8 } from "react";
3363
- import { Collapsible } from "@base-ui/react/collapsible";
3364
- import { jsx as jsx57, jsxs as jsxs40 } from "react/jsx-runtime";
3365
- var OPEN = "open";
3366
- var CLOSED = "closed";
3367
- function readStored(key) {
3368
- if (!key) return void 0;
3369
- try {
3370
- const value = window.localStorage.getItem(key);
3371
- return value === OPEN ? true : value === CLOSED ? false : void 0;
3372
- } catch {
3373
- return void 0;
3374
- }
3375
- }
3376
- function writeStored(key, open) {
3377
- if (!key) return;
3378
- try {
3379
- window.localStorage.setItem(key, open ? OPEN : CLOSED);
3380
- } catch {
3381
- }
3382
- }
3383
- function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenChange, storageKey, trailing, actions, showActions, look = "heading", children, className, contentClassName }) {
3384
- const [openState, setOpenState] = useState8(() => readStored(storageKey) ?? defaultOpen);
3385
- const open = openProp ?? openState;
3386
- const setOpen = (next) => {
3387
- setOpenState(next);
3388
- writeStored(storageKey, next);
3389
- onOpenChange?.(next);
3390
- };
3391
- return /* @__PURE__ */ jsxs40(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
3392
- /* @__PURE__ */ jsx57(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, look, className: "shrink-0", render: /* @__PURE__ */ jsx57(Collapsible.Trigger, {}) }),
3393
- /* @__PURE__ */ jsx57(
3394
- Collapsible.Panel,
3395
- {
3396
- hiddenUntilFound: true,
3397
- className: "h-[var(--collapsible-panel-height)] overflow-hidden transition-[height] duration-150 ease-out motion-reduce:transition-none data-[starting-style]:h-0 data-[ending-style]:h-0",
3398
- children: /* @__PURE__ */ jsx57("div", { className: cn("flex flex-col", look === "row" && "pl-6", contentClassName), children })
3399
- }
3400
- )
3401
- ] });
3402
- }
3403
-
3404
3523
  // src/Tabs.tsx
3405
3524
  import { Tabs as BaseTabs } from "@base-ui/react/tabs";
3406
- import { jsx as jsx58, jsxs as jsxs41 } from "react/jsx-runtime";
3525
+ import { jsx as jsx59, jsxs as jsxs42 } from "react/jsx-runtime";
3407
3526
  function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
3408
- return /* @__PURE__ */ jsx58(
3527
+ return /* @__PURE__ */ jsx59(
3409
3528
  BaseTabs.Root,
3410
3529
  {
3411
3530
  value: active,
@@ -3413,14 +3532,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
3413
3532
  if (details.reason === "none") onChange(value);
3414
3533
  },
3415
3534
  className,
3416
- children: /* @__PURE__ */ jsx58(
3535
+ children: /* @__PURE__ */ jsx59(
3417
3536
  BaseTabs.List,
3418
3537
  {
3419
3538
  activateOnFocus: true,
3420
3539
  "aria-label": aria["aria-label"],
3421
3540
  "aria-labelledby": aria["aria-labelledby"],
3422
3541
  className: "flex items-center gap-2",
3423
- children: tabs.map((tab) => /* @__PURE__ */ jsxs41(
3542
+ children: tabs.map((tab) => /* @__PURE__ */ jsxs42(
3424
3543
  BaseTabs.Tab,
3425
3544
  {
3426
3545
  value: tab.id,
@@ -3433,9 +3552,9 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
3433
3552
  ),
3434
3553
  children: [
3435
3554
  tab.icon,
3436
- /* @__PURE__ */ jsxs41("span", { className: "flex items-baseline", children: [
3555
+ /* @__PURE__ */ jsxs42("span", { className: "flex items-baseline", children: [
3437
3556
  tab.label,
3438
- tab.count !== void 0 ? /* @__PURE__ */ jsx58("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
3557
+ tab.count !== void 0 ? /* @__PURE__ */ jsx59("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
3439
3558
  ] })
3440
3559
  ]
3441
3560
  },
@@ -3451,7 +3570,7 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
3451
3570
  import { createContext as createContext6, useContext as useContext6, useMemo as useMemo5 } from "react";
3452
3571
  import { Toast as BaseToast } from "@base-ui/react/toast";
3453
3572
  import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
3454
- import { jsx as jsx59, jsxs as jsxs42 } from "react/jsx-runtime";
3573
+ import { jsx as jsx60, jsxs as jsxs43 } from "react/jsx-runtime";
3455
3574
  var SURFACE_STYLES = {
3456
3575
  success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md leaf:bg-bg-inset leaf:border leaf:border-border-default leaf:shadow-md",
3457
3576
  brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md leaf:bg-bg-inset leaf:border leaf:border-border-default leaf:shadow-md",
@@ -3487,16 +3606,16 @@ var pillClassName = (type, hasAction, className) => cn(
3487
3606
  );
3488
3607
  function LeadingIcon({ type }) {
3489
3608
  const Icon = ICONS[type];
3490
- return /* @__PURE__ */ jsx59(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
3609
+ return /* @__PURE__ */ jsx60(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
3491
3610
  }
3492
3611
  function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
3493
3612
  const hasAction = !!(actionLabel && onAction);
3494
- return /* @__PURE__ */ jsxs42("div", { className: pillClassName(type, hasAction, className), children: [
3495
- /* @__PURE__ */ jsxs42("div", { className: "flex items-center gap-2 shrink-0", children: [
3496
- leadingIcon && /* @__PURE__ */ jsx59(LeadingIcon, { type }),
3497
- /* @__PURE__ */ jsx59("span", { className: LABEL_CLASSES, children: label })
3613
+ return /* @__PURE__ */ jsxs43("div", { className: pillClassName(type, hasAction, className), children: [
3614
+ /* @__PURE__ */ jsxs43("div", { className: "flex items-center gap-2 shrink-0", children: [
3615
+ leadingIcon && /* @__PURE__ */ jsx60(LeadingIcon, { type }),
3616
+ /* @__PURE__ */ jsx60("span", { className: LABEL_CLASSES, children: label })
3498
3617
  ] }),
3499
- hasAction && /* @__PURE__ */ jsx59(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
3618
+ hasAction && /* @__PURE__ */ jsx60(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
3500
3619
  ] });
3501
3620
  }
3502
3621
  var ToastContext = createContext6(null);
@@ -3517,9 +3636,9 @@ function ToastProvider({ children }) {
3517
3636
  }),
3518
3637
  [manager]
3519
3638
  );
3520
- return /* @__PURE__ */ jsx59(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs42(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
3639
+ return /* @__PURE__ */ jsx60(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs43(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
3521
3640
  children,
3522
- /* @__PURE__ */ jsx59(BaseToast.Portal, { children: /* @__PURE__ */ jsx59(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx59(ToastList, {}) }) })
3641
+ /* @__PURE__ */ jsx60(BaseToast.Portal, { children: /* @__PURE__ */ jsx60(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx60(ToastList, {}) }) })
3523
3642
  ] }) });
3524
3643
  }
3525
3644
  function ToastList() {
@@ -3527,25 +3646,25 @@ function ToastList() {
3527
3646
  return toasts.map((toast) => {
3528
3647
  const type = toast.type ?? "neutral";
3529
3648
  const { leadingIcon = true, actionLabel, onAction } = toast.data ?? {};
3530
- return /* @__PURE__ */ jsxs42(
3649
+ return /* @__PURE__ */ jsxs43(
3531
3650
  BaseToast.Root,
3532
3651
  {
3533
3652
  toast,
3534
3653
  swipeDirection: ["left", "down"],
3535
3654
  className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
3536
3655
  children: [
3537
- /* @__PURE__ */ jsxs42("div", { className: "flex items-center gap-2 shrink-0", children: [
3538
- leadingIcon && /* @__PURE__ */ jsx59(LeadingIcon, { type }),
3539
- /* @__PURE__ */ jsx59(BaseToast.Title, { render: /* @__PURE__ */ jsx59("span", {}), className: LABEL_CLASSES })
3656
+ /* @__PURE__ */ jsxs43("div", { className: "flex items-center gap-2 shrink-0", children: [
3657
+ leadingIcon && /* @__PURE__ */ jsx60(LeadingIcon, { type }),
3658
+ /* @__PURE__ */ jsx60(BaseToast.Title, { render: /* @__PURE__ */ jsx60("span", {}), className: LABEL_CLASSES })
3540
3659
  ] }),
3541
- actionLabel && /* @__PURE__ */ jsx59(
3660
+ actionLabel && /* @__PURE__ */ jsx60(
3542
3661
  BaseToast.Action,
3543
3662
  {
3544
3663
  onClick: () => {
3545
3664
  onAction?.();
3546
3665
  close(toast.id);
3547
3666
  },
3548
- render: /* @__PURE__ */ jsx59(Button, { variant: "outlined", size: "small", children: actionLabel })
3667
+ render: /* @__PURE__ */ jsx60(Button, { variant: "outlined", size: "small", children: actionLabel })
3549
3668
  }
3550
3669
  )
3551
3670
  ]
@@ -3623,6 +3742,7 @@ export {
3623
3742
  MenuSeparator,
3624
3743
  MenuSub,
3625
3744
  NavItem,
3745
+ NavTree,
3626
3746
  Panel,
3627
3747
  Person,
3628
3748
  PersonTrigger,