@estiva-app/ui 0.44.1 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/CollapsibleSection.d.ts +7 -1
  2. package/dist/CollapsibleSection.d.ts.map +1 -1
  3. package/dist/InlineChip.d.ts +1 -1
  4. package/dist/NavItem.d.ts +11 -1
  5. package/dist/NavItem.d.ts.map +1 -1
  6. package/dist/SectionHeader.d.ts +9 -1
  7. package/dist/SectionHeader.d.ts.map +1 -1
  8. package/dist/SelectionToolbar.d.ts +62 -0
  9. package/dist/SelectionToolbar.d.ts.map +1 -0
  10. package/dist/SuggestionMenu.d.ts +75 -0
  11. package/dist/SuggestionMenu.d.ts.map +1 -0
  12. package/dist/editor.d.ts +12 -0
  13. package/dist/editor.d.ts.map +1 -0
  14. package/dist/editor.js +357 -0
  15. package/dist/editor.js.map +7 -0
  16. package/dist/eslint/index.js +4 -3
  17. package/dist/eslint/index.js.map +2 -2
  18. package/dist/eslint/no-restyled-part.d.ts.map +1 -1
  19. package/dist/index.d.ts +2 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +274 -133
  22. package/dist/index.js.map +4 -4
  23. package/dist/looks.d.ts +3 -0
  24. package/dist/looks.d.ts.map +1 -1
  25. package/dist/registry/{app-YMABQII6.js → app-LDGOH6UW.js} +3 -3
  26. package/dist/registry/{build-3EANARLQ.js → build-P6X3PTZP.js} +6 -2
  27. package/dist/registry/build.d.ts +4 -0
  28. package/dist/registry/build.d.ts.map +1 -1
  29. package/dist/registry/{chunk-SIB44CES.js → chunk-P55P2QFD.js} +9 -4
  30. package/dist/registry/chunk-P55P2QFD.js.map +7 -0
  31. package/dist/registry/{chunk-EVJW26UR.js → chunk-TQ6UQER3.js} +10 -10
  32. package/dist/registry/chunk-TQ6UQER3.js.map +7 -0
  33. package/dist/registry/cli.js +2 -2
  34. package/dist/registry/index.js +2 -2
  35. package/dist/shortcuts.d.ts +27 -0
  36. package/dist/shortcuts.d.ts.map +1 -0
  37. package/dist/suggestionPopup.d.ts +41 -0
  38. package/dist/suggestionPopup.d.ts.map +1 -0
  39. package/package.json +27 -2
  40. package/registry.json +391 -11
  41. package/src/Chip.tsx +1 -1
  42. package/src/CollapsibleSection.mdx +5 -0
  43. package/src/CollapsibleSection.stories.tsx +5 -0
  44. package/src/CollapsibleSection.tsx +10 -3
  45. package/src/CommandPalette.tsx +1 -1
  46. package/src/InlineChip.test.tsx +1 -1
  47. package/src/InlineChip.tsx +1 -1
  48. package/src/NavItem.mdx +9 -0
  49. package/src/NavItem.stories.tsx +23 -0
  50. package/src/NavItem.tsx +56 -6
  51. package/src/Reaction.tsx +1 -1
  52. package/src/SectionHeader.mdx +9 -0
  53. package/src/SectionHeader.stories.tsx +15 -0
  54. package/src/SectionHeader.tsx +28 -7
  55. package/src/SelectionToolbar.mdx +78 -0
  56. package/src/SelectionToolbar.stories.tsx +63 -0
  57. package/src/SelectionToolbar.test.ts +105 -0
  58. package/src/SelectionToolbar.tsx +487 -0
  59. package/src/SuggestionMenu.mdx +107 -0
  60. package/src/SuggestionMenu.stories.tsx +202 -0
  61. package/src/SuggestionMenu.test.tsx +128 -0
  62. package/src/SuggestionMenu.tsx +189 -0
  63. package/src/editor.ts +11 -0
  64. package/src/eslint/no-rebuilt-behaviour.test.ts +1 -1
  65. package/src/eslint/no-rebuilt-behaviour.ts +2 -2
  66. package/src/eslint/no-restyled-part.ts +2 -1
  67. package/src/how.test.ts +1 -1
  68. package/src/index.ts +2 -0
  69. package/src/keptSelection.test.ts +67 -0
  70. package/src/looks.ts +4 -0
  71. package/src/registry/app.ts +8 -8
  72. package/src/registry/build.ts +10 -2
  73. package/src/registry/registry.test.ts +14 -9
  74. package/src/shortcuts.ts +40 -0
  75. package/src/suggestionPopup.tsx +119 -0
  76. package/stories/Choosing.mdx +2 -0
  77. package/tailwind-preset.js +1 -0
  78. package/tokens.css +19 -4
  79. package/dist/registry/chunk-EVJW26UR.js.map +0 -7
  80. package/dist/registry/chunk-SIB44CES.js.map +0 -7
  81. /package/dist/registry/{app-YMABQII6.js.map → app-LDGOH6UW.js.map} +0 -0
  82. /package/dist/registry/{build-3EANARLQ.js.map → build-P6X3PTZP.js.map} +0 -0
package/dist/index.js CHANGED
@@ -319,6 +319,8 @@ var FIELD_SHELL_CLASSES = "bg-bg-field border border-border-field shadow-field h
319
319
  var FLOATING_SURFACE_CLASSES = "rounded-lg border border-border-default bg-bg-elevated shadow-lg";
320
320
  var CHIP_TEXT_CLASSES = "text-chip signal:font-mono signal:text-small signal:font-semibold signal:tabular-nums";
321
321
  var BARE_INPUT_CLASSES = "bg-transparent text-text-primary placeholder:text-text-muted outline-none";
322
+ var SIDEBAR_ROW_CLASSES = "rounded-md transition-colors";
323
+ var SIDEBAR_ROW_TEXT_CLASSES = "text-text-secondary hover:text-text-primary";
322
324
 
323
325
  // src/Tooltip.tsx
324
326
  import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
