@estiva-app/ui 0.24.0 → 0.25.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 (85) hide show
  1. package/dist/ErrorBoundary.d.ts +32 -0
  2. package/dist/ErrorBoundary.d.ts.map +1 -0
  3. package/dist/ListColumn.d.ts +42 -0
  4. package/dist/ListColumn.d.ts.map +1 -0
  5. package/dist/Menu.d.ts +7 -0
  6. package/dist/Menu.d.ts.map +1 -1
  7. package/dist/Select.d.ts +1 -0
  8. package/dist/Select.d.ts.map +1 -1
  9. package/dist/Toolbar.d.ts +18 -0
  10. package/dist/Toolbar.d.ts.map +1 -1
  11. package/dist/index.d.ts +4 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +183 -108
  14. package/dist/index.js.map +4 -4
  15. package/package.json +1 -1
  16. package/registry.json +211 -4
  17. package/src/AppShell.mdx +8 -1
  18. package/src/AttachmentCard.mdx +3 -1
  19. package/src/Avatar.mdx +7 -2
  20. package/src/Banner.mdx +4 -5
  21. package/src/Breadcrumb.mdx +2 -0
  22. package/src/Button.mdx +3 -2
  23. package/src/Button.tsx +2 -2
  24. package/src/Card.mdx +5 -1
  25. package/src/Checkbox.mdx +1 -0
  26. package/src/ChipInput.mdx +1 -1
  27. package/src/CollapsibleSection.mdx +4 -4
  28. package/src/ConfirmDialog.mdx +2 -2
  29. package/src/ContainerHeader.mdx +12 -3
  30. package/src/DialogShell.mdx +1 -1
  31. package/src/Divider.mdx +5 -2
  32. package/src/EditableText.mdx +6 -1
  33. package/src/EmptyState.mdx +2 -2
  34. package/src/ErrorBoundary.mdx +66 -0
  35. package/src/ErrorBoundary.stories.tsx +64 -0
  36. package/src/ErrorBoundary.test.tsx +79 -0
  37. package/src/ErrorBoundary.tsx +54 -0
  38. package/src/Field.mdx +3 -4
  39. package/src/Form.mdx +1 -1
  40. package/src/IconButton.mdx +1 -1
  41. package/src/IdentityMenu.mdx +1 -1
  42. package/src/InlineChip.mdx +3 -0
  43. package/src/Kbd.mdx +2 -2
  44. package/src/Link.mdx +3 -1
  45. package/src/ListColumn.mdx +95 -0
  46. package/src/ListColumn.stories.tsx +160 -0
  47. package/src/ListColumn.test.tsx +63 -0
  48. package/src/ListColumn.tsx +86 -0
  49. package/src/Menu.mdx +7 -2
  50. package/src/Menu.stories.tsx +6 -7
  51. package/src/Menu.test.tsx +19 -1
  52. package/src/Menu.tsx +11 -1
  53. package/src/MenuItem.mdx +3 -0
  54. package/src/NavItem.mdx +4 -0
  55. package/src/Person.mdx +3 -0
  56. package/src/PersonTrigger.mdx +2 -1
  57. package/src/PersonTrigger.tsx +1 -1
  58. package/src/Popover.mdx +2 -0
  59. package/src/Rail.mdx +3 -0
  60. package/src/RailItem.mdx +4 -0
  61. package/src/RailItem.tsx +1 -1
  62. package/src/Reaction.mdx +1 -0
  63. package/src/Reaction.tsx +1 -1
  64. package/src/ScrollArea.mdx +3 -0
  65. package/src/SectionHeader.mdx +10 -2
  66. package/src/SectionHeader.tsx +1 -1
  67. package/src/SectionLabel.mdx +10 -4
  68. package/src/Select.mdx +3 -2
  69. package/src/Select.test.tsx +12 -0
  70. package/src/Select.tsx +4 -3
  71. package/src/Skeleton.mdx +5 -1
  72. package/src/Skeleton.tsx +1 -1
  73. package/src/TextInput.mdx +1 -0
  74. package/src/TextInput.tsx +1 -1
  75. package/src/Toolbar.mdx +9 -2
  76. package/src/Toolbar.stories.tsx +19 -2
  77. package/src/Toolbar.test.tsx +24 -1
  78. package/src/Toolbar.tsx +22 -0
  79. package/src/Tooltip.mdx +2 -1
  80. package/src/Tooltip.test.tsx +22 -0
  81. package/src/Tooltip.tsx +1 -1
  82. package/src/TopBar.mdx +8 -1
  83. package/src/heights.test.tsx +78 -0
  84. package/src/index.ts +4 -2
  85. package/src/registry/registry.test.ts +16 -8
package/dist/index.js CHANGED
@@ -324,7 +324,7 @@ function TooltipSurface({ label, shortcut, placement }) {
324
324
  function WithTooltip({ label, shortcut, placement = "top", wrapperClassName, inline = false, children }) {
325
325
  const Wrapper = inline ? "span" : "div";
326
326
  return /* @__PURE__ */ jsxs4(BaseTooltip.Root, { disableHoverablePopup: true, children: [
327
- /* @__PURE__ */ jsx7(BaseTooltip.Trigger, { delay: OPEN_DELAY, render: /* @__PURE__ */ jsx7(Wrapper, { className: cn("inline-flex shrink-0", wrapperClassName) }), children }),
327
+ /* @__PURE__ */ jsx7(BaseTooltip.Trigger, { delay: OPEN_DELAY, render: /* @__PURE__ */ jsx7(Wrapper, { className: cn("inline-flex shrink-0", inline && "align-top", wrapperClassName) }), children }),
328
328
  /* @__PURE__ */ jsx7(TooltipSurface, { label, shortcut, placement })
329
329
  ] });
330
330
  }
@@ -723,8 +723,8 @@ function Button({
723
723
  // this package's own story frames, each of which asks for the top.
724
724
  // A control does not get to decide where its caller puts it.
725
725
  "inline-flex items-center justify-center gap-1 rounded-md transition-colors font-sans font-medium",
726
- size === "default" && "h-8 text-btn-default",
727
- size === "small" && "h-6 text-btn-small",
726
+ size === "default" && "h-8 min-h-8 text-btn-default",
727
+ size === "small" && "h-6 min-h-6 text-btn-small",
728
728
  // Extra right padding beside a leading icon, for optical balance.
729
729
  size === "default" && (hasLeadingIcon ? "pl-2 pr-3" : "px-2"),
730
730
  size === "small" && (hasLeadingIcon ? "pl-1.5 pr-2" : "px-1.5"),
@@ -1143,6 +1143,9 @@ function MenuSection({ label, children, className }) {
1143
1143
  children
1144
1144
  ] });
1145
1145
  }
