@estiva-app/ui 0.24.1 → 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.
package/dist/index.js CHANGED
@@ -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
  }
@@ -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,27 +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
  }
2496
2526
  function ToolbarLink({ ref, href, ...props }) {
2497
- return /* @__PURE__ */ jsx40(BaseToolbar.Link, { ref, render: /* @__PURE__ */ jsx40(IconButton, { href, ...props }) });
2527
+ return /* @__PURE__ */ jsx41(BaseToolbar.Link, { ref, render: /* @__PURE__ */ jsx41(IconButton, { href, ...props }) });
2498
2528
  }
2499
2529
  function ToolbarInput({ size, ...props }) {
2500
- return /* @__PURE__ */ jsx40(BaseToolbar.Input, { render: /* @__PURE__ */ jsx40(TextInput, { size }), ...props });
2530
+ return /* @__PURE__ */ jsx41(BaseToolbar.Input, { render: /* @__PURE__ */ jsx41(TextInput, { size }), ...props });
2501
2531
  }
2502
2532
  function ToolbarSeparator({ className }) {
2503
- return /* @__PURE__ */ jsx40(
2533
+ return /* @__PURE__ */ jsx41(
2504
2534
  BaseToolbar.Separator,
2505
2535
  {
2506
2536
  orientation: "vertical",
@@ -2510,9 +2540,9 @@ function ToolbarSeparator({ className }) {
2510
2540
  }
2511
2541
 
2512
2542
  // src/ReactionPicker.tsx
2513
- import { jsx as jsx41 } from "react/jsx-runtime";
2543
+ import { jsx as jsx42 } from "react/jsx-runtime";
2514
2544
  function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reactions", surface = true, className }) {
2515
- 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) => (
2516
2546
  /*
2517
2547
  A `ToolbarButton`, not a button in a tooltip wrapper. The wrapper
2518
2548
  would become the toolbar's item and the button inside it would never
@@ -2522,14 +2552,14 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
2522
2552
  The tooltip names it for a pointer, `aria-label` for everything else,
2523
2553
  and both say the meaning rather than the glyph.
2524
2554
  */
2525
- /* @__PURE__ */ jsx41(
2555
+ /* @__PURE__ */ jsx42(
2526
2556
  ToolbarButton,
2527
2557
  {
2528
2558
  "aria-label": option.label,
2529
2559
  tooltip: option.label,
2530
2560
  onClick: () => onSelect(option.emoji),
2531
2561
  className: "size-7",
2532
- 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 })
2533
2563
  },
2534
2564
  option.emoji
2535
2565
  )
@@ -2538,23 +2568,23 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
2538
2568
 
2539
2569
  // src/PreviewCard.tsx
2540
2570
  import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
2541
- import { jsx as jsx42, jsxs as jsxs28 } from "react/jsx-runtime";
2571
+ import { jsx as jsx43, jsxs as jsxs28 } from "react/jsx-runtime";
2542
2572
  var GAP6 = 12;
2543
2573
  var VIEWPORT_PAD6 = 8;
2544
2574
  var OPEN_DELAY2 = 350;
2545
2575
  var CLOSE_DELAY = 200;
2546
2576
  function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, contentClassName, wrapperClassName }) {
2547
2577
  return /* @__PURE__ */ jsxs28(BasePreviewCard.Root, { children: [
2548
- /* @__PURE__ */ jsx42(
2578
+ /* @__PURE__ */ jsx43(
2549
2579
  BasePreviewCard.Trigger,
2550
2580
  {
2551
2581
  delay,
2552
2582
  closeDelay,
2553
- render: /* @__PURE__ */ jsx42("span", { className: cn("inline-flex", wrapperClassName) }),
2583
+ render: /* @__PURE__ */ jsx43("span", { className: cn("inline-flex", wrapperClassName) }),
2554
2584
  children
2555
2585
  }
2556
2586
  ),
2557
- /* @__PURE__ */ jsx42(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx42(
2587
+ /* @__PURE__ */ jsx43(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx43(
2558
2588
  BasePreviewCard.Positioner,
2559
2589
  {
2560
2590
  side,
@@ -2562,12 +2592,12 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
2562
2592
  sideOffset: GAP6,
2563
2593
  collisionPadding: VIEWPORT_PAD6,
2564
2594
  className: "z-50 data-[anchor-hidden]:hidden",
2565
- children: /* @__PURE__ */ jsx42(
2595
+ children: /* @__PURE__ */ jsx43(
2566
2596
  BasePreviewCard.Popup,
2567
2597
  {
2568
2598
  className: cn("w-[360px] p-0 outline-none", className),
2569
- render: /* @__PURE__ */ jsx42(MenuPanel, {}),
2570
- 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 })
2571
2601
  }
2572
2602
  )
2573
2603
  }
@@ -2576,13 +2606,13 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
2576
2606
  }
2577
2607
 
2578
2608
  // src/Rail.tsx
2579
- import { jsx as jsx43 } from "react/jsx-runtime";
2609
+ import { jsx as jsx44 } from "react/jsx-runtime";
2580
2610
  function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
2581
- 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 });
2582
2612
  }
2583
2613
 
2584
2614
  // src/RailItem.tsx
2585
- import { jsx as jsx44, jsxs as jsxs29 } from "react/jsx-runtime";
2615
+ import { jsx as jsx45, jsxs as jsxs29 } from "react/jsx-runtime";
2586
2616
  function RailItem({ href, icon, label, active = false, className, ...props }) {
2587
2617
  return /* @__PURE__ */ jsxs29(
2588
2618
  "a",
@@ -2592,14 +2622,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
2592
2622
  className: cn("group flex h-12 w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
2593
2623
  ...props,
2594
2624
  children: [
2595
- /* @__PURE__ */ jsx44(
2625
+ /* @__PURE__ */ jsx45(
2596
2626
  "div",
2597
2627
  {
2598
2628
  className: cn(
2599
2629
  "flex items-center justify-center rounded-lg p-2 transition-colors",
2600
2630
  active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
2601
2631
  ),
2602
- children: /* @__PURE__ */ jsx44(
2632
+ children: /* @__PURE__ */ jsx45(
2603
2633
  "span",
2604
2634
  {
2605
2635
  className: cn(
@@ -2611,27 +2641,27 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
2611
2641
  )
2612
2642
  }
2613
2643
  ),
2614
- /* @__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 })
2615
2645
  ]
2616
2646
  }
2617
2647
  );
2618
2648
  }
2619
2649
 
2620
2650
  // src/Sidebar.tsx
2621
- import { jsx as jsx45 } from "react/jsx-runtime";
2651
+ import { jsx as jsx46 } from "react/jsx-runtime";
2622
2652
  function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className }) {
2623
- return /* @__PURE__ */ jsx45(
2653
+ return /* @__PURE__ */ jsx46(
2624
2654
  "nav",
2625
2655
  {
2626
2656
  "aria-label": ariaLabel,
2627
2657
  className: cn("flex w-60 shrink-0 flex-col border-r border-border-default bg-bg-surface", className),
2628
- 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 })
2629
2659
  }
2630
2660
  );
2631
2661
  }
2632
2662
 
2633
2663
  // src/Property.tsx
2634
- import { jsx as jsx46, jsxs as jsxs30 } from "react/jsx-runtime";
2664
+ import { jsx as jsx47, jsxs as jsxs30 } from "react/jsx-runtime";
2635
2665
  var VALUE_CLASSES = "contents";
2636
2666
  function Property({ label, layout = "row", children, className }) {
2637
2667
  if (layout === "stacked") {
@@ -2640,20 +2670,20 @@ function Property({ label, layout = "row", children, className }) {
2640
2670
  // Peek's topic-details sections already sit at 12px, Ship's rail was
2641
2671
  // 6px, and unifying means the bigger, calmer one.
2642
2672
  /* @__PURE__ */ jsxs30("dl", { className: cn("flex flex-col gap-3", className), children: [
2643
- /* @__PURE__ */ jsx46("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
2644
- /* @__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 })
2645
2675
  ] })
2646
2676
  );
2647
2677
  }
2648
2678
  return /* @__PURE__ */ jsxs30("dl", { className: cn("flex items-center gap-2", className), children: [
2649
- /* @__PURE__ */ jsx46("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
2650
- /* @__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 })
2651
2681
  ] });
2652
2682
  }
2653
2683
 
2654
2684
  // src/Reaction.tsx
2655
2685
  import { Toggle } from "@base-ui/react/toggle";
2656
- import { jsx as jsx47, jsxs as jsxs31 } from "react/jsx-runtime";
2686
+ import { jsx as jsx48, jsxs as jsxs31 } from "react/jsx-runtime";
2657
2687
  function Reaction({ emoji, count, pressed = false, className, ...props }) {
2658
2688
  return /* @__PURE__ */ jsxs31(
2659
2689
  Toggle,
@@ -2677,8 +2707,8 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
2677
2707
  ),
2678
2708
  ...props,
2679
2709
  children: [
2680
- /* @__PURE__ */ jsx47("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
2681
- /* @__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 })
2682
2712
  ]
2683
2713
  }
2684
2714
  );
@@ -2687,7 +2717,7 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
2687
2717
  // src/SearchInput.tsx
2688
2718
  import "react";
2689
2719
  import { Input as Input3 } from "@base-ui/react/input";
2690
- import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
2720
+ import { jsx as jsx49, jsxs as jsxs32 } from "react/jsx-runtime";
2691
2721
  function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
2692
2722
  return /* @__PURE__ */ jsxs32(
2693
2723
  "div",
@@ -2701,7 +2731,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
2701
2731
  className
2702
2732
  ),
2703
2733
  children: [
2704
- /* @__PURE__ */ jsx48(
2734
+ /* @__PURE__ */ jsx49(
2705
2735
  Input3,
2706
2736
  {
2707
2737
  className: "flex-1 min-w-0 bg-transparent text-input-value text-text-primary placeholder:text-text-muted outline-none",
@@ -2709,7 +2739,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
2709
2739
  ...props
2710
2740
  }
2711
2741
  ),
2712
- shortcut && /* @__PURE__ */ jsx48(Kbd, { children: shortcut })
2742
+ shortcut && /* @__PURE__ */ jsx49(Kbd, { children: shortcut })
2713
2743
  ]
2714
2744
  }
2715
2745
  );
@@ -2718,17 +2748,17 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
2718
2748
  // src/SectionHeader.tsx
2719
2749
  import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
2720
2750
  import { useRender } from "@base-ui/react/use-render";
2721
- 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";
2722
2752
  function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", hover = "fill", render, className }) {
2723
2753
  const titleElement = useRender({
2724
- 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", {})),
2725
2755
  props: {
2726
2756
  // `text-left`: a button centres its text. `h-full` and `flex-1`: the
2727
2757
  // whole row up to the actions is the hit target, as it was when the
2728
2758
  // row itself carried the click.
2729
2759
  className: "flex h-full min-w-0 flex-1 items-center gap-1 text-left",
2730
2760
  children: /* @__PURE__ */ jsxs33(Fragment8, { children: [
2731
- chevron && /* @__PURE__ */ jsx49(
2761
+ chevron && /* @__PURE__ */ jsx50(
2732
2762
  IconChevronRight2,
2733
2763
  {
2734
2764
  size: 12,
@@ -2736,7 +2766,7 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2736
2766
  className: cn("shrink-0 text-text-secondary transition-transform duration-150", isExpanded && "rotate-90")
2737
2767
  }
2738
2768
  ),
2739
- /* @__PURE__ */ jsx49(SectionLabel, { children: title })
2769
+ /* @__PURE__ */ jsx50(SectionLabel, { children: title })
2740
2770
  ] })
2741
2771
  }
2742
2772
  });
@@ -2753,15 +2783,15 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2753
2783
  ),
2754
2784
  children: [
2755
2785
  titleElement,
2756
- trailing != null && /* @__PURE__ */ jsx49("div", { className: "flex shrink-0 items-center", children: trailing }),
2757
- 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(
2758
2788
  "div",
2759
2789
  {
2760
2790
  className: cn(
2761
2791
  "-mr-1 flex shrink-0 items-center gap-1",
2762
2792
  showActions === "hover" && "opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100"
2763
2793
  ),
2764
- 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))
2765
2795
  }
2766
2796
  )
2767
2797
  ]
@@ -2771,21 +2801,21 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2771
2801
 
2772
2802
  // src/ContainerHeader.tsx
2773
2803
  import { IconChevronDown as IconChevronDown3 } from "@tabler/icons-react";
2774
- import { jsx as jsx50, jsxs as jsxs34 } from "react/jsx-runtime";
2804
+ import { jsx as jsx51, jsxs as jsxs34 } from "react/jsx-runtime";
2775
2805
  function ContainerHeader({ title, chevron = false, actions, className }) {
2776
2806
  const text = typeof title === "string";
2777
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: [
2778
- /* @__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: [
2779
- 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 }),
2780
- 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" })
2781
2811
  ] }) }),
2782
- 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 }) })
2783
2813
  ] });
2784
2814
  }
2785
2815
 
2786
2816
  // src/ListColumn.tsx
2787
- import { jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
2788
- function ListColumn({ title, chevron = false, actions, above, spacing = "rows", collapsed = false, children, className }) {
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 }) {
2789
2819
  return /* @__PURE__ */ jsxs35(
2790
2820
  "div",
2791
2821
  {
@@ -2797,18 +2827,34 @@ function ListColumn({ title, chevron = false, actions, above, spacing = "rows",
2797
2827
  ),
2798
2828
  "data-collapsed": collapsed || void 0,
2799
2829
  children: [
2800
- /* @__PURE__ */ jsx51(ContainerHeader, { title, chevron, actions }),
2830
+ /* @__PURE__ */ jsx52(ContainerHeader, { title, chevron, actions }),
2801
2831
  above,
2802
- /* @__PURE__ */ jsx51(ScrollArea, { className: "flex-1", contentClassName: cn("flex flex-col px-3 pt-4 pb-3", spacing === "rows" ? "gap-0.5" : "gap-1"), children })
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 })
2803
2836
  ]
2804
2837
  }
2805
2838
  );
2806
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
+ }
2807
2853
 
2808
2854
  // src/CollapsibleSection.tsx
2809
2855
  import { useState as useState7 } from "react";
2810
2856
  import { Collapsible } from "@base-ui/react/collapsible";
2811
- import { jsx as jsx52, jsxs as jsxs36 } from "react/jsx-runtime";
2857
+ import { jsx as jsx53, jsxs as jsxs36 } from "react/jsx-runtime";
2812
2858
  var OPEN = "open";
2813
2859
  var CLOSED = "closed";
2814
2860
  function readStored(key) {
@@ -2836,13 +2882,13 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
2836
2882
  onOpenChange?.(next);
2837
2883
  };
2838
2884
  return /* @__PURE__ */ jsxs36(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
2839
- /* @__PURE__ */ jsx52(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx52(Collapsible.Trigger, {}) }),
2840
- /* @__PURE__ */ jsx52(
2885
+ /* @__PURE__ */ jsx53(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx53(Collapsible.Trigger, {}) }),
2886
+ /* @__PURE__ */ jsx53(
2841
2887
  Collapsible.Panel,
2842
2888
  {
2843
2889
  hiddenUntilFound: true,
2844
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",
2845
- children: /* @__PURE__ */ jsx52("div", { className: cn("flex flex-col", contentClassName), children })
2891
+ children: /* @__PURE__ */ jsx53("div", { className: cn("flex flex-col", contentClassName), children })
2846
2892
  }
2847
2893
  )
2848
2894
  ] });
@@ -2850,9 +2896,9 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
2850
2896
 
2851
2897
  // src/Tabs.tsx
2852
2898
  import { Tabs as BaseTabs } from "@base-ui/react/tabs";
2853
- import { jsx as jsx53, jsxs as jsxs37 } from "react/jsx-runtime";
2899
+ import { jsx as jsx54, jsxs as jsxs37 } from "react/jsx-runtime";
2854
2900
  function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
2855
- return /* @__PURE__ */ jsx53(
2901
+ return /* @__PURE__ */ jsx54(
2856
2902
  BaseTabs.Root,
2857
2903
  {
2858
2904
  value: active,
@@ -2860,7 +2906,7 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2860
2906
  if (details.reason === "none") onChange(value);
2861
2907
  },
2862
2908
  className,
2863
- children: /* @__PURE__ */ jsx53(
2909
+ children: /* @__PURE__ */ jsx54(
2864
2910
  BaseTabs.List,
2865
2911
  {
2866
2912
  activateOnFocus: true,
@@ -2882,7 +2928,7 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2882
2928
  tab.icon,
2883
2929
  /* @__PURE__ */ jsxs37("span", { className: "flex items-baseline", children: [
2884
2930
  tab.label,
2885
- tab.count !== void 0 ? /* @__PURE__ */ jsx53("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
2886
2932
  ] })
2887
2933
  ]
2888
2934
  },
@@ -2898,7 +2944,7 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2898
2944
  import { createContext as createContext5, useContext as useContext5, useMemo as useMemo4 } from "react";
2899
2945
  import { Toast as BaseToast } from "@base-ui/react/toast";
2900
2946
  import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
2901
- import { jsx as jsx54, jsxs as jsxs38 } from "react/jsx-runtime";
2947
+ import { jsx as jsx55, jsxs as jsxs38 } from "react/jsx-runtime";
2902
2948
  var SURFACE_STYLES = {
2903
2949
  success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
2904
2950
  brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
@@ -2934,16 +2980,16 @@ var pillClassName = (type, hasAction, className) => cn(
2934
2980
  );
2935
2981
  function LeadingIcon({ type }) {
2936
2982
  const Icon = ICONS[type];
2937
- return /* @__PURE__ */ jsx54(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]) });
2938
2984
  }
2939
2985
  function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
2940
2986
  const hasAction = !!(actionLabel && onAction);
2941
2987
  return /* @__PURE__ */ jsxs38("div", { className: pillClassName(type, hasAction, className), children: [
2942
2988
  /* @__PURE__ */ jsxs38("div", { className: "flex items-center gap-2 shrink-0", children: [
2943
- leadingIcon && /* @__PURE__ */ jsx54(LeadingIcon, { type }),
2944
- /* @__PURE__ */ jsx54("span", { className: LABEL_CLASSES, children: label })
2989
+ leadingIcon && /* @__PURE__ */ jsx55(LeadingIcon, { type }),
2990
+ /* @__PURE__ */ jsx55("span", { className: LABEL_CLASSES, children: label })
2945
2991
  ] }),
2946
- hasAction && /* @__PURE__ */ jsx54(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
2992
+ hasAction && /* @__PURE__ */ jsx55(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
2947
2993
  ] });
2948
2994
  }
2949
2995
  var ToastContext = createContext5(null);
@@ -2964,9 +3010,9 @@ function ToastProvider({ children }) {
2964
3010
  }),
2965
3011
  [manager]
2966
3012
  );
2967
- return /* @__PURE__ */ jsx54(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs38(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: [
2968
3014
  children,
2969
- /* @__PURE__ */ jsx54(BaseToast.Portal, { children: /* @__PURE__ */ jsx54(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx54(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, {}) }) })
2970
3016
  ] }) });
2971
3017
  }
2972
3018
  function ToastList() {
@@ -2982,17 +3028,17 @@ function ToastList() {
2982
3028
  className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
2983
3029
  children: [
2984
3030
  /* @__PURE__ */ jsxs38("div", { className: "flex items-center gap-2 shrink-0", children: [
2985
- leadingIcon && /* @__PURE__ */ jsx54(LeadingIcon, { type }),
2986
- /* @__PURE__ */ jsx54(BaseToast.Title, { render: /* @__PURE__ */ jsx54("span", {}), className: LABEL_CLASSES })
3031
+ leadingIcon && /* @__PURE__ */ jsx55(LeadingIcon, { type }),
3032
+ /* @__PURE__ */ jsx55(BaseToast.Title, { render: /* @__PURE__ */ jsx55("span", {}), className: LABEL_CLASSES })
2987
3033
  ] }),
2988
- actionLabel && /* @__PURE__ */ jsx54(
3034
+ actionLabel && /* @__PURE__ */ jsx55(
2989
3035
  BaseToast.Action,
2990
3036
  {
2991
3037
  onClick: () => {
2992
3038
  onAction?.();
2993
3039
  close(toast.id);
2994
3040
  },
2995
- render: /* @__PURE__ */ jsx54(Button, { variant: "outlined", size: "small", children: actionLabel })
3041
+ render: /* @__PURE__ */ jsx55(Button, { variant: "outlined", size: "small", children: actionLabel })
2996
3042
  }
2997
3043
  )
2998
3044
  ]
@@ -3032,6 +3078,7 @@ export {
3032
3078
  EditableText,
3033
3079
  EmptyState,
3034
3080
  EnterHint,
3081
+ ErrorBoundary,
3035
3082
  Field,
3036
3083
  FieldLine,
3037
3084
  FilePicker,
@@ -3051,6 +3098,7 @@ export {
3051
3098
  MenuPanel,
3052
3099
  MenuRow,
3053
3100
  MenuSection,
3101
+ MenuSeparator,
3054
3102
  MenuSub,
3055
3103
  NavItem,
3056
3104
  Person,