@@ -1004,7 +1006,7 @@ function Checkbox({ checked, onChange, disabled: ownDisabled = false, label, row
1004
1006
  import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
1005
1007
  var typeStyles = {
1006
1008
  neutral: "bg-bg-inset text-text-primary",
1007
- brand: "bg-accent-muted text-accent-primary signal:border signal:border-accent-outline",
1009
+ brand: "bg-accent-muted text-accent-text signal:border signal:border-accent-outline",
1008
1010
  info: "bg-info-muted text-info-default signal:border signal:border-info-outline",
1009
1011
  warning: "bg-warning-muted text-warning-default signal:border signal:border-warning-outline signal:shadow-glow-warning",
1010
1012
  success: "bg-success-muted text-success-default signal:border signal:border-success-outline",
@@ -1922,7 +1924,7 @@ function CommandPaletteAnswer({ children, note }) {
1922
1924
  const paragraphs = children.split(/\n\s*\n/).filter((p) => p.trim() !== "");
1923
1925
  return /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-2", children: [
1924
1926
  paragraphs.map((paragraph, i) => /* @__PURE__ */ jsx26("p", { className: "whitespace-pre-wrap text-body-2 text-text-primary", children: paragraph.split(/\s*(\[\d+\])/).map(
1925
- (part, j) => /^\[\d+\]$/.test(part) ? /* @__PURE__ */ jsx26("sup", { className: "ml-0.5 font-mono text-small text-accent-primary", children: part.slice(1, -1) }, j) : part
1927
+ (part, j) => /^\[\d+\]$/.test(part) ? /* @__PURE__ */ jsx26("sup", { className: "ml-0.5 font-mono text-small text-accent-text", children: part.slice(1, -1) }, j) : part
1926
1928
  ) }, i)),
1927
1929
  note && /* @__PURE__ */ jsx26(FieldLine, { children: note })
1928
1930
  ] });
@@ -1947,7 +1949,7 @@ var INLINE_CHIP_TONE_CLASSES = {
1947
1949
  /** A thing or a place — anything that is not a person. */
1948
1950
  neutral: "bg-bg-active text-text-primary",
1949
1951
  /** A person. */
1950
- person: "bg-accent-muted text-accent-primary",
1952
+ person: "bg-accent-muted text-accent-text",
1951
1953
  /** A person, called urgently. */
1952
1954
  urgent: "bg-warning-muted text-warning-default",
1953
1955
  /**
@@ -2792,32 +2794,61 @@ function Breadcrumb({ items, className }) {
2792
2794
  }
2793
2795
 
2794
2796
  // src/NavItem.tsx
2797
+ import { IconDotsVertical } from "@tabler/icons-react";
2795
2798
  import { jsx as jsx43, jsxs as jsxs29 } from "react/jsx-runtime";
2796
- function NavItem({ label, href, count, countLabel, active = false, icon, className, ...props }) {
2797
- return (
2798
- // @estiva-escape(no-copied-look): N5 (Katerina, 24 September: record only): a row that fills on hover, as PersonTrigger's row also does
2799
- /* @__PURE__ */ jsxs29(
2800
- "a",
2799
+ function NavItem({ label, href, count, countLabel, active = false, icon, menu, menuLabel, className, ...props }) {
2800
+ const row = /* @__PURE__ */ jsxs29(
2801
+ "a",
2802
+ {
2803
+ href,
2804
+ "aria-current": active ? "page" : void 0,
2805
+ className: cn(
2806
+ // shrink-0: the row keeps its 32px inside an overflowing flex column
2807
+ // — without it the list compresses instead of scrolling (the missing-
2808
+ // shrink-0 family; Katerina, 2026-09-02).
2809
+ "flex h-8 min-w-0 shrink-0 items-center gap-2 px-2 text-body-2",
2810
+ SIDEBAR_ROW_CLASSES,
2811
+ active ? "bg-bg-active text-text-primary" : cn(SIDEBAR_ROW_TEXT_CLASSES, "hover:bg-bg-hover"),
2812
+ // 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",
2815
+ className
2816
+ ),
2817
+ ...props,
2818
+ children: [
2819
+ icon && /* @__PURE__ */ jsx43("span", { className: "flex shrink-0 items-center", children: icon }),
2820
+ /* @__PURE__ */ jsx43("span", { className: "flex-1 truncate", children: label }),
2821
+ count ? /* @__PURE__ */ jsx43(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx43(
2822
+ "span",
2823
+ {
2824
+ className: cn(
2825
+ "min-w-4 shrink-0 text-center font-mono text-caption tabular-nums text-text-muted",
2826
+ // 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"
2828
+ ),
2829
+ children: count
2830
+ }
2831
+ ) }) : menu != null ? (
2832
+ // No count, but a menu: the count's place is kept free, so a long
2833
+ // label truncates before the ⋮ instead of running under it.
2834
+ /* @__PURE__ */ jsx43("span", { "aria-hidden": "true", className: "min-w-4 shrink-0" })
2835
+ ) : null
2836
+ ]
2837
+ }
2838
+ );
2839
+ if (menu == null) return row;
2840
+ const name = menuLabel ?? `More options for ${label}`;
2841
+ return /* @__PURE__ */ jsxs29("div", { className: "group/nav relative shrink-0", children: [
2842
+ 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(
2844
+ Menu,
2801
2845
  {
2802
- href,
2803
- "aria-current": active ? "page" : void 0,
2804
- className: cn(
2805
- // shrink-0: the row keeps its 32px inside an overflowing flex column
2806
- // — without it the list compresses instead of scrolling (the missing-
2807
- // shrink-0 family; Katerina, 2026-09-02).
2808
- "flex h-8 min-w-0 shrink-0 items-center gap-2 rounded-md px-2 text-body-2 transition-colors",
2809
- active ? "bg-bg-active text-text-primary" : "text-text-secondary hover:bg-bg-hover hover:text-text-primary",
2810
- className
2811
- ),
2812
- ...props,
2813
- children: [
2814
- icon && /* @__PURE__ */ jsx43("span", { className: "flex shrink-0 items-center", children: icon }),
2815
- /* @__PURE__ */ jsx43("span", { className: "flex-1 truncate", children: label }),
2816
- count ? /* @__PURE__ */ jsx43(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx43("span", { className: "min-w-4 shrink-0 text-center font-mono text-caption tabular-nums text-text-muted", children: count }) }) : null
2817
- ]
2846
+ align: "right",
2847
+ trigger: /* @__PURE__ */ jsx43(IconButton, { tooltip: "More options", "aria-label": name, children: /* @__PURE__ */ jsx43(IconDotsVertical, { size: 16, stroke: 1.5 }) }),
2848
+ children: menu
2818
2849
  }
2819
- )
2820
- );
2850
+ ) })
2851
+ ] });
2821
2852
  }