1146
+ function MenuSeparator() {
1147
+ return /* @__PURE__ */ jsx18(Divider, { className: "my-1" });
1148
+ }
1146
1149
  function MenuRow({ children, className }) {
1147
1150
  return /* @__PURE__ */ jsx18("div", { className: cn("flex items-center gap-2 px-2 py-1.5", className), children });
1148
1151
  }
@@ -1432,7 +1435,7 @@ function SkeletonBar({ className, style }) {
1432
1435
  }
1433
1436
  var ROW_BAR_WIDTHS = [150, 100, 170, 120, 90, 140, 110, 160];
1434
1437
  function SkeletonRow({ barWidth = 130 }) {
1435
- return /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2 px-2 h-[32px] rounded-lg", children: [
1438
+ return /* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-2 px-2 h-[32px] rounded-lg", children: [
1436
1439
  /* @__PURE__ */ jsx23(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
1437
1440
  /* @__PURE__ */ jsx23(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
1438
1441
  ] });
@@ -1818,7 +1821,7 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
1818
1821
  "aria-haspopup": "menu",
1819
1822
  "aria-expanded": open,
1820
1823
  className: cn(
1821
- "flex h-8 cursor-pointer items-center gap-1.5 rounded-md pl-1.5 pr-1.5 text-body-2 text-text-primary transition-colors hover:bg-bg-hover",
1824
+ "flex h-8 min-h-8 cursor-pointer items-center gap-1.5 rounded-md pl-1.5 pr-1.5 text-body-2 text-text-primary transition-colors hover:bg-bg-hover",
1822
1825
  open && "bg-bg-hover",
1823
1826
  // Under a `Menu` the open state is Base UI's, not a prop: the trigger
1824
1827
  // carries `data-popup-open` while its menu is up, and sets its own
@@ -1956,7 +1959,7 @@ var GAP4 = 4;
1956
1959
  var VIEWPORT_PAD4 = 8;
1957
1960
  function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, disabledReason, className, ...aria }) {
1958
1961
  const selected = options.find((o) => o.value === value);
1959
- const held = Boolean(disabledReason) && !disabled;
1962
+ const held = Boolean(disabledReason);
1960
1963
  const trigger = /* @__PURE__ */ jsxs22(
1961
1964
  BaseSelect.Trigger,
1962
1965
  {
@@ -1983,7 +1986,7 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
1983
1986
  "focus-visible:border-border-focus aria-expanded:border-border-focus",
1984
1987
  "signal:transition-shadow signal:focus-visible:shadow-focus-ring",
1985
1988
  size === "default" && "px-3 py-2 text-input-value",
1986
- size === "small" && "h-6 px-2 text-caption",
1989
+ size === "small" && "h-6 min-h-6 px-2 text-caption",
1987
1990
  className
1988
1991
  ),
1989
1992
  children: [
@@ -2009,7 +2012,7 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
2009
2012
  },
2010
2013
  ...held ? { open: false, onOpenChange: () => {
2011
2014
  } } : {},
2012
- disabled,
2015
+ disabled: disabled && !held,
2013
2016
  modal: false,
2014
2017
  children: [
2015
2018
  held ? /* @__PURE__ */ jsx30(TooltipTrigger, { label: disabledReason ?? "", children: trigger }) : trigger,
@@ -2073,7 +2076,7 @@ var TextInput = forwardRef2(function TextInput2({ className, type = "text", size
2073
2076
  "bg-bg-inset border border-border-default hover:border-border-strong focus:border-border-focus rounded-lg",
2074
2077
  // The small size is the small Select's trigger, class for class.
2075
2078
  size === "default" && "px-3 py-2 text-input-value",
2076
- size === "small" && "h-6 px-2 text-caption",
2079
+ size === "small" && "h-6 min-h-6 px-2 text-caption",
2077
2080
  "text-text-primary placeholder:text-text-muted",
2078
2081
  "outline-none transition-colors",
2079
2082
  "disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled",
@@ -2307,9 +2310,36 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2307
2310
  );
2308
2311
  }
2309
2312
 
2313
+ // src/ErrorBoundary.tsx
2314
+ import { Component } from "react";
2315
+ import { IconAlertTriangle as IconAlertTriangle2 } from "@tabler/icons-react";
2316
+ import { jsx as jsx36 } from "react/jsx-runtime";
2317
+ var ErrorBoundary = class extends Component {
2318
+ state = { hasError: false };
2319
+ static getDerivedStateFromError() {
2320
+ return { hasError: true };
2321
+ }
2322
+ componentDidCatch(error, info) {
2323
+ console.error(`${this.props.label ?? "part of the page"} crashed:`, error, info.componentStack ?? "");
2324
+ }
2325
+ render() {
2326
+ if (!this.state.hasError) return this.props.children;
2327
+ const message = /* @__PURE__ */ jsx36(
2328
+ EmptyState,
2329
+ {
2330
+ icon: /* @__PURE__ */ jsx36(IconAlertTriangle2, { size: 16, stroke: 1.5 }),
2331
+ message: `Something went wrong${this.props.label ? ` in the ${this.props.label}` : ""}. Your data is safe \u2014 try again.`,
2332
+ action: { label: "Try again", onClick: () => this.setState({ hasError: false }) }
2333
+ }
2334
+ );
2335
+ if (this.props.frame) return this.props.frame(message);
2336
+ return this.props.fallbackClassName ? /* @__PURE__ */ jsx36("div", { className: this.props.fallbackClassName, children: message }) : message;
2337
+ }
2338
+ };
2339
+
2310
2340
  // src/ProgressBar.tsx
2311
2341
  import { Progress } from "@base-ui/react/progress";
2312
- import { jsx as jsx36 } from "react/jsx-runtime";
2342
+ import { jsx as jsx37 } from "react/jsx-runtime";
2313
2343
  var TRACK_CLASSES = {
2314
2344
  default: "h-1.5 w-full overflow-hidden rounded-full bg-bg-inset",
2315
2345
  // 4px, Katerina's ruling of 14 September; Peek's own bar is 3px until it takes this one.
@@ -2322,13 +2352,13 @@ var INDICATOR_CLASSES = {
2322
2352
  function ProgressBar({ value, max, label, variant = "default", className }) {
2323
2353
  return (
2324
2354
  // `max={0}` needs no guard: Base UI reads the 0/0 share as an empty bar.
2325
- /* @__PURE__ */ jsx36(Progress.Root, { value, max, "aria-label": label, className, children: /* @__PURE__ */ jsx36(Progress.Track, { className: TRACK_CLASSES[variant], children: /* @__PURE__ */ jsx36(Progress.Indicator, { className: INDICATOR_CLASSES[variant] }) }) })
2355
+ /* @__PURE__ */ jsx37(Progress.Root, { value, max, "aria-label": label, className, children: /* @__PURE__ */ jsx37(Progress.Track, { className: TRACK_CLASSES[variant], children: /* @__PURE__ */ jsx37(Progress.Indicator, { className: INDICATOR_CLASSES[variant] }) }) })
2326
2356
  );
2327
2357
  }
2328
2358
 
2329
2359
  // src/Breadcrumb.tsx
2330
2360
  import { Fragment as Fragment7, useCallback as useCallback2, useLayoutEffect as useLayoutEffect4, useRef as useRef7, useState as useState6 } from "react";
2331
- import { jsx as jsx37, jsxs as jsxs25 } from "react/jsx-runtime";
2361
+ import { jsx as jsx38, jsxs as jsxs25 } from "react/jsx-runtime";
2332
2362
  function Breadcrumb({ items, className }) {
2333
2363
  const navRef = useRef7(null);
2334
2364
  const labelRefs = useRef7([]);
@@ -2348,7 +2378,7 @@ function Breadcrumb({ items, className }) {
2348
2378
  observer.observe(nav);
2349
2379
  return () => observer.disconnect();
2350
2380
  }, [measure, items]);
2351
- return /* @__PURE__ */ jsx37("nav", { ref: navRef, "aria-label": "Breadcrumb", className: cn("flex min-w-0 items-center gap-1.5 text-body-2", className), children: items.map((item, index) => {
2381
+ return /* @__PURE__ */ jsx38("nav", { ref: navRef, "aria-label": "Breadcrumb", className: cn("flex min-w-0 items-center gap-1.5 text-body-2", className), children: items.map((item, index) => {
2352
2382
  const last = index === items.length - 1;
2353
2383
  const tone = item.muted || last && item.mono ? "text-text-muted" : last ? "text-text-primary" : "text-text-secondary";
2354
2384
  const text = cn(
@@ -2369,23 +2399,23 @@ function Breadcrumb({ items, className }) {
2369
2399
  // on a box around it, which the link takes them from, rather than
2370
2400
  // pushed into it (UIG-9); the link is still the one element that
2371
2401
  // truncates and is measured.
2372
- /* @__PURE__ */ jsx37("span", { className: cn("flex min-w-0", item.mono && "shrink-0 font-mono text-caption", tone, "hover:text-text-primary"), children: /* @__PURE__ */ jsx37(Link, { ref: setLabelRef, variant: "plain", truncate: true, href: item.href, onClick: item.onClick, children: item.label }) })
2373
- ) : /* @__PURE__ */ jsx37("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
2402
+ /* @__PURE__ */ jsx38("span", { className: cn("flex min-w-0", item.mono && "shrink-0 font-mono text-caption", tone, "hover:text-text-primary"), children: /* @__PURE__ */ jsx38(Link, { ref: setLabelRef, variant: "plain", truncate: true, href: item.href, onClick: item.onClick, children: item.label }) })
2403
+ ) : /* @__PURE__ */ jsx38("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
2374
2404
  return /* @__PURE__ */ jsxs25(Fragment7, { children: [
2375
- index > 0 && /* @__PURE__ */ jsx37("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
2376
- item.icon && /* @__PURE__ */ jsx37("span", { "aria-hidden": "true", className: cn("flex shrink-0", tone), children: item.icon }),
2405
+ index > 0 && /* @__PURE__ */ jsx38("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
2406
+ item.icon && /* @__PURE__ */ jsx38("span", { "aria-hidden": "true", className: cn("flex shrink-0", tone), children: item.icon }),
2377
2407
  truncated.has(index) ? (
2378
2408
  // `min-w-0 shrink` undoes the wrapper's own shrink-0 — the crumb
2379
2409
  // must keep truncating inside it, or wrapping it would widen the
2380
2410
  // trail and the tooltip would never be needed again.
2381
- /* @__PURE__ */ jsx37(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
2411
+ /* @__PURE__ */ jsx38(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
2382
2412
  ) : crumb
2383
2413
  ] }, `${item.label}-${index}`);
2384
2414
  }) });
2385
2415
  }
2386
2416
 
2387
2417
  // src/NavItem.tsx
2388
- import { jsx as jsx38, jsxs as jsxs26 } from "react/jsx-runtime";
2418
+ import { jsx as jsx39, jsxs as jsxs26 } from "react/jsx-runtime";
2389
2419
  function NavItem({ label, href, count, countLabel, active = false, icon, className, ...props }) {
2390
2420
  return /* @__PURE__ */ jsxs26(
2391
2421
  "a",
@@ -2402,9 +2432,9 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
2402
2432
  ),
2403
2433
  ...props,
2404
2434
  children: [
2405
- icon && /* @__PURE__ */ jsx38("span", { className: "flex shrink-0 items-center", children: icon }),
2406
- /* @__PURE__ */ jsx38("span", { className: "flex-1 truncate", children: label }),
2407
- count ? /* @__PURE__ */ jsx38(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx38("span", { className: "min-w-4 shrink-0 text-center font-mono text-caption tabular-nums text-text-muted", children: count }) }) : null
2435
+ icon && /* @__PURE__ */ jsx39("span", { className: "flex shrink-0 items-center", children: icon }),
2436
+ /* @__PURE__ */ jsx39("span", { className: "flex-1 truncate", children: label }),
2437
+ count ? /* @__PURE__ */ jsx39(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx39("span", { className: "min-w-4 shrink-0 text-center font-mono text-caption tabular-nums text-text-muted", children: count }) }) : null
2408
2438
  ]
2409
2439
  }
2410
2440
  );
@@ -2413,7 +2443,7 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
2413
2443
  // src/Popover.tsx
2414
2444
  import { useMemo as useMemo3 } from "react";
2415
2445
  import { Popover as BasePopover } from "@base-ui/react/popover";
2416
- import { jsx as jsx39, jsxs as jsxs27 } from "react/jsx-runtime";
2446
+ import { jsx as jsx40, jsxs as jsxs27 } from "react/jsx-runtime";
2417
2447
  var GAP5 = 4;
2418
2448
  var VIEWPORT_PAD5 = 8;
2419
2449
  function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpenChange, finalFocus, actionsRef, ariaLabel, children, className, contentClassName, maxHeight }) {
@@ -2430,8 +2460,8 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2430
2460
  actionsRef,
2431
2461
  modal: false,
2432
2462
  children: [
2433
- trigger && /* @__PURE__ */ jsx39(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
2434
- /* @__PURE__ */ jsx39(BasePopover.Portal, { children: /* @__PURE__ */ jsx39(
2463
+ trigger && /* @__PURE__ */ jsx40(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
2464
+ /* @__PURE__ */ jsx40(BasePopover.Portal, { children: /* @__PURE__ */ jsx40(
2435
2465
  BasePopover.Positioner,
2436
2466
  {
2437
2467
  anchor: anchorTarget,
@@ -2440,20 +2470,20 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2440
2470
  sideOffset: GAP5,
2441
2471
  collisionPadding: VIEWPORT_PAD5,
2442
2472
  className: "z-50 data-[anchor-hidden]:hidden",
2443
- children: /* @__PURE__ */ jsx39(
2473
+ children: /* @__PURE__ */ jsx40(
2444
2474
  BasePopover.Popup,
2445
2475
  {
2446
2476
  "aria-label": ariaLabel,
2447
2477
  initialFocus: trigger ? void 0 : false,
2448
2478
  finalFocus,
2449
2479
  className: cn("min-w-[180px] outline-none p-0", className),
2450
- render: /* @__PURE__ */ jsx39(MenuPanel, {}),
2451
- children: /* @__PURE__ */ jsx39(
2480
+ render: /* @__PURE__ */ jsx40(MenuPanel, {}),
2481
+ children: /* @__PURE__ */ jsx40(
2452
2482
  ScrollArea,
2453
2483
  {
2454
2484
  viewportClassName: maxHeight ?? "max-h-[var(--available-height)]",
2455
2485
  contentClassName: cn("flex flex-col p-2", contentClassName),
2456
- children: /* @__PURE__ */ jsx39(DividerInPanel.Provider, { value: true, children })
2486
+ children: /* @__PURE__ */ jsx40(DividerInPanel.Provider, { value: true, children })
2457
2487
  }
2458
2488
  )
2459
2489
  }
@@ -2467,9 +2497,9 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2467
2497
 
2468
2498
  // src/Toolbar.tsx
2469
2499
  import { Toolbar as BaseToolbar } from "@base-ui/react/toolbar";
2470
- import { jsx as jsx40 } from "react/jsx-runtime";
2500
+ import { jsx as jsx41 } from "react/jsx-runtime";
2471
2501
  function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocus = true, surface = true, children, className }) {
2472
- const strip = /* @__PURE__ */ jsx40(
2502
+ const strip = /* @__PURE__ */ jsx41(
2473
2503
  BaseToolbar.Root,
2474
2504
  {
2475
2505
  "aria-label": ariaLabel,
@@ -2480,24 +2510,27 @@ function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocu
2480
2510
  }
2481
2511
  );
2482
2512
  if (!surface) return strip;
2483
- return /* @__PURE__ */ jsx40(MenuPanel, { className: "w-fit p-1", children: strip });
2513
+ return /* @__PURE__ */ jsx41(MenuPanel, { className: "w-fit p-1", children: strip });
2484
2514
  }
2485
2515
  function ToolbarButton({ ref, disabled, disabledReason, ...props }) {
2486
- return /* @__PURE__ */ jsx40(
2516
+ return /* @__PURE__ */ jsx41(
2487
2517
  BaseToolbar.Button,
2488
2518
  {
2489
2519
  ref,
2490
2520
  disabled: disabled || !!disabledReason,
2491
2521
  focusableWhenDisabled: true,
2492
- render: /* @__PURE__ */ jsx40(IconButton, { disabled, disabledReason, ...props })
2522
+ render: /* @__PURE__ */ jsx41(IconButton, { disabled, disabledReason, ...props })
2493
2523
  }
2494
2524
  );
2495
2525
  }
2526
+ function ToolbarLink({ ref, href, ...props }) {
2527
+ return /* @__PURE__ */ jsx41(BaseToolbar.Link, { ref, render: /* @__PURE__ */ jsx41(IconButton, { href, ...props }) });
2528
+ }
2496
2529
  function ToolbarInput({ size, ...props }) {
2497
- return /* @__PURE__ */ jsx40(BaseToolbar.Input, { render: /* @__PURE__ */ jsx40(TextInput, { size }), ...props });
2530
+ return /* @__PURE__ */ jsx41(BaseToolbar.Input, { render: /* @__PURE__ */ jsx41(TextInput, { size }), ...props });
2498
2531
  }
2499
2532
  function ToolbarSeparator({ className }) {
2500
- return /* @__PURE__ */ jsx40(
2533
+ return /* @__PURE__ */ jsx41(
2501
2534
  BaseToolbar.Separator,
2502
2535
  {
2503
2536
  orientation: "vertical",
@@ -2507,9 +2540,9 @@ function ToolbarSeparator({ className }) {
2507
2540
  }
2508
2541
 
2509
2542
  // src/ReactionPicker.tsx
2510
- import { jsx as jsx41 } from "react/jsx-runtime";
2543
+ import { jsx as jsx42 } from "react/jsx-runtime";
2511
2544
  function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reactions", surface = true, className }) {
2512
- return /* @__PURE__ */ jsx41(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
2545
+ return /* @__PURE__ */ jsx42(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
2513
2546
  /*
2514
2547
  A `ToolbarButton`, not a button in a tooltip wrapper. The wrapper
2515
2548
  would become the toolbar's item and the button inside it would never
@@ -2519,14 +2552,14 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
2519
2552
  The tooltip names it for a pointer, `aria-label` for everything else,
2520
2553
  and both say the meaning rather than the glyph.
2521
2554
  */
2522
- /* @__PURE__ */ jsx41(
2555
+ /* @__PURE__ */ jsx42(
2523
2556
  ToolbarButton,
2524
2557
  {
2525
2558
  "aria-label": option.label,
2526
2559
  tooltip: option.label,
2527
2560
  onClick: () => onSelect(option.emoji),
2528
2561
  className: "size-7",
2529
- children: /* @__PURE__ */ jsx41("span", { "aria-hidden": "true", className: "text-h3 leading-none", children: option.emoji })
2562
+ children: /* @__PURE__ */ jsx42("span", { "aria-hidden": "true", className: "text-h3 leading-none", children: option.emoji })
2530
2563
  },
2531
2564
  option.emoji
2532
2565
  )
@@ -2535,23 +2568,23 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
2535
2568
 
2536
2569
  // src/PreviewCard.tsx
2537
2570
  import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
2538
- import { jsx as jsx42, jsxs as jsxs28 } from "react/jsx-runtime";
2571
+ import { jsx as jsx43, jsxs as jsxs28 } from "react/jsx-runtime";
2539
2572
  var GAP6 = 12;
2540
2573
  var VIEWPORT_PAD6 = 8;
2541
2574
  var OPEN_DELAY2 = 350;
2542
2575
  var CLOSE_DELAY = 200;
2543
2576
  function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, contentClassName, wrapperClassName }) {
2544
2577
  return /* @__PURE__ */ jsxs28(BasePreviewCard.Root, { children: [
2545
- /* @__PURE__ */ jsx42(
2578
+ /* @__PURE__ */ jsx43(
2546
2579
  BasePreviewCard.Trigger,
2547
2580
  {
2548
2581
  delay,
2549
2582
  closeDelay,
2550
- render: /* @__PURE__ */ jsx42("span", { className: cn("inline-flex", wrapperClassName) }),
2583
+ render: /* @__PURE__ */ jsx43("span", { className: cn("inline-flex", wrapperClassName) }),
2551
2584
  children
2552
2585
  }
2553
2586
  ),
2554
- /* @__PURE__ */ jsx42(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx42(
2587
+ /* @__PURE__ */ jsx43(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx43(
2555
2588
  BasePreviewCard.Positioner,
2556
2589
  {
2557
2590
  side,
@@ -2559,12 +2592,12 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
2559
2592
  sideOffset: GAP6,
2560
2593
  collisionPadding: VIEWPORT_PAD6,
2561
2594
  className: "z-50 data-[anchor-hidden]:hidden",
2562
- children: /* @__PURE__ */ jsx42(
2595
+ children: /* @__PURE__ */ jsx43(
2563
2596
  BasePreviewCard.Popup,
2564
2597
  {
2565
2598
  className: cn("w-[360px] p-0 outline-none", className),
2566
- render: /* @__PURE__ */ jsx42(MenuPanel, {}),
2567
- children: /* @__PURE__ */ jsx42(ScrollArea, { viewportClassName: "max-h-[min(300px,var(--available-height))]", contentClassName: cn("flex flex-col gap-3 p-3", contentClassName), children: content })
2599
+ render: /* @__PURE__ */ jsx43(MenuPanel, {}),
2600
+ children: /* @__PURE__ */ jsx43(ScrollArea, { viewportClassName: "max-h-[min(300px,var(--available-height))]", contentClassName: cn("flex flex-col gap-3 p-3", contentClassName), children: content })
2568
2601
  }
2569
2602
  )
2570
2603
  }
@@ -2573,30 +2606,30 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
2573
2606
  }
2574
2607
 
2575
2608
  // src/Rail.tsx
2576
- import { jsx as jsx43 } from "react/jsx-runtime";
2609
+ import { jsx as jsx44 } from "react/jsx-runtime";
2577
2610
  function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
2578
- return /* @__PURE__ */ jsx43("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
2611
+ return /* @__PURE__ */ jsx44("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
2579
2612
  }
2580
2613
 
2581
2614
  // src/RailItem.tsx
2582
- import { jsx as jsx44, jsxs as jsxs29 } from "react/jsx-runtime";
2615
+ import { jsx as jsx45, jsxs as jsxs29 } from "react/jsx-runtime";
2583
2616
  function RailItem({ href, icon, label, active = false, className, ...props }) {
2584
2617
  return /* @__PURE__ */ jsxs29(
2585
2618
  "a",
2586
2619
  {
2587
2620
  href,
2588
2621
  "aria-current": active ? "page" : void 0,
2589
- className: cn("group flex w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
2622
+ className: cn("group flex h-12 w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
2590
2623
  ...props,
2591
2624
  children: [
2592
- /* @__PURE__ */ jsx44(
2625
+ /* @__PURE__ */ jsx45(
2593
2626
  "div",
2594
2627
  {
2595
2628
  className: cn(
2596
2629
  "flex items-center justify-center rounded-lg p-2 transition-colors",
2597
2630
  active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
2598
2631
  ),
2599
- children: /* @__PURE__ */ jsx44(
2632
+ children: /* @__PURE__ */ jsx45(
2600
2633
  "span",
2601
2634
  {
2602
2635
  className: cn(
@@ -2608,27 +2641,27 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
2608
2641
  )
2609
2642
  }
2610
2643
  ),
2611
- /* @__PURE__ */ jsx44("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
2644
+ /* @__PURE__ */ jsx45("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
2612
2645
  ]
2613
2646
  }
2614
2647
  );
2615
2648
  }
2616
2649
 
2617
2650
  // src/Sidebar.tsx
2618
- import { jsx as jsx45 } from "react/jsx-runtime";
2651
+ import { jsx as jsx46 } from "react/jsx-runtime";
2619
2652
  function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className }) {
2620
- return /* @__PURE__ */ jsx45(
2653
+ return /* @__PURE__ */ jsx46(
2621
2654
  "nav",
2622
2655
  {
2623
2656
  "aria-label": ariaLabel,
2624
2657
  className: cn("flex w-60 shrink-0 flex-col border-r border-border-default bg-bg-surface", className),
2625
- children: /* @__PURE__ */ jsx45(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex flex-col gap-px px-2.5 py-3", children })
2658
+ children: /* @__PURE__ */ jsx46(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex flex-col gap-px px-2.5 py-3", children })
2626
2659
  }
2627
2660
  );
2628
2661
  }
2629
2662
 
2630
2663
  // src/Property.tsx
2631
- import { jsx as jsx46, jsxs as jsxs30 } from "react/jsx-runtime";
2664
+ import { jsx as jsx47, jsxs as jsxs30 } from "react/jsx-runtime";
2632
2665
  var VALUE_CLASSES = "contents";
2633
2666
  function Property({ label, layout = "row", children, className }) {
2634
2667
  if (layout === "stacked") {
@@ -2637,20 +2670,20 @@ function Property({ label, layout = "row", children, className }) {
2637
2670
  // Peek's topic-details sections already sit at 12px, Ship's rail was
2638
2671
  // 6px, and unifying means the bigger, calmer one.
2639
2672
  /* @__PURE__ */ jsxs30("dl", { className: cn("flex flex-col gap-3", className), children: [
2640
- /* @__PURE__ */ jsx46("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
2641
- /* @__PURE__ */ jsx46("dd", { className: VALUE_CLASSES, children })
2673
+ /* @__PURE__ */ jsx47("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
2674
+ /* @__PURE__ */ jsx47("dd", { className: VALUE_CLASSES, children })
2642
2675
  ] })
2643
2676
  );
2644
2677
  }
2645
2678
  return /* @__PURE__ */ jsxs30("dl", { className: cn("flex items-center gap-2", className), children: [
2646
- /* @__PURE__ */ jsx46("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
2647
- /* @__PURE__ */ jsx46("dd", { className: VALUE_CLASSES, children })
2679
+ /* @__PURE__ */ jsx47("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
2680
+ /* @__PURE__ */ jsx47("dd", { className: VALUE_CLASSES, children })
2648
2681
  ] });
2649
2682
  }
2650
2683
 
2651
2684
  // src/Reaction.tsx
2652
2685
  import { Toggle } from "@base-ui/react/toggle";
2653
- import { jsx as jsx47, jsxs as jsxs31 } from "react/jsx-runtime";
2686
+ import { jsx as jsx48, jsxs as jsxs31 } from "react/jsx-runtime";
2654
2687
  function Reaction({ emoji, count, pressed = false, className, ...props }) {
2655
2688
  return /* @__PURE__ */ jsxs31(
2656
2689
  Toggle,
@@ -2659,7 +2692,7 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
2659
2692
  className: cn(
2660
2693
  // Chip's pill at a control's height, so a reaction and a status chip
2661
2694
  // read as the same family — 24px matches Button `small`.
2662
- "inline-flex h-6 items-center justify-center gap-1.5 rounded-full px-2",
2695
+ "inline-flex h-6 min-h-6 items-center justify-center gap-1.5 rounded-full px-2",
2663
2696
  "border transition-colors",
2664
2697
  "disabled:cursor-not-allowed disabled:opacity-50",
2665
2698
  pressed ? (
@@ -2674,8 +2707,8 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
2674
2707
  ),
2675
2708
  ...props,
2676
2709
  children: [
2677
- /* @__PURE__ */ jsx47("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
2678
- /* @__PURE__ */ jsx47("span", { className: "text-chip signal:font-mono signal:text-small signal:font-semibold signal:tabular-nums", children: count })
2710
+ /* @__PURE__ */ jsx48("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
2711
+ /* @__PURE__ */ jsx48("span", { className: "text-chip signal:font-mono signal:text-small signal:font-semibold signal:tabular-nums", children: count })
2679
2712
  ]
2680
2713
  }
2681
2714
  );
@@ -2684,7 +2717,7 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
2684
2717
  // src/SearchInput.tsx
2685
2718
  import "react";
2686
2719
  import { Input as Input3 } from "@base-ui/react/input";
2687
- import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
2720
+ import { jsx as jsx49, jsxs as jsxs32 } from "react/jsx-runtime";
2688
2721
  function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
2689
2722
  return /* @__PURE__ */ jsxs32(
2690
2723
  "div",
@@ -2698,7 +2731,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
2698
2731
  className
2699
2732
  ),
2700
2733
  children: [
2701
- /* @__PURE__ */ jsx48(
2734
+ /* @__PURE__ */ jsx49(
2702
2735
  Input3,
2703
2736
  {
2704
2737
  className: "flex-1 min-w-0 bg-transparent text-input-value text-text-primary placeholder:text-text-muted outline-none",
@@ -2706,7 +2739,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
2706
2739
  ...props
2707
2740
  }
2708
2741
  ),
2709
- shortcut && /* @__PURE__ */ jsx48(Kbd, { children: shortcut })
2742
+ shortcut && /* @__PURE__ */ jsx49(Kbd, { children: shortcut })
2710
2743
  ]
2711
2744
  }
2712
2745
  );
@@ -2715,17 +2748,17 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
2715
2748
  // src/SectionHeader.tsx
2716
2749
  import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
2717
2750
  import { useRender } from "@base-ui/react/use-render";
2718
- import { Fragment as Fragment8, jsx as jsx49, jsxs as jsxs33 } from "react/jsx-runtime";
2751
+ import { Fragment as Fragment8, jsx as jsx50, jsxs as jsxs33 } from "react/jsx-runtime";
2719
2752
  function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", hover = "fill", render, className }) {
2720
2753
  const titleElement = useRender({
2721
- render: render ?? (chevron ? /* @__PURE__ */ jsx49("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx49("span", {})),
2754
+ render: render ?? (chevron ? /* @__PURE__ */ jsx50("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx50("span", {})),
2722
2755
  props: {
2723
2756
  // `text-left`: a button centres its text. `h-full` and `flex-1`: the
2724
2757
  // whole row up to the actions is the hit target, as it was when the
2725
2758
  // row itself carried the click.
2726
2759
  className: "flex h-full min-w-0 flex-1 items-center gap-1 text-left",
2727
2760
  children: /* @__PURE__ */ jsxs33(Fragment8, { children: [
2728
- chevron && /* @__PURE__ */ jsx49(
2761
+ chevron && /* @__PURE__ */ jsx50(
2729
2762
  IconChevronRight2,
2730
2763
  {
2731
2764
  size: 12,
@@ -2733,7 +2766,7 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2733
2766
  className: cn("shrink-0 text-text-secondary transition-transform duration-150", isExpanded && "rotate-90")
2734
2767
  }
2735
2768
  ),
2736
- /* @__PURE__ */ jsx49(SectionLabel, { children: title })
2769
+ /* @__PURE__ */ jsx50(SectionLabel, { children: title })
2737
2770
  ] })
2738
2771
  }
2739
2772
  });
@@ -2741,7 +2774,7 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2741
2774
  "div",
2742
2775
  {
2743
2776
  className: cn(
2744
- "group flex h-[32px] items-center gap-1 rounded-lg px-2 transition-colors",
2777
+ "group flex h-[32px] shrink-0 items-center gap-1 rounded-lg px-2 transition-colors",
2745
2778
  // The fill says "this does something": a row with a toggle or actions
2746
2779
  // lights up, a fixed heading over rows does not (2026-09-09, the
2747
2780
  // Sidebar's fixed group).
@@ -2750,15 +2783,15 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2750
2783
  ),
2751
2784
  children: [
2752
2785
  titleElement,
2753
- trailing != null && /* @__PURE__ */ jsx49("div", { className: "flex shrink-0 items-center", children: trailing }),
2754
- actions && actions.length > 0 && /* @__PURE__ */ jsx49(
2786
+ trailing != null && /* @__PURE__ */ jsx50("div", { className: "flex shrink-0 items-center", children: trailing }),
2787
+ actions && actions.length > 0 && /* @__PURE__ */ jsx50(
2755
2788
  "div",
2756
2789
  {
2757
2790
  className: cn(
2758
2791
  "-mr-1 flex shrink-0 items-center gap-1",
2759
2792
  showActions === "hover" && "opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100"
2760
2793
  ),
2761
- children: actions.map((action) => /* @__PURE__ */ jsx49(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
2794
+ children: actions.map((action) => /* @__PURE__ */ jsx50(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
2762
2795
  }
2763
2796
  )
2764
2797
  ]
@@ -2768,22 +2801,60 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2768
2801
 
2769
2802
  // src/ContainerHeader.tsx
2770
2803
  import { IconChevronDown as IconChevronDown3 } from "@tabler/icons-react";
2771
- import { jsx as jsx50, jsxs as jsxs34 } from "react/jsx-runtime";
2804
+ import { jsx as jsx51, jsxs as jsxs34 } from "react/jsx-runtime";
2772
2805
  function ContainerHeader({ title, chevron = false, actions, className }) {
2773
2806
  const text = typeof title === "string";
2774
2807
  return /* @__PURE__ */ jsxs34("div", { className: cn("flex h-12 shrink-0 items-center justify-between overflow-hidden border-b border-border-subtle py-2 pr-4 pl-5", className), children: [
2775
- /* @__PURE__ */ jsx50("div", { className: cn("flex items-center gap-2 overflow-hidden", text ? "shrink-0" : "min-w-0 flex-1"), children: /* @__PURE__ */ jsxs34("div", { className: cn("flex items-center gap-1", text ? "shrink-0" : "min-w-0 flex-1"), children: [
2776
- text ? /* @__PURE__ */ jsx50("span", { className: "whitespace-nowrap text-body-2-strong text-text-primary", children: title }) : /* @__PURE__ */ jsx50("div", { className: "min-w-0 flex-1", children: title }),
2777
- chevron && /* @__PURE__ */ jsx50(IconChevronDown3, { size: 12, stroke: 1.5, className: "shrink-0 text-text-secondary" })
2808
+ /* @__PURE__ */ jsx51("div", { className: cn("flex items-center gap-2 overflow-hidden", text ? "shrink-0" : "min-w-0 flex-1"), children: /* @__PURE__ */ jsxs34("div", { className: cn("flex items-center gap-1", text ? "shrink-0" : "min-w-0 flex-1"), children: [
2809
+ text ? /* @__PURE__ */ jsx51("span", { className: "whitespace-nowrap text-body-2-strong text-text-primary", children: title }) : /* @__PURE__ */ jsx51("div", { className: "min-w-0 flex-1", children: title }),
2810
+ chevron && /* @__PURE__ */ jsx51(IconChevronDown3, { size: 12, stroke: 1.5, className: "shrink-0 text-text-secondary" })
2778
2811
  ] }) }),
2779
- actions && /* @__PURE__ */ jsx50("div", { className: "flex shrink-0 items-center justify-end gap-3", children: /* @__PURE__ */ jsx50("div", { className: "flex shrink-0 items-center gap-1", children: actions }) })
2812
+ actions && /* @__PURE__ */ jsx51("div", { className: "flex shrink-0 items-center justify-end gap-3", children: /* @__PURE__ */ jsx51("div", { className: "flex shrink-0 items-center gap-1", children: actions }) })
2780
2813
  ] });
2781
2814
  }
2782
2815
 
2816
+ // src/ListColumn.tsx
2817
+ import { jsx as jsx52, jsxs as jsxs35 } from "react/jsx-runtime";
2818
+ function Column({ title, chevron = false, actions, above, collapsed = false, children, className, broken = false }) {
2819
+ return /* @__PURE__ */ jsxs35(
2820
+ "div",
2821
+ {
2822
+ className: cn(
2823
+ // `shrink-0`: the column keeps its 290px beside a main area that grows.
2824
+ "flex shrink-0 flex-col overflow-hidden border-r border-border-subtle transition-[width,opacity] duration-300 ease-in-out",
2825
+ collapsed ? "w-0 border-r-0 opacity-0" : "w-[290px] opacity-100",
2826
+ className
2827
+ ),
2828
+ "data-collapsed": collapsed || void 0,
2829
+ children: [
2830
+ /* @__PURE__ */ jsx52(ContainerHeader, { title, chevron, actions }),
2831
+ above,
2832
+ broken ? (
2833
+ // The message takes the room the list had and centres itself in it (Katerina, 19 September).
2834
+ /* @__PURE__ */ jsx52("div", { className: "flex min-h-0 flex-1 flex-col px-3", children })
2835
+ ) : /* @__PURE__ */ jsx52(ScrollArea, { className: "flex-1", contentClassName: "flex flex-col gap-0.5 px-3 pt-4 pb-3", children })
2836
+ ]
2837
+ }
2838
+ );
2839
+ }
2840
+ function ListColumn(props) {
2841
+ return /* @__PURE__ */ jsx52(
2842
+ ErrorBoundary,
2843
+ {
2844
+ label: "list panel",
2845
+ frame: (message) => (
2846
+ // Only the name comes back with the message: the actions and the row above may be what threw.
2847
+ /* @__PURE__ */ jsx52(Column, { title: props.title, chevron: props.chevron, collapsed: props.collapsed, className: props.className, broken: true, children: message })
2848
+ ),
2849
+ children: /* @__PURE__ */ jsx52(Column, { ...props })
2850
+ }
2851
+ );
2852
+ }
2853
+
2783
2854
  // src/CollapsibleSection.tsx
2784
2855
  import { useState as useState7 } from "react";
2785
2856
  import { Collapsible } from "@base-ui/react/collapsible";
2786
- import { jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
2857
+ import { jsx as jsx53, jsxs as jsxs36 } from "react/jsx-runtime";
2787
2858
  var OPEN = "open";
2788
2859
  var CLOSED = "closed";
2789
2860
  function readStored(key) {
@@ -2810,14 +2881,14 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
2810
2881
  writeStored(storageKey, next);
2811
2882
  onOpenChange?.(next);
2812
2883
  };
2813
- return /* @__PURE__ */ jsxs35(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
2814
- /* @__PURE__ */ jsx51(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx51(Collapsible.Trigger, {}) }),
2815
- /* @__PURE__ */ jsx51(
2884
+ return /* @__PURE__ */ jsxs36(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
2885
+ /* @__PURE__ */ jsx53(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx53(Collapsible.Trigger, {}) }),
2886
+ /* @__PURE__ */ jsx53(
2816
2887
  Collapsible.Panel,
2817
2888
  {
2818
2889
  hiddenUntilFound: true,
2819
2890
  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",
2820
- children: /* @__PURE__ */ jsx51("div", { className: cn("flex flex-col", contentClassName), children })
2891
+ children: /* @__PURE__ */ jsx53("div", { className: cn("flex flex-col", contentClassName), children })
2821
2892
  }
2822
2893
  )
2823
2894
  ] });
@@ -2825,9 +2896,9 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
2825
2896
 
2826
2897
  // src/Tabs.tsx
2827
2898
  import { Tabs as BaseTabs } from "@base-ui/react/tabs";
2828
- import { jsx as jsx52, jsxs as jsxs36 } from "react/jsx-runtime";
2899
+ import { jsx as jsx54, jsxs as jsxs37 } from "react/jsx-runtime";
2829
2900
  function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
2830
- return /* @__PURE__ */ jsx52(
2901
+ return /* @__PURE__ */ jsx54(
2831
2902
  BaseTabs.Root,
2832
2903
  {
2833
2904
  value: active,
@@ -2835,14 +2906,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2835
2906
  if (details.reason === "none") onChange(value);
2836
2907
  },
2837
2908
  className,
2838
- children: /* @__PURE__ */ jsx52(
2909
+ children: /* @__PURE__ */ jsx54(
2839
2910
  BaseTabs.List,
2840
2911
  {
2841
2912
  activateOnFocus: true,
2842
2913
  "aria-label": aria["aria-label"],
2843
2914
  "aria-labelledby": aria["aria-labelledby"],
2844
2915
  className: "flex items-center gap-2",
2845
- children: tabs.map((tab) => /* @__PURE__ */ jsxs36(
2916
+ children: tabs.map((tab) => /* @__PURE__ */ jsxs37(
2846
2917
  BaseTabs.Tab,
2847
2918
  {
2848
2919
  value: tab.id,
@@ -2855,9 +2926,9 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2855
2926
  ),
2856
2927
  children: [
2857
2928
  tab.icon,
2858
- /* @__PURE__ */ jsxs36("span", { className: "flex items-baseline", children: [
2929
+ /* @__PURE__ */ jsxs37("span", { className: "flex items-baseline", children: [
2859
2930
  tab.label,
2860
- tab.count !== void 0 ? /* @__PURE__ */ jsx52("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
2931
+ tab.count !== void 0 ? /* @__PURE__ */ jsx54("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
2861
2932
  ] })
2862
2933
  ]
2863
2934
  },
@@ -2873,7 +2944,7 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2873
2944
  import { createContext as createContext5, useContext as useContext5, useMemo as useMemo4 } from "react";
2874
2945
  import { Toast as BaseToast } from "@base-ui/react/toast";
2875
2946
  import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
2876
- import { jsx as jsx53, jsxs as jsxs37 } from "react/jsx-runtime";
2947
+ import { jsx as jsx55, jsxs as jsxs38 } from "react/jsx-runtime";
2877
2948
  var SURFACE_STYLES = {
2878
2949
  success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
2879
2950
  brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
@@ -2909,16 +2980,16 @@ var pillClassName = (type, hasAction, className) => cn(
2909
2980
  );
2910
2981
  function LeadingIcon({ type }) {
2911
2982
  const Icon = ICONS[type];
2912
- return /* @__PURE__ */ jsx53(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
2983
+ return /* @__PURE__ */ jsx55(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
2913
2984
  }
2914
2985
  function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
2915
2986
  const hasAction = !!(actionLabel && onAction);
2916
- return /* @__PURE__ */ jsxs37("div", { className: pillClassName(type, hasAction, className), children: [
2917
- /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2 shrink-0", children: [
2918
- leadingIcon && /* @__PURE__ */ jsx53(LeadingIcon, { type }),
2919
- /* @__PURE__ */ jsx53("span", { className: LABEL_CLASSES, children: label })
2987
+ return /* @__PURE__ */ jsxs38("div", { className: pillClassName(type, hasAction, className), children: [
2988
+ /* @__PURE__ */ jsxs38("div", { className: "flex items-center gap-2 shrink-0", children: [
2989
+ leadingIcon && /* @__PURE__ */ jsx55(LeadingIcon, { type }),
2990
+ /* @__PURE__ */ jsx55("span", { className: LABEL_CLASSES, children: label })
2920
2991
  ] }),
2921
- hasAction && /* @__PURE__ */ jsx53(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
2992
+ hasAction && /* @__PURE__ */ jsx55(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
2922
2993
  ] });
2923
2994
  }
2924
2995
  var ToastContext = createContext5(null);
@@ -2939,9 +3010,9 @@ function ToastProvider({ children }) {
2939
3010
  }),
2940
3011
  [manager]
2941
3012
  );
2942
- return /* @__PURE__ */ jsx53(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs37(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
3013
+ return /* @__PURE__ */ jsx55(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs38(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
2943
3014
  children,
2944
- /* @__PURE__ */ jsx53(BaseToast.Portal, { children: /* @__PURE__ */ jsx53(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx53(ToastList, {}) }) })
3015
+ /* @__PURE__ */ jsx55(BaseToast.Portal, { children: /* @__PURE__ */ jsx55(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx55(ToastList, {}) }) })
2945
3016
  ] }) });
2946
3017
  }
2947
3018
  function ToastList() {
@@ -2949,25 +3020,25 @@ function ToastList() {
2949
3020
  return toasts.map((toast) => {
2950
3021
  const type = toast.type ?? "neutral";
2951
3022
  const { leadingIcon = true, actionLabel, onAction } = toast.data ?? {};
2952
- return /* @__PURE__ */ jsxs37(
3023
+ return /* @__PURE__ */ jsxs38(
2953
3024
  BaseToast.Root,
2954
3025
  {
2955
3026
  toast,
2956
3027
  swipeDirection: ["left", "down"],
2957
3028
  className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
2958
3029
  children: [
2959
- /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2 shrink-0", children: [
2960
- leadingIcon && /* @__PURE__ */ jsx53(LeadingIcon, { type }),
2961
- /* @__PURE__ */ jsx53(BaseToast.Title, { render: /* @__PURE__ */ jsx53("span", {}), className: LABEL_CLASSES })
3030
+ /* @__PURE__ */ jsxs38("div", { className: "flex items-center gap-2 shrink-0", children: [
3031
+ leadingIcon && /* @__PURE__ */ jsx55(LeadingIcon, { type }),
3032
+ /* @__PURE__ */ jsx55(BaseToast.Title, { render: /* @__PURE__ */ jsx55("span", {}), className: LABEL_CLASSES })
2962
3033
  ] }),
2963
- actionLabel && /* @__PURE__ */ jsx53(
3034
+ actionLabel && /* @__PURE__ */ jsx55(
2964
3035
  BaseToast.Action,
2965
3036
  {
2966
3037
  onClick: () => {
2967
3038
  onAction?.();
2968
3039
  close(toast.id);
2969
3040
  },
2970
- render: /* @__PURE__ */ jsx53(Button, { variant: "outlined", size: "small", children: actionLabel })
3041
+ render: /* @__PURE__ */ jsx55(Button, { variant: "outlined", size: "small", children: actionLabel })
2971
3042
  }
2972
3043
  )
2973
3044
  ]
@@ -3007,6 +3078,7 @@ export {
3007
3078
  EditableText,
3008
3079
  EmptyState,
3009
3080
  EnterHint,
3081
+ ErrorBoundary,
3010
3082
  Field,
3011
3083
  FieldLine,
3012
3084
  FilePicker,
@@ -3020,11 +3092,13 @@ export {
3020
3092
  InputChip,
3021
3093
  Kbd,
3022
3094
  Link,
3095
+ ListColumn,
3023
3096
  Menu,
3024
3097
  MenuItem,
3025
3098
  MenuPanel,
3026
3099
  MenuRow,
3027
3100
  MenuSection,
3101
+ MenuSeparator,
3028
3102
  MenuSub,
3029
3103
  NavItem,
3030
3104
  Person,
@@ -3054,6 +3128,7 @@ export {
3054
3128
  Toolbar,
3055
3129
  ToolbarButton,
3056
3130
  ToolbarInput,
3131
+ ToolbarLink,
3057
3132
  ToolbarSeparator,
3058
3133
  Tooltip,
3059
3134
  TooltipProvider,