2822
2853
 
2823
2854
  // src/Popover.tsx
@@ -2875,11 +2906,97 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2875
2906
  );
2876
2907
  }
2877
2908
 
2909
+ // 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";
2912
+ function SuggestionMenu({ rect, editorElement, ariaLabel, width, maxHeight, sections, itemKey, row, onSelect, handle }) {
2913
+ const shown = useMemo4(() => sections.filter((section) => section.items.length > 0), [sections]);
2914
+ const items = useMemo4(() => shown.flatMap((section) => section.items), [shown]);
2915
+ const keys = items.map(itemKey).join("\n");
2916
+ const [highlight, setHighlight] = useState7(0);
2917
+ const base = useId();
2918
+ const listboxId = `${base}-list`;
2919
+ useEffect4(() => setHighlight(0), [keys]);
2920
+ useImperativeHandle(handle, () => ({
2921
+ // The editor hands its arrow keys to this list: Base UI's lists need a text field of their own, and an editor is not one.
2922
+ onKeyDown: (event) => {
2923
+ if (!items.length) return false;
2924
+ if (event.key === "ArrowDown") {
2925
+ setHighlight((h) => (h + 1) % items.length);
2926
+ return true;
2927
+ }
2928
+ if (event.key === "ArrowUp") {
2929
+ setHighlight((h) => (h - 1 + items.length) % items.length);
2930
+ return true;
2931
+ }
2932
+ if (event.key === "Enter") {
2933
+ const item = items[highlight];
2934
+ if (item !== void 0) onSelect(item);
2935
+ return true;
2936
+ }
2937
+ return false;
2938
+ }
2939
+ }), [items, highlight, onSelect]);
2940
+ const open = rect !== null && items.length > 0;
2941
+ useEffect4(() => {
2942
+ if (!editorElement || !open) return;
2943
+ editorElement.setAttribute("aria-autocomplete", "list");
2944
+ editorElement.setAttribute("aria-haspopup", "listbox");
2945
+ editorElement.setAttribute("aria-controls", listboxId);
2946
+ return () => {
2947
+ for (const name of ["aria-autocomplete", "aria-haspopup", "aria-controls", "aria-activedescendant"]) editorElement.removeAttribute(name);
2948
+ };
2949
+ }, [editorElement, open, listboxId]);
2950
+ useEffect4(() => {
2951
+ if (!editorElement || !open) return;
2952
+ editorElement.setAttribute("aria-activedescendant", `${base}-${highlight}`);
2953
+ }, [editorElement, open, base, highlight]);
2954
+ const scrollRef = useCallback3((el) => {
2955
+ el?.scrollIntoView({ block: "nearest" });
2956
+ }, []);
2957
+ if (items.length === 0) return null;
2958
+ const drawRow = (item) => {
2959
+ const index = items.indexOf(item);
2960
+ const selected = index === highlight;
2961
+ const { label, description, leading, shortcut, hint, size } = row(item);
2962
+ return (
2963
+ // 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(
2965
+ MenuItem,
2966
+ {
2967
+ role: "option",
2968
+ id: `${base}-${index}`,
2969
+ "aria-selected": selected,
2970
+ tabIndex: -1,
2971
+ ref: selected ? scrollRef : void 0,
2972
+ size,
2973
+ label,
2974
+ description,
2975
+ leading,
2976
+ shortcut,
2977
+ hint,
2978
+ selected,
2979
+ onMouseEnter: () => setHighlight(index),
2980
+ onMouseDown: (event) => {
2981
+ event.preventDefault();
2982
+ onSelect(item);
2983
+ }
2984
+ },
2985
+ itemKey(item)
2986
+ )
2987
+ );
2988
+ };
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)
2992
+ ] }, section.label ?? i)) }) });
2993
+ }
2994
+
2878
2995
  // src/Toolbar.tsx
2879
2996
  import { Toolbar as BaseToolbar } from "@base-ui/react/toolbar";
2880
- import { jsx as jsx45 } from "react/jsx-runtime";
2997
+ import { jsx as jsx46 } from "react/jsx-runtime";
2881
2998
  function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocus = true, surface = true, children, className }) {
2882
- const strip = /* @__PURE__ */ jsx45(
2999
+ const strip = /* @__PURE__ */ jsx46(
2883
3000
  BaseToolbar.Root,
2884
3001
  {
2885
3002
  "aria-label": ariaLabel,
@@ -2890,27 +3007,27 @@ function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocu
2890
3007
  }
2891
3008
  );
2892
3009
  if (!surface) return strip;
2893
- return /* @__PURE__ */ jsx45(MenuPanel, { className: "w-fit p-1", children: strip });
3010
+ return /* @__PURE__ */ jsx46(MenuPanel, { className: "w-fit p-1", children: strip });
2894
3011
  }
2895
3012
  function ToolbarButton({ ref, disabled, disabledReason, ...props }) {
2896
- return /* @__PURE__ */ jsx45(
3013
+ return /* @__PURE__ */ jsx46(
2897
3014
  BaseToolbar.Button,
2898
3015
  {
2899
3016
  ref,
2900
3017
  disabled: disabled || !!disabledReason,
2901
3018
  focusableWhenDisabled: true,
2902
- render: /* @__PURE__ */ jsx45(IconButton, { disabled, disabledReason, ...props })
3019
+ render: /* @__PURE__ */ jsx46(IconButton, { disabled, disabledReason, ...props })
2903
3020
  }
2904
3021
  );
2905
3022
  }
2906
3023
  function ToolbarLink({ ref, href, ...props }) {
2907
- return /* @__PURE__ */ jsx45(BaseToolbar.Link, { ref, render: /* @__PURE__ */ jsx45(IconButton, { href, ...props }) });
3024
+ return /* @__PURE__ */ jsx46(BaseToolbar.Link, { ref, render: /* @__PURE__ */ jsx46(IconButton, { href, ...props }) });
2908
3025
  }
2909
3026
  function ToolbarInput({ size, ...props }) {
2910
- return /* @__PURE__ */ jsx45(BaseToolbar.Input, { render: /* @__PURE__ */ jsx45(TextInput, { size }), ...props });
3027
+ return /* @__PURE__ */ jsx46(BaseToolbar.Input, { render: /* @__PURE__ */ jsx46(TextInput, { size }), ...props });
2911
3028
  }
2912
3029
  function ToolbarSeparator({ className }) {
2913
- return /* @__PURE__ */ jsx45(
3030
+ return /* @__PURE__ */ jsx46(
2914
3031
  BaseToolbar.Separator,
2915
3032
  {
2916
3033
  orientation: "vertical",
@@ -2920,9 +3037,9 @@ function ToolbarSeparator({ className }) {
2920
3037
  }
2921
3038
 
2922
3039
  // src/ReactionPicker.tsx
2923
- import { jsx as jsx46 } from "react/jsx-runtime";
3040
+ import { jsx as jsx47 } from "react/jsx-runtime";
2924
3041
  function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reactions", surface = true, className }) {
2925
- return /* @__PURE__ */ jsx46(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
3042
+ return /* @__PURE__ */ jsx47(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
2926
3043
  /*
2927
3044
  A `ToolbarButton`, not a button in a tooltip wrapper. The wrapper
2928
3045
  would become the toolbar's item and the button inside it would never
@@ -2932,14 +3049,14 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
2932
3049
  The tooltip names it for a pointer, `aria-label` for everything else,
2933
3050
  and both say the meaning rather than the glyph.
2934
3051
  */
2935
- /* @__PURE__ */ jsx46(
3052
+ /* @__PURE__ */ jsx47(
2936
3053
  ToolbarButton,
2937
3054
  {
2938
3055
  "aria-label": option.label,
2939
3056
  tooltip: option.label,
2940
3057
  onClick: () => onSelect(option.emoji),
2941
3058
  className: "size-7",
2942
- children: /* @__PURE__ */ jsx46("span", { "aria-hidden": "true", className: "text-h3 leading-none", children: option.emoji })
3059
+ children: /* @__PURE__ */ jsx47("span", { "aria-hidden": "true", className: "text-h3 leading-none", children: option.emoji })
2943
3060
  },
2944
3061
  option.emoji
2945
3062
  )
@@ -2948,23 +3065,23 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
2948
3065
 
2949
3066
  // src/PreviewCard.tsx
2950
3067
  import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
2951
- import { jsx as jsx47, jsxs as jsxs31 } from "react/jsx-runtime";
3068
+ import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
2952
3069
  var GAP6 = 12;
2953
3070
  var VIEWPORT_PAD6 = 8;
2954
3071
  var OPEN_DELAY2 = 350;
2955
3072
  var CLOSE_DELAY = 200;
2956
3073
  function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, contentClassName, wrapperClassName }) {
2957
- return /* @__PURE__ */ jsxs31(BasePreviewCard.Root, { children: [
2958
- /* @__PURE__ */ jsx47(
3074
+ return /* @__PURE__ */ jsxs32(BasePreviewCard.Root, { children: [
3075
+ /* @__PURE__ */ jsx48(
2959
3076
  BasePreviewCard.Trigger,
2960
3077
  {
2961
3078
  delay,
2962
3079
  closeDelay,
2963
- render: /* @__PURE__ */ jsx47("span", { className: cn("inline-flex", wrapperClassName) }),
3080
+ render: /* @__PURE__ */ jsx48("span", { className: cn("inline-flex", wrapperClassName) }),
2964
3081
  children
2965
3082
  }
2966
3083
  ),
2967
- /* @__PURE__ */ jsx47(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx47(
3084
+ /* @__PURE__ */ jsx48(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx48(
2968
3085
  BasePreviewCard.Positioner,
2969
3086
  {
2970
3087
  side,
@@ -2972,12 +3089,12 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
2972
3089
  sideOffset: GAP6,
2973
3090
  collisionPadding: VIEWPORT_PAD6,
2974
3091
  className: "z-50 data-[anchor-hidden]:hidden",
2975
- children: /* @__PURE__ */ jsx47(
3092
+ children: /* @__PURE__ */ jsx48(
2976
3093
  BasePreviewCard.Popup,
2977
3094
  {
2978
3095
  className: cn("w-[360px] p-0 outline-none", className),
2979
- render: /* @__PURE__ */ jsx47(MenuPanel, {}),
2980
- children: /* @__PURE__ */ jsx47(ScrollArea, { viewportClassName: "max-h-[min(300px,var(--available-height))]", contentClassName: cn("flex flex-col gap-3 p-3", contentClassName), children: content })
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 })
2981
3098
  }
2982
3099
  )
2983
3100
  }
@@ -2986,15 +3103,15 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
2986
3103
  }
2987
3104
 
2988
3105
  // src/Rail.tsx
2989
- import { jsx as jsx48 } from "react/jsx-runtime";
3106
+ import { jsx as jsx49 } from "react/jsx-runtime";
2990
3107
  function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
2991
- return /* @__PURE__ */ jsx48("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
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 });
2992
3109
  }
2993
3110
 
2994
3111
  // src/RailItem.tsx
2995
- import { jsx as jsx49, jsxs as jsxs32 } from "react/jsx-runtime";
3112
+ import { jsx as jsx50, jsxs as jsxs33 } from "react/jsx-runtime";
2996
3113
  function RailItem({ href, icon, label, active = false, className, ...props }) {
2997
- return /* @__PURE__ */ jsxs32(
3114
+ return /* @__PURE__ */ jsxs33(
2998
3115
  "a",
2999
3116
  {
3000
3117
  href,
@@ -3002,14 +3119,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
3002
3119
  className: cn("group flex h-12 w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
3003
3120
  ...props,
3004
3121
  children: [
3005
- /* @__PURE__ */ jsx49(
3122
+ /* @__PURE__ */ jsx50(
3006
3123
  "div",
3007
3124
  {
3008
3125
  className: cn(
3009
3126
  "flex items-center justify-center rounded-lg p-2 transition-colors",
3010
3127
  active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
3011
3128
  ),
3012
- children: /* @__PURE__ */ jsx49(
3129
+ children: /* @__PURE__ */ jsx50(
3013
3130
  "span",
3014
3131
  {
3015
3132
  className: cn(
@@ -3021,14 +3138,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
3021
3138
  )
3022
3139
  }
3023
3140
  ),
3024
- /* @__PURE__ */ jsx49("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
3141
+ /* @__PURE__ */ jsx50("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
3025
3142
  ]
3026
3143
  }
3027
3144
  );
3028
3145
  }
3029
3146
 
3030
3147
  // src/Property.tsx
3031
- import { jsx as jsx50, jsxs as jsxs33 } from "react/jsx-runtime";
3148
+ import { jsx as jsx51, jsxs as jsxs34 } from "react/jsx-runtime";
3032
3149
  var VALUE_CLASSES = "contents";
3033
3150
  function Property({ label, layout = "row", children, className }) {
3034
3151
  if (layout === "stacked") {
@@ -3036,25 +3153,25 @@ function Property({ label, layout = "row", children, className }) {
3036
3153
  // gap-3 — the one label-above-content distance (Katerina, 2026-09-01):
3037
3154
  // Peek's topic-details sections already sit at 12px, Ship's rail was
3038
3155
  // 6px, and unifying means the bigger, calmer one.
3039
- /* @__PURE__ */ jsxs33("dl", { className: cn("flex flex-col gap-3", className), children: [
3040
- /* @__PURE__ */ jsx50("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
3041
- /* @__PURE__ */ jsx50("dd", { className: VALUE_CLASSES, children })
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 })
3042
3159
  ] })
3043
3160
  );
3044
3161
  }
3045
- return /* @__PURE__ */ jsxs33("dl", { className: cn("flex items-center gap-2", className), children: [
3046
- /* @__PURE__ */ jsx50("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
3047
- /* @__PURE__ */ jsx50("dd", { className: VALUE_CLASSES, children })
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 })
3048
3165
  ] });
3049
3166
  }
3050
3167
 
3051
3168
  // src/Reaction.tsx
3052
3169
  import { Toggle } from "@base-ui/react/toggle";
3053
- import { jsx as jsx51, jsxs as jsxs34 } from "react/jsx-runtime";
3170
+ import { jsx as jsx52, jsxs as jsxs35 } from "react/jsx-runtime";
3054
3171
  function Reaction({ emoji, count, pressed = false, className, ...props }) {
3055
3172
  return (
3056
3173
  // @estiva-escape(no-copied-look): W1 (Katerina, 24 September: leave alone): a reaction pill shares four words with a field's box by coincidence
3057
- /* @__PURE__ */ jsxs34(
3174
+ /* @__PURE__ */ jsxs35(
3058
3175
  Toggle,
3059
3176
  {
3060
3177
  pressed,
@@ -3070,14 +3187,14 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
3070
3187
  (Katerina, 2026-09-08). The number reads in the text colour
3071
3188
  there; the accent keeps the edge and the fill. Signal keeps
3072
3189
  Peek's blue-on-wash, which reads. */
3073
- "border-accent-primary bg-accent-muted text-accent-primary hover:border-accent-hover ship:text-text-primary"
3190
+ "border-accent-primary bg-accent-muted text-accent-text hover:border-accent-hover ship:text-text-primary"
3074
3191
  ) : "border-border-default bg-bg-inset text-text-primary hover:border-border-strong hover:bg-bg-hover",
3075
3192
  className
3076
3193
  ),
3077
3194
  ...props,
3078
3195
  children: [
3079
- /* @__PURE__ */ jsx51("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
3080
- /* @__PURE__ */ jsx51("span", { className: CHIP_TEXT_CLASSES, children: count })
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 })
3081
3198
  ]
3082
3199
  }
3083
3200
  )
@@ -3087,9 +3204,9 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
3087
3204
  // src/SearchInput.tsx
3088
3205
  import "react";
3089
3206
  import { Input as Input3 } from "@base-ui/react/input";
3090
- import { jsx as jsx52, jsxs as jsxs35 } from "react/jsx-runtime";
3207
+ import { jsx as jsx53, jsxs as jsxs36 } from "react/jsx-runtime";
3091
3208
  function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
3092
- return /* @__PURE__ */ jsxs35(
3209
+ return /* @__PURE__ */ jsxs36(
3093
3210
  "div",
3094
3211
  {
3095
3212
  className: cn(
@@ -3101,7 +3218,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
3101
3218
  className
3102
3219
  ),
3103
3220
  children: [
3104
- /* @__PURE__ */ jsx52(
3221
+ /* @__PURE__ */ jsx53(
3105
3222
  Input3,
3106
3223
  {
3107
3224
  className: cn("flex-1 min-w-0 text-input-value", BARE_INPUT_CLASSES),
@@ -3109,7 +3226,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
3109
3226
  ...props
3110
3227
  }
3111
3228
  ),
3112
- shortcut && /* @__PURE__ */ jsx52(Kbd, { children: shortcut })
3229
+ shortcut && /* @__PURE__ */ jsx53(Kbd, { children: shortcut })
3113
3230
  ]
3114
3231
  }
3115
3232
  );
@@ -3118,50 +3235,58 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
3118
3235
  // src/SectionHeader.tsx
3119
3236
  import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
3120
3237
  import { useRender } from "@base-ui/react/use-render";
3121
- import { Fragment as Fragment11, jsx as jsx53, jsxs as jsxs36 } from "react/jsx-runtime";
3122
- function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", hover = "fill", render, className }) {
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";
3123
3241
  const titleElement = useRender({
3124
- render: render ?? (chevron ? /* @__PURE__ */ jsx53("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx53("span", {})),
3242
+ render: render ?? (chevron ? /* @__PURE__ */ jsx54("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx54("span", {})),
3125
3243
  props: {
3126
3244
  // `text-left`: a button centres its text. `h-full` and `flex-1`: the
3127
3245
  // whole row up to the actions is the hit target, as it was when the
3128
3246
  // row itself carried the click.
3129
- className: "flex h-full min-w-0 flex-1 items-center gap-1 text-left",
3130
- children: /* @__PURE__ */ jsxs36(Fragment11, { children: [
3131
- chevron && /* @__PURE__ */ jsx53(
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(
3132
3250
  IconChevronRight2,
3133
3251
  {
3134
- size: 12,
3252
+ size: row ? 16 : 12,
3135
3253
  stroke: 1.5,
3136
- className: cn("shrink-0 text-text-secondary transition-transform duration-150", isExpanded && "rotate-90")
3254
+ className: cn("shrink-0 transition-transform duration-150", !row && "text-text-secondary", isExpanded && "rotate-90")
3137
3255
  }
3138
3256
  ),
3139
- /* @__PURE__ */ jsx53(SectionLabel, { children: title })
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 })
3140
3261
  ] })
3141
3262
  }
3142
3263
  });
3143
- return /* @__PURE__ */ jsxs36(
3264
+ return /* @__PURE__ */ jsxs37(
3144
3265
  "div",
3145
3266
  {
3146
3267
  className: cn(
3147
- "group flex h-[32px] shrink-0 items-center gap-1 rounded-lg px-2 transition-colors",
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",
3148
3272
  // The fill says "this does something": a row with a toggle or actions
3149
3273
  // lights up, a fixed heading over rows does not (2026-09-09, the
3150
3274
  // Sidebar's fixed group).
3151
- hover === "fill" && (chevron || actions && actions.length > 0) && "hover:bg-bg-hover",
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",
3152
3277
  className
3153
3278
  ),
3154
3279
  children: [
3155
3280
  titleElement,
3156
- trailing != null && /* @__PURE__ */ jsx53("div", { className: "flex shrink-0 items-center", children: trailing }),
3157
- actions && actions.length > 0 && /* @__PURE__ */ jsx53(
3281
+ trailing != null && /* @__PURE__ */ jsx54("div", { className: "flex shrink-0 items-center", children: trailing }),
3282
+ actions && actions.length > 0 && /* @__PURE__ */ jsx54(
3158
3283
  "div",
3159
3284
  {
3160
3285
  className: cn(
3161
3286
  "-mr-1 flex shrink-0 items-center gap-1",
3162
3287
  showActions === "hover" && "opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100"
3163
3288
  ),
3164
- children: actions.map((action) => /* @__PURE__ */ jsx53(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
3289
+ children: actions.map((action) => /* @__PURE__ */ jsx54(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
3165
3290
  }
3166
3291
  )
3167
3292
  ]
@@ -3170,35 +3295,35 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
3170
3295
  }
3171
3296
 
3172
3297
  // src/Panel.tsx
3173
- import { jsx as jsx54, jsxs as jsxs37 } from "react/jsx-runtime";
3298
+ import { jsx as jsx55, jsxs as jsxs38 } from "react/jsx-runtime";
3174
3299
  function Frame({ title, chevron = false, actions, children, footer, bodyClassName, bodyRef, onBodyScroll, className, broken = false }) {
3175
- return /* @__PURE__ */ jsxs37("div", { className: cn("flex h-full min-h-0 flex-1 flex-col", className), children: [
3176
- /* @__PURE__ */ jsx54(ContainerHeader, { title, chevron, actions }),
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 }),
3177
3302
  broken ? (
3178
3303
  // The message takes the room the body had and centres itself in it.
3179
- /* @__PURE__ */ jsx54("div", { className: "flex min-h-0 flex-1 flex-col px-4", children })
3180
- ) : /* @__PURE__ */ jsx54(ScrollArea, { className: "min-h-0 flex-1", contentClassName: bodyClassName, viewportRef: bodyRef, onScroll: onBodyScroll, children }),
3181
- !broken && footer && /* @__PURE__ */ jsx54("div", { className: "shrink-0", children: footer })
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 })
3182
3307
  ] });
3183
3308
  }
3184
3309
  function Panel(props) {
3185
- return /* @__PURE__ */ jsx54(
3310
+ return /* @__PURE__ */ jsx55(
3186
3311
  ErrorBoundary,
3187
3312
  {
3188
3313
  label: "panel",
3189
3314
  frame: (message) => (
3190
3315
  // Only the name comes back with the message: the actions and the footer may be what threw.
3191
- /* @__PURE__ */ jsx54(Frame, { title: props.title, chevron: props.chevron, className: props.className, broken: true, children: message })
3316
+ /* @__PURE__ */ jsx55(Frame, { title: props.title, chevron: props.chevron, className: props.className, broken: true, children: message })
3192
3317
  ),
3193
- children: /* @__PURE__ */ jsx54(Frame, { ...props })
3318
+ children: /* @__PURE__ */ jsx55(Frame, { ...props })
3194
3319
  }
3195
3320
  );
3196
3321
  }
3197
3322
 
3198
3323
  // src/ListColumn.tsx
3199
- import { jsx as jsx55, jsxs as jsxs38 } from "react/jsx-runtime";
3324
+ import { jsx as jsx56, jsxs as jsxs39 } from "react/jsx-runtime";
3200
3325
  function Column({ title, chevron = false, actions, above, collapsed = false, children, className, broken = false }) {
3201
- return /* @__PURE__ */ jsxs38(
3326
+ return /* @__PURE__ */ jsxs39(
3202
3327
  "div",
3203
3328
  {
3204
3329
  className: cn(
@@ -3209,34 +3334,34 @@ function Column({ title, chevron = false, actions, above, collapsed = false, chi
3209
3334
  ),
3210
3335
  "data-collapsed": collapsed || void 0,
3211
3336
  children: [
3212
- /* @__PURE__ */ jsx55(ContainerHeader, { title, chevron, actions }),
3337
+ /* @__PURE__ */ jsx56(ContainerHeader, { title, chevron, actions }),
3213
3338
  above,
3214
3339
  broken ? (
3215
3340
  // The message takes the room the list had and centres itself in it (Katerina, 19 September).
3216
- /* @__PURE__ */ jsx55("div", { className: "flex min-h-0 flex-1 flex-col px-3", children })
3217
- ) : /* @__PURE__ */ jsx55(ScrollArea, { className: "flex-1", contentClassName: "flex flex-col gap-0.5 px-3 pt-4 pb-3", children })
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 })
3218
3343
  ]
3219
3344
  }
3220
3345
  );
3221
3346
  }
3222
3347
  function ListColumn(props) {
3223
- return /* @__PURE__ */ jsx55(
3348
+ return /* @__PURE__ */ jsx56(
3224
3349
  ErrorBoundary,
3225
3350
  {
3226
3351
  label: "list panel",
3227
3352
  frame: (message) => (
3228
3353
  // Only the name comes back with the message: the actions and the row above may be what threw.
3229
- /* @__PURE__ */ jsx55(Column, { title: props.title, chevron: props.chevron, collapsed: props.collapsed, className: props.className, broken: true, children: message })
3354
+ /* @__PURE__ */ jsx56(Column, { title: props.title, chevron: props.chevron, collapsed: props.collapsed, className: props.className, broken: true, children: message })
3230
3355
  ),
3231
- children: /* @__PURE__ */ jsx55(Column, { ...props })
3356
+ children: /* @__PURE__ */ jsx56(Column, { ...props })
3232
3357
  }
3233
3358
  );
3234
3359
  }
3235
3360
 
3236
3361
  // src/CollapsibleSection.tsx
3237
- import { useState as useState7 } from "react";
3362
+ import { useState as useState8 } from "react";
3238
3363
  import { Collapsible } from "@base-ui/react/collapsible";
3239
- import { jsx as jsx56, jsxs as jsxs39 } from "react/jsx-runtime";
3364
+ import { jsx as jsx57, jsxs as jsxs40 } from "react/jsx-runtime";
3240
3365
  var OPEN = "open";
3241
3366
  var CLOSED = "closed";
3242
3367
  function readStored(key) {
@@ -3255,22 +3380,22 @@ function writeStored(key, open) {
3255
3380
  } catch {
3256
3381
  }
3257
3382
  }
3258
- function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenChange, storageKey, trailing, actions, showActions, children, className, contentClassName }) {
3259
- const [openState, setOpenState] = useState7(() => readStored(storageKey) ?? defaultOpen);
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);
3260
3385
  const open = openProp ?? openState;
3261
3386
  const setOpen = (next) => {
3262
3387
  setOpenState(next);
3263
3388
  writeStored(storageKey, next);
3264
3389
  onOpenChange?.(next);
3265
3390
  };
3266
- return /* @__PURE__ */ jsxs39(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
3267
- /* @__PURE__ */ jsx56(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx56(Collapsible.Trigger, {}) }),
3268
- /* @__PURE__ */ jsx56(
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(
3269
3394
  Collapsible.Panel,
3270
3395
  {
3271
3396
  hiddenUntilFound: true,
3272
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",
3273
- children: /* @__PURE__ */ jsx56("div", { className: cn("flex flex-col", contentClassName), children })
3398
+ children: /* @__PURE__ */ jsx57("div", { className: cn("flex flex-col", look === "row" && "pl-6", contentClassName), children })
3274
3399
  }
3275
3400
  )
3276
3401
  ] });
@@ -3278,9 +3403,9 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
3278
3403
 
3279
3404
  // src/Tabs.tsx
3280
3405
  import { Tabs as BaseTabs } from "@base-ui/react/tabs";
3281
- import { jsx as jsx57, jsxs as jsxs40 } from "react/jsx-runtime";
3406
+ import { jsx as jsx58, jsxs as jsxs41 } from "react/jsx-runtime";
3282
3407
  function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
3283
- return /* @__PURE__ */ jsx57(
3408
+ return /* @__PURE__ */ jsx58(
3284
3409
  BaseTabs.Root,
3285
3410
  {
3286
3411
  value: active,
@@ -3288,14 +3413,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
3288
3413
  if (details.reason === "none") onChange(value);
3289
3414
  },
3290
3415
  className,
3291
- children: /* @__PURE__ */ jsx57(
3416
+ children: /* @__PURE__ */ jsx58(
3292
3417
  BaseTabs.List,
3293
3418
  {
3294
3419
  activateOnFocus: true,
3295
3420
  "aria-label": aria["aria-label"],
3296
3421
  "aria-labelledby": aria["aria-labelledby"],
3297
3422
  className: "flex items-center gap-2",
3298
- children: tabs.map((tab) => /* @__PURE__ */ jsxs40(
3423
+ children: tabs.map((tab) => /* @__PURE__ */ jsxs41(
3299
3424
  BaseTabs.Tab,
3300
3425
  {
3301
3426
  value: tab.id,
@@ -3308,9 +3433,9 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
3308
3433
  ),
3309
3434
  children: [
3310
3435
  tab.icon,
3311
- /* @__PURE__ */ jsxs40("span", { className: "flex items-baseline", children: [
3436
+ /* @__PURE__ */ jsxs41("span", { className: "flex items-baseline", children: [
3312
3437
  tab.label,
3313
- tab.count !== void 0 ? /* @__PURE__ */ jsx57("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
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
3314
3439
  ] })
3315
3440
  ]
3316
3441
  },
@@ -3323,10 +3448,10 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
3323
3448
  }
3324
3449
 
3325
3450
  // src/Toast.tsx
3326
- import { createContext as createContext6, useContext as useContext6, useMemo as useMemo4 } from "react";
3451
+ import { createContext as createContext6, useContext as useContext6, useMemo as useMemo5 } from "react";
3327
3452
  import { Toast as BaseToast } from "@base-ui/react/toast";
3328
3453
  import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
3329
- import { jsx as jsx58, jsxs as jsxs41 } from "react/jsx-runtime";
3454
+ import { jsx as jsx59, jsxs as jsxs42 } from "react/jsx-runtime";
3330
3455
  var SURFACE_STYLES = {
3331
3456
  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",
3332
3457
  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",
@@ -3362,23 +3487,23 @@ var pillClassName = (type, hasAction, className) => cn(
3362
3487
  );
3363
3488
  function LeadingIcon({ type }) {
3364
3489
  const Icon = ICONS[type];
3365
- return /* @__PURE__ */ jsx58(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
3490
+ return /* @__PURE__ */ jsx59(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
3366
3491
  }
3367
3492
  function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
3368
3493
  const hasAction = !!(actionLabel && onAction);
3369
- return /* @__PURE__ */ jsxs41("div", { className: pillClassName(type, hasAction, className), children: [
3370
- /* @__PURE__ */ jsxs41("div", { className: "flex items-center gap-2 shrink-0", children: [
3371
- leadingIcon && /* @__PURE__ */ jsx58(LeadingIcon, { type }),
3372
- /* @__PURE__ */ jsx58("span", { className: LABEL_CLASSES, children: label })
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 })
3373
3498
  ] }),
3374
- hasAction && /* @__PURE__ */ jsx58(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
3499
+ hasAction && /* @__PURE__ */ jsx59(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
3375
3500
  ] });
3376
3501
  }
3377
3502
  var ToastContext = createContext6(null);
3378
3503
  var VISIBLE_TOASTS = 3;
3379
3504
  function ToastProvider({ children }) {
3380
- const manager = useMemo4(() => BaseToast.createToastManager(), []);
3381
- const value = useMemo4(
3505
+ const manager = useMemo5(() => BaseToast.createToastManager(), []);
3506
+ const value = useMemo5(
3382
3507
  () => ({
3383
3508
  showToast: ({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, durationMs = 5e3 }) => manager.add({
3384
3509
  title: label,
@@ -3392,9 +3517,9 @@ function ToastProvider({ children }) {
3392
3517
  }),
3393
3518
  [manager]
3394
3519
  );
3395
- return /* @__PURE__ */ jsx58(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs41(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
3520
+ return /* @__PURE__ */ jsx59(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs42(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
3396
3521
  children,
3397
- /* @__PURE__ */ jsx58(BaseToast.Portal, { children: /* @__PURE__ */ jsx58(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx58(ToastList, {}) }) })
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, {}) }) })
3398
3523
  ] }) });
3399
3524
  }
3400
3525
  function ToastList() {
@@ -3402,25 +3527,25 @@ function ToastList() {
3402
3527
  return toasts.map((toast) => {
3403
3528
  const type = toast.type ?? "neutral";
3404
3529
  const { leadingIcon = true, actionLabel, onAction } = toast.data ?? {};
3405
- return /* @__PURE__ */ jsxs41(
3530
+ return /* @__PURE__ */ jsxs42(
3406
3531
  BaseToast.Root,
3407
3532
  {
3408
3533
  toast,
3409
3534
  swipeDirection: ["left", "down"],
3410
3535
  className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
3411
3536
  children: [
3412
- /* @__PURE__ */ jsxs41("div", { className: "flex items-center gap-2 shrink-0", children: [
3413
- leadingIcon && /* @__PURE__ */ jsx58(LeadingIcon, { type }),
3414
- /* @__PURE__ */ jsx58(BaseToast.Title, { render: /* @__PURE__ */ jsx58("span", {}), className: LABEL_CLASSES })
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 })
3415
3540
  ] }),
3416
- actionLabel && /* @__PURE__ */ jsx58(
3541
+ actionLabel && /* @__PURE__ */ jsx59(
3417
3542
  BaseToast.Action,
3418
3543
  {
3419
3544
  onClick: () => {
3420
3545
  onAction?.();
3421
3546
  close(toast.id);
3422
3547
  },
3423
- render: /* @__PURE__ */ jsx58(Button, { variant: "outlined", size: "small", children: actionLabel })
3548
+ render: /* @__PURE__ */ jsx59(Button, { variant: "outlined", size: "small", children: actionLabel })
3424
3549
  }
3425
3550
  )
3426
3551
  ]
@@ -3434,6 +3559,19 @@ function useToast() {
3434
3559
  if (!ctx) throw new Error("useToast must be used within ToastProvider");
3435
3560
  return ctx;
3436
3561
  }
3562
+
3563
+ // src/shortcuts.ts
3564
+ function isApplePlatform() {
3565
+ if (typeof navigator === "undefined") return false;
3566
+ return /Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent || "");
3567
+ }
3568
+ function shortcutLabel(keys, apple = isApplePlatform()) {
3569
+ return keys.split("-").map((part, i, all) => {
3570
+ if (i === all.length - 1) return part.length === 1 ? part.toUpperCase() : part;
3571
+ if (part === "Mod") return apple ? "Cmd" : "Ctrl";
3572
+ return part;
3573
+ }).join("+");
3574
+ }
3437
3575
  export {
3438
3576
  AppShell,
3439
3577
  AttachmentCard,
@@ -3506,6 +3644,7 @@ export {
3506
3644
  SkeletonBar,
3507
3645
  SkeletonList,
3508
3646
  SkeletonRow,
3647
+ SuggestionMenu,
3509
3648
  Tabs,
3510
3649
  TextInput,
3511
3650
  Textarea,
@@ -3524,7 +3663,9 @@ export {
3524
3663
  hueFor,
3525
3664
  initialsFor,
3526
3665
  inlineChipClassName,
3666
+ isApplePlatform,
3527
3667
  richTextClassName,
3668
+ shortcutLabel,
3528
3669
  useToast
3529
3670
  };
3530
3671
  //# sourceMappingURL=index.js.map