@estiva-app/ui 0.22.0 → 0.24.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 (173) hide show
  1. package/README.md +21 -0
  2. package/dist/AppShell.d.ts.map +1 -1
  3. package/dist/AttachmentCard.d.ts.map +1 -1
  4. package/dist/Banner.d.ts +20 -2
  5. package/dist/Banner.d.ts.map +1 -1
  6. package/dist/ContainerHeader.d.ts +25 -0
  7. package/dist/ContainerHeader.d.ts.map +1 -0
  8. package/dist/EmptyState.d.ts +10 -1
  9. package/dist/EmptyState.d.ts.map +1 -1
  10. package/dist/Form.d.ts.map +1 -1
  11. package/dist/IconButton.d.ts +9 -1
  12. package/dist/IconButton.d.ts.map +1 -1
  13. package/dist/PreviewCard.d.ts +9 -2
  14. package/dist/PreviewCard.d.ts.map +1 -1
  15. package/dist/SectionHeader.d.ts +7 -1
  16. package/dist/SectionHeader.d.ts.map +1 -1
  17. package/dist/Select.d.ts +11 -3
  18. package/dist/Select.d.ts.map +1 -1
  19. package/dist/Tooltip.d.ts +13 -1
  20. package/dist/Tooltip.d.ts.map +1 -1
  21. package/dist/eslint/index.js +2 -1
  22. package/dist/eslint/index.js.map +2 -2
  23. package/dist/eslint/no-restyled-part.d.ts.map +1 -1
  24. package/dist/gates/app-checks.d.ts.map +1 -1
  25. package/dist/gates/{chunk-ZGJ2J5NU.js → chunk-EA33NP5B.js} +275 -11
  26. package/dist/gates/chunk-EA33NP5B.js.map +7 -0
  27. package/dist/gates/{chunk-AUXD4GCY.js → chunk-GTQZEHPC.js} +15 -1
  28. package/dist/gates/chunk-GTQZEHPC.js.map +7 -0
  29. package/dist/gates/cli.js +1 -1
  30. package/dist/gates/create-app.d.ts +2 -0
  31. package/dist/gates/create-app.d.ts.map +1 -1
  32. package/dist/gates/create-app.js +1 -1
  33. package/dist/gates/index.js +25 -3
  34. package/dist/gates/index.js.map +2 -2
  35. package/dist/gates/status.d.ts +2 -0
  36. package/dist/gates/status.d.ts.map +1 -1
  37. package/dist/index.d.ts +1 -0
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +196 -156
  40. package/dist/index.js.map +4 -4
  41. package/dist/registry/app-DQI6WLHR.js +10 -0
  42. package/dist/registry/app.d.ts +21 -0
  43. package/dist/registry/app.d.ts.map +1 -0
  44. package/dist/registry/build-LGFCCOLR.js +27 -0
  45. package/dist/registry/build-LGFCCOLR.js.map +7 -0
  46. package/dist/registry/build.d.ts +68 -2
  47. package/dist/registry/build.d.ts.map +1 -1
  48. package/dist/registry/{chunk-MRSBS5OP.js → chunk-E4JNV7PC.js} +68 -12
  49. package/dist/registry/chunk-E4JNV7PC.js.map +7 -0
  50. package/dist/registry/{chunk-QDYGB3QN.js → chunk-NJN4MQAM.js} +60 -15
  51. package/dist/registry/chunk-NJN4MQAM.js.map +7 -0
  52. package/dist/registry/{chunk-IJNCYVH4.js → chunk-W2B2G7OE.js} +34 -9
  53. package/dist/registry/chunk-W2B2G7OE.js.map +7 -0
  54. package/dist/registry/chunk-WMFF3MPP.js +648 -0
  55. package/dist/registry/chunk-WMFF3MPP.js.map +7 -0
  56. package/dist/registry/cli.js +81 -26
  57. package/dist/registry/cli.js.map +3 -3
  58. package/dist/registry/find.d.ts +12 -1
  59. package/dist/registry/find.d.ts.map +1 -1
  60. package/dist/registry/index.d.ts +5 -2
  61. package/dist/registry/index.d.ts.map +1 -1
  62. package/dist/registry/index.js +11 -3
  63. package/dist/registry/schema.d.ts +83 -6
  64. package/dist/registry/schema.d.ts.map +1 -1
  65. package/package.json +2 -2
  66. package/registry.json +283 -95
  67. package/src/AppShell.mdx +10 -0
  68. package/src/AppShell.test.tsx +16 -0
  69. package/src/AppShell.tsx +4 -1
  70. package/src/AttachmentCard.mdx +9 -0
  71. package/src/AttachmentCard.test.tsx +10 -0
  72. package/src/AttachmentCard.tsx +8 -5
  73. package/src/Avatar.mdx +13 -3
  74. package/src/AvatarGroup.mdx +4 -0
  75. package/src/Banner.mdx +30 -7
  76. package/src/Banner.stories.tsx +22 -0
  77. package/src/Banner.test.tsx +35 -0
  78. package/src/Banner.tsx +34 -9
  79. package/src/Breadcrumb.mdx +10 -0
  80. package/src/Button.mdx +14 -3
  81. package/src/Card.mdx +9 -0
  82. package/src/Checkbox.mdx +10 -0
  83. package/src/Chip.mdx +4 -0
  84. package/src/ChipInput.mdx +12 -0
  85. package/src/CollapsibleSection.mdx +9 -0
  86. package/src/CommandPalette.mdx +14 -2
  87. package/src/ConfirmDialog.mdx +11 -0
  88. package/src/ContainerHeader.mdx +60 -0
  89. package/src/ContainerHeader.stories.tsx +62 -0
  90. package/src/ContainerHeader.test.tsx +47 -0
  91. package/src/ContainerHeader.tsx +45 -0
  92. package/src/DialogShell.mdx +14 -0
  93. package/src/Divider.mdx +9 -1
  94. package/src/EditableText.mdx +11 -0
  95. package/src/EmptyState.mdx +27 -4
  96. package/src/EmptyState.stories.tsx +6 -1
  97. package/src/EmptyState.test.tsx +18 -1
  98. package/src/EmptyState.tsx +14 -1
  99. package/src/Field.mdx +10 -1
  100. package/src/FieldLine.mdx +9 -1
  101. package/src/FilePicker.mdx +8 -0
  102. package/src/Form.mdx +10 -0
  103. package/src/Form.test.tsx +26 -0
  104. package/src/Form.tsx +7 -0
  105. package/src/IconButton.mdx +16 -2
  106. package/src/IconButton.stories.tsx +3 -0
  107. package/src/IconButton.test.tsx +25 -0
  108. package/src/IconButton.tsx +61 -46
  109. package/src/IdentityMenu.mdx +9 -0
  110. package/src/InlineChip.mdx +8 -0
  111. package/src/Kbd.mdx +4 -0
  112. package/src/Link.mdx +10 -0
  113. package/src/Menu.mdx +16 -1
  114. package/src/MenuItem.mdx +12 -2
  115. package/src/NavItem.mdx +8 -0
  116. package/src/Person.mdx +4 -0
  117. package/src/PersonTrigger.mdx +9 -0
  118. package/src/Popover.mdx +21 -0
  119. package/src/PreviewCard.mdx +19 -4
  120. package/src/PreviewCard.tsx +11 -4
  121. package/src/ProgressBar.mdx +8 -0
  122. package/src/Property.mdx +4 -0
  123. package/src/Rail.mdx +9 -1
  124. package/src/RailItem.mdx +8 -0
  125. package/src/Reaction.mdx +9 -0
  126. package/src/ReactionPicker.mdx +8 -0
  127. package/src/ScrollArea.mdx +13 -2
  128. package/src/SearchInput.mdx +9 -0
  129. package/src/SectionHeader.mdx +13 -0
  130. package/src/SectionHeader.stories.tsx +9 -0
  131. package/src/SectionHeader.test.tsx +9 -0
  132. package/src/SectionHeader.tsx +8 -2
  133. package/src/SectionLabel.mdx +4 -0
  134. package/src/Select.mdx +21 -2
  135. package/src/Select.stories.tsx +4 -1
  136. package/src/Select.test.tsx +17 -0
  137. package/src/Select.tsx +34 -13
  138. package/src/Sidebar.mdx +8 -0
  139. package/src/Skeleton.mdx +4 -0
  140. package/src/Tabs.mdx +12 -1
  141. package/src/TextInput.mdx +8 -0
  142. package/src/Textarea.mdx +8 -0
  143. package/src/Toast.mdx +12 -1
  144. package/src/Toolbar.mdx +11 -0
  145. package/src/Tooltip.mdx +26 -2
  146. package/src/Tooltip.stories.tsx +26 -0
  147. package/src/Tooltip.test.tsx +29 -0
  148. package/src/Tooltip.tsx +17 -4
  149. package/src/TopBar.mdx +4 -0
  150. package/src/eslint/no-rebuilt-behaviour.ts +1 -1
  151. package/src/eslint/no-restyled-part.ts +1 -0
  152. package/src/gates/app-checks.ts +23 -1
  153. package/src/gates/create-app.test.ts +77 -6
  154. package/src/gates/create-app.ts +288 -15
  155. package/src/gates/status.ts +16 -0
  156. package/src/index.ts +1 -0
  157. package/src/pages.test.ts +142 -0
  158. package/src/registry/app.test.ts +562 -0
  159. package/src/registry/app.ts +854 -0
  160. package/src/registry/build.ts +114 -25
  161. package/src/registry/cli.ts +105 -42
  162. package/src/registry/find.ts +45 -8
  163. package/src/registry/index.ts +8 -1
  164. package/src/registry/registry.test.ts +5 -5
  165. package/src/registry/schema.ts +163 -12
  166. package/tailwind-preset.js +22 -1
  167. package/dist/gates/chunk-AUXD4GCY.js.map +0 -7
  168. package/dist/gates/chunk-ZGJ2J5NU.js.map +0 -7
  169. package/dist/registry/build-GOVLABI6.js +0 -13
  170. package/dist/registry/chunk-IJNCYVH4.js.map +0 -7
  171. package/dist/registry/chunk-MRSBS5OP.js.map +0 -7
  172. package/dist/registry/chunk-QDYGB3QN.js.map +0 -7
  173. /package/dist/registry/{build-GOVLABI6.js.map → app-DQI6WLHR.js.map} +0 -0
package/dist/index.js CHANGED
@@ -91,25 +91,30 @@ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
91
91
  function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav, children }) {
92
92
  const bar = /* @__PURE__ */ jsx3(TopBar, { variant, menu, logo, search, right: identity });
93
93
  if (variant === "floating") {
94
- return /* @__PURE__ */ jsxs3("div", { className: "relative h-full min-h-0 overflow-hidden bg-bg-base", children: [
95
- bar,
96
- /* @__PURE__ */ jsxs3("div", { className: "flex h-full pb-4 pr-4 pt-[52px]", children: [
97
- nav,
98
- /* @__PURE__ */ jsxs3(
99
- "div",
100
- {
101
- className: cn(
102
- "flex min-w-0 flex-1 flex-col overflow-hidden rounded-2xl bg-bg-surface",
103
- "signal:border signal:border-border-subtle signal:shadow-highlight-inset"
104
- ),
105
- children: [
106
- banner,
107
- /* @__PURE__ */ jsx3("main", { className: "flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden", children })
108
- ]
109
- }
110
- )
94
+ return (
95
+ // `signal-canvas`: in the Signal theme, the preset draws the control-room dot
96
+ // grid behind everything in the frame (Peek's, moved here with the frame:
97
+ // UIG-14, Katerina, 19 September — the canvas is the theme's, not an app's).
98
+ /* @__PURE__ */ jsxs3("div", { className: "signal-canvas relative h-full min-h-0 overflow-hidden bg-bg-base", children: [
99
+ bar,
100
+ /* @__PURE__ */ jsxs3("div", { className: "flex h-full pb-4 pr-4 pt-[52px]", children: [
101
+ nav,
102
+ /* @__PURE__ */ jsxs3(
103
+ "div",
104
+ {
105
+ className: cn(
106
+ "flex min-w-0 flex-1 flex-col overflow-hidden rounded-2xl bg-bg-surface",
107
+ "signal:border signal:border-border-subtle signal:shadow-highlight-inset"
108
+ ),
109
+ children: [
110
+ banner,
111
+ /* @__PURE__ */ jsx3("main", { className: "flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden", children })
112
+ ]
113
+ }
114
+ )
115
+ ] })
111
116
  ] })
112
- ] });
117
+ );
113
118
  }
114
119
  return (
115
120
  /* `relative overflow-hidden` is the seal the floating manner already has
@@ -283,8 +288,8 @@ function TooltipProvider({ delay = OPEN_DELAY, closeDelay, timeout, children })
283
288
  return /* @__PURE__ */ jsx7(BaseTooltip.Provider, { delay, closeDelay, timeout, children });
284
289
  }
285
290
  function Tooltip({ label, shortcut, className, ...props }) {
286
- return /* @__PURE__ */ jsxs4("div", { role: "tooltip", className: cn("bg-bg-elevated border border-border-default rounded-lg h-[30px] flex items-center justify-center gap-1.5 px-2 shadow-lg", className), ...props, children: [
287
- /* @__PURE__ */ jsx7("span", { className: "text-caption text-text-primary whitespace-nowrap", children: label }),
291
+ return /* @__PURE__ */ jsxs4("div", { role: "tooltip", className: cn("bg-bg-elevated border border-border-default rounded-lg min-h-[30px] max-w-80 flex items-center justify-center gap-1.5 px-2 py-1 shadow-lg", className), ...props, children: [
292
+ /* @__PURE__ */ jsx7("span", { className: "min-w-0 text-caption text-text-primary break-words", children: label }),
288
293
  shortcut && /* @__PURE__ */ jsx7(Kbd, { children: shortcut })
289
294
  ] });
290
295
  }
@@ -316,9 +321,10 @@ function TooltipSurface({ label, shortcut, placement }) {
316
321
  }
317
322
  ) });
318
323
  }
319
- function WithTooltip({ label, shortcut, placement = "top", wrapperClassName, children }) {
324
+ function WithTooltip({ label, shortcut, placement = "top", wrapperClassName, inline = false, children }) {
325
+ const Wrapper = inline ? "span" : "div";
320
326
  return /* @__PURE__ */ jsxs4(BaseTooltip.Root, { disableHoverablePopup: true, children: [
321
- /* @__PURE__ */ jsx7(BaseTooltip.Trigger, { delay: OPEN_DELAY, render: /* @__PURE__ */ jsx7("div", { 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", wrapperClassName) }), children }),
322
328
  /* @__PURE__ */ jsx7(TooltipSurface, { label, shortcut, placement })
323
329
  ] });
324
330
  }
@@ -343,48 +349,51 @@ function IconButton({
343
349
  tooltipShortcut,
344
350
  tooltipPlacement,
345
351
  type = "button",
352
+ href,
346
353
  ...props
347
354
  }) {
348
355
  const formBusy = useFormBusy();
349
- const button = /* @__PURE__ */ jsx8(
356
+ const unusable = disabled || !!disabledReason || formBusy;
357
+ const look = (off) => cn(
358
+ // `shrink-0` stops a flex parent squashing the button; `self-center`
359
+ // stops one stretching it. Two different failures, and both have
360
+ // happened here: a row with no `items-*` drew this 24 wide and 228
361
+ // tall in Peek's TopicMoreMenu story (Katerina, 2026-09-11). A button
362
+ // is the size of its icon and its padding, whatever box it lands in.
363
+ //
364
+ // This is the one of the two that needs it: an IconButton states no
365
+ // height, so its cross size is `auto` and a stretching parent takes
366
+ // it. Measured in the same 260px row on 2026-09-12: 24px with this
367
+ // class, 226px without. `Button` states `h-8`/`h-6`, so it cannot be
368
+ // stretched and carries no `self-center` — see the note there.
369
+ "flex items-center justify-center p-1 rounded-lg transition-colors shrink-0 self-center cursor-pointer",
370
+ !off && variant === "primary" && "bg-accent-primary hover:bg-accent-hover text-text-inverse",
371
+ !off && (variant === "muted" || variant === "resolve") && "text-text-secondary hover:bg-bg-hover hover:text-text-primary",
372
+ !off && variant === "outlined" && "border border-border-default hover:bg-bg-hover text-text-secondary",
373
+ !off && variant === "current" && "hover:bg-bg-hover",
374
+ off && variant === "primary" && "bg-bg-disabled text-text-disabled",
375
+ off && (variant === "muted" || variant === "resolve") && "text-text-disabled",
376
+ off && variant === "outlined" && "border border-border-default text-text-disabled",
377
+ // Always, disabled too: the colour of where it sits, and Resolve's green.
378
+ variant === "current" && "text-current",
379
+ variant === "resolve" && "signal:hover:bg-success-muted signal:hover:text-success-default",
380
+ pressed && "bg-bg-active text-text-primary",
381
+ glow && "signal:shadow-glow-accent",
382
+ // `pointer-events-none` only where the button is truly out of reach:
383
+ // with a `disabledReason` the button IS the tooltip's trigger, and a
384
+ // trigger the pointer cannot land on never opens one. Base UI already
385
+ // swallows the click.
386
+ off && !disabledReason && "pointer-events-none",
387
+ off && "cursor-not-allowed",
388
+ className
389
+ );
390
+ const button = href && !unusable ? /* @__PURE__ */ jsx8("a", { href, className: look(false), ...props, children }) : /* @__PURE__ */ jsx8(
350
391
  BaseButton,
351
392
  {
352
393
  type,
353
- disabled: disabled || !!disabledReason || formBusy,
394
+ disabled: unusable,
354
395
  focusableWhenDisabled: !!disabledReason,
355
- className: (state) => cn(
356
- // `shrink-0` stops a flex parent squashing the button; `self-center`
357
- // stops one stretching it. Two different failures, and both have
358
- // happened here: a row with no `items-*` drew this 24 wide and 228
359
- // tall in Peek's TopicMoreMenu story (Katerina, 2026-09-11). A button
360
- // is the size of its icon and its padding, whatever box it lands in.
361
- //
362
- // This is the one of the two that needs it: an IconButton states no
363
- // height, so its cross size is `auto` and a stretching parent takes
364
- // it. Measured in the same 260px row on 2026-09-12: 24px with this
365
- // class, 226px without. `Button` states `h-8`/`h-6`, so it cannot be
366
- // stretched and carries no `self-center` — see the note there.
367
- "flex items-center justify-center p-1 rounded-lg transition-colors shrink-0 self-center cursor-pointer",
368
- !state.disabled && variant === "primary" && "bg-accent-primary hover:bg-accent-hover text-text-inverse",
369
- !state.disabled && (variant === "muted" || variant === "resolve") && "text-text-secondary hover:bg-bg-hover hover:text-text-primary",
370
- !state.disabled && variant === "outlined" && "border border-border-default hover:bg-bg-hover text-text-secondary",
371
- !state.disabled && variant === "current" && "hover:bg-bg-hover",
372
- state.disabled && variant === "primary" && "bg-bg-disabled text-text-disabled",
373
- state.disabled && (variant === "muted" || variant === "resolve") && "text-text-disabled",
374
- state.disabled && variant === "outlined" && "border border-border-default text-text-disabled",
375
- // Always, disabled too: the colour of where it sits, and Resolve's green.
376
- variant === "current" && "text-current",
377
- variant === "resolve" && "signal:hover:bg-success-muted signal:hover:text-success-default",
378
- pressed && "bg-bg-active text-text-primary",
379
- glow && "signal:shadow-glow-accent",
380
- // `pointer-events-none` only where the button is truly out of reach:
381
- // with a `disabledReason` the button IS the tooltip's trigger, and a
382
- // trigger the pointer cannot land on never opens one. Base UI already
383
- // swallows the click.
384
- state.disabled && !disabledReason && "pointer-events-none",
385
- state.disabled && "cursor-not-allowed",
386
- className
387
- ),
396
+ className: (state) => look(state.disabled),
388
397
  "aria-pressed": pressed,
389
398
  ...props,
390
399
  children
@@ -434,7 +443,7 @@ function TypeIcon({ name }) {
434
443
  const Icon = ICON_BY_EXTENSION[extensionOf(name)] ?? IconFile;
435
444
  return /* @__PURE__ */ jsx9(Icon, { size: 20, stroke: 1.5 });
436
445
  }
437
- function Truncating({ text, hint, className, wrapperClassName }) {
446
+ function Truncating({ text, hint, className, wrapperClassName, placement }) {
438
447
  const ref = useRef(null);
439
448
  const [cut, setCut] = useState(false);
440
449
  useLayoutEffect(() => {
@@ -456,7 +465,7 @@ function Truncating({ text, hint, className, wrapperClassName }) {
456
465
  }, [text, cut]);
457
466
  const line = /* @__PURE__ */ jsx9("span", { ref, className, children: text });
458
467
  if (!hint && !cut) return line;
459
- return /* @__PURE__ */ jsx9(WithTooltip, { label: hint ?? text, wrapperClassName: cn("min-w-0 flex-col", wrapperClassName), children: line });
468
+ return /* @__PURE__ */ jsx9(WithTooltip, { label: hint ?? text, placement, wrapperClassName: cn("min-w-0 flex-col", wrapperClassName), children: line });
460
469
  }
461
470
  function AttachmentCard({
462
471
  name,
@@ -490,7 +499,7 @@ function AttachmentCard({
490
499
  children: [
491
500
  /* @__PURE__ */ jsx9("div", { className: cn(TILE_CLASSES, "overflow-hidden"), children: state === "uploading" ? /* @__PURE__ */ jsx9(IconLoader2, { size: 16, stroke: 1.5, className: "animate-spin" }) : failed ? /* @__PURE__ */ jsx9(IconAlertCircle, { size: 16, stroke: 1.5, className: "text-error-default" }) : warning ? /* @__PURE__ */ jsx9(IconAlertTriangle, { size: 16, stroke: 1.5, className: "text-warning-default" }) : image && src ? /* @__PURE__ */ jsx9("img", { src, alt: name, className: "size-full object-cover" }) : /* @__PURE__ */ jsx9("span", { className: "text-menu font-semibold", children: typeLabelOf(name) }) }),
492
501
  /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-[1px] min-w-0", children: [
493
- /* @__PURE__ */ jsx9(Truncating, { text: name, className: NAME_CLASSES }),
502
+ /* @__PURE__ */ jsx9(Truncating, { text: name, className: NAME_CLASSES, placement: onRemove ? "bottom" : void 0 }),
494
503
  /* @__PURE__ */ jsx9(
495
504
  Truncating,
496
505
  {
@@ -505,7 +514,7 @@ function AttachmentCard({
505
514
  {
506
515
  type: "button",
507
516
  "aria-label": `Remove ${name}`,
508
- className: "absolute -top-1.5 -right-1.5 size-5 rounded-full bg-bg-elevated border border-border-strong flex items-center justify-center text-text-secondary hover:text-text-primary opacity-0 group-hover:opacity-100 transition-opacity",
517
+ className: "absolute -top-1.5 -right-1.5 size-5 rounded-full bg-bg-elevated border border-border-strong flex items-center justify-center text-text-secondary hover:text-text-primary opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100 transition-opacity",
509
518
  onClick: (event) => {
510
519
  event.stopPropagation();
511
520
  onRemove();
@@ -678,27 +687,10 @@ function AvatarGroup({ members, size = 24 }) {
678
687
 
679
688
  // src/Banner.tsx
680
689
  import { IconX as IconX2 } from "@tabler/icons-react";
681
- import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
682
- var TONE_STYLES = {
683
- ok: "bg-success-muted text-success-default",
684
- error: "bg-error-muted text-error-default",
685
- info: "bg-info-muted text-info-default",
686
- warning: "bg-warning-muted text-warning-default"
687
- };
688
- function Banner({ tone, children, onDismiss, dismissLabel = "Dismiss", className }) {
689
- const role = tone === "error" ? "alert" : "status";
690
- if (!onDismiss) {
691
- return /* @__PURE__ */ jsx12("div", { role, className: cn("px-4 py-2 text-body-2", TONE_STYLES[tone], className), children });
692
- }
693
- return /* @__PURE__ */ jsxs7("div", { role, className: cn("flex items-center gap-3 px-4 py-2 text-body-2", TONE_STYLES[tone], className), children: [
694
- /* @__PURE__ */ jsx12("span", { className: "min-w-0 flex-1", children }),
695
- /* @__PURE__ */ jsx12(IconButton, { variant: "current", "aria-label": dismissLabel, onClick: onDismiss, className: "-mr-1 shrink-0", children: /* @__PURE__ */ jsx12(IconX2, { size: 16, stroke: 1.5 }) })
696
- ] });
697
- }
698
690
 
699
691
  // src/Button.tsx
700
692
  import { Button as BaseButton3 } from "@base-ui/react/button";
701
- import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
693
+ import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
702
694
  function Button({
703
695
  variant = "muted",
704
696
  size = "default",
@@ -712,7 +704,7 @@ function Button({
712
704
  }) {
713
705
  const hasLeadingIcon = !!leadingIcon;
714
706
  const formBusy = useFormBusy();
715
- const button = /* @__PURE__ */ jsxs8(
707
+ const button = /* @__PURE__ */ jsxs7(
716
708
  BaseButton3,
717
709
  {
718
710
  type,
@@ -759,7 +751,29 @@ function Button({
759
751
  ]
760
752
  }
761
753
  );
762
- return disabledReason ? /* @__PURE__ */ jsx13(TooltipTrigger, { label: disabledReason, children: button }) : button;
754
+ return disabledReason ? /* @__PURE__ */ jsx12(TooltipTrigger, { label: disabledReason, children: button }) : button;
755
+ }
756
+
757
+ // src/Banner.tsx
758
+ import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
759
+ var TONE_STYLES = {
760
+ ok: "bg-success-muted text-success-default",
761
+ error: "bg-error-muted text-error-default",
762
+ info: "bg-info-muted text-info-default",
763
+ warning: "bg-warning-muted text-warning-default"
764
+ };
765
+ function Banner({ tone, children, icon, action, onDismiss, dismissLabel = "Dismiss", className }) {
766
+ const role = tone === "error" ? "alert" : "status";
767
+ if (!onDismiss && !icon && !action) {
768
+ return /* @__PURE__ */ jsx13("div", { role, className: cn("px-4 py-2 text-body-2", TONE_STYLES[tone], className), children });
769
+ }
770
+ const oneLine = Boolean(icon || action);
771
+ return /* @__PURE__ */ jsxs8("div", { role, className: cn("flex items-center gap-3 px-4 py-2 text-body-2", TONE_STYLES[tone], className), children: [
772
+ icon && /* @__PURE__ */ jsx13("span", { className: "flex shrink-0", children: icon }),
773
+ /* @__PURE__ */ jsx13("span", { className: cn("min-w-0 flex-1", oneLine && "truncate"), children }),
774
+ action && /* @__PURE__ */ jsx13(Button, { variant: "muted", size: "small", className: "shrink-0", onClick: action.onClick, children: action.label }),
775
+ onDismiss && /* @__PURE__ */ jsx13(IconButton, { variant: "current", "aria-label": dismissLabel, onClick: onDismiss, className: "-mr-1 shrink-0", children: /* @__PURE__ */ jsx13(IconX2, { size: 16, stroke: 1.5 }) })
776
+ ] });
763
777
  }
764
778
 
765
779
  // src/Checkbox.tsx
@@ -1281,13 +1295,14 @@ var VIEWPORT_PAD3 = 8;
1281
1295
  // src/EmptyState.tsx
1282
1296
  import { IconMessage2 } from "@tabler/icons-react";
1283
1297
  import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
1284
- function EmptyState({ icon, message, scope = "page", className }) {
1298
+ function EmptyState({ icon, message, scope = "page", action, className }) {
1285
1299
  if (scope === "section") {
1286
1300
  return /* @__PURE__ */ jsx20("p", { className: cn("text-caption text-text-muted", className), children: message });
1287
1301
  }
1288
1302
  return /* @__PURE__ */ jsxs14("div", { className: cn("flex flex-1 flex-col items-center justify-center gap-2", className), children: [
1289
1303
  /* @__PURE__ */ jsx20("span", { className: "text-text-secondary", children: icon ?? /* @__PURE__ */ jsx20(IconMessage2, { size: 16, stroke: 1.5 }) }),
1290
- /* @__PURE__ */ jsx20("p", { className: "text-body-2 text-text-secondary text-center", children: message })
1304
+ /* @__PURE__ */ jsx20("p", { className: "text-body-2 text-text-secondary text-center", children: message }),
1305
+ action && /* @__PURE__ */ jsx20(Button, { variant: "outlined", className: "mt-2", onClick: action.onClick, children: action.label })
1291
1306
  ] });
1292
1307
  }
1293
1308
 
@@ -1400,6 +1415,7 @@ function Form({ onSubmit, busy: ownBusy = false, enterSends = true, className, c
1400
1415
  },
1401
1416
  onKeyDown,
1402
1417
  onSubmit: (event) => {
1418
+ if (event.target !== event.currentTarget) return;
1403
1419
  event.preventDefault();
1404
1420
  if (busyNow.current) return;
1405
1421
  void onSubmit();
@@ -1938,56 +1954,65 @@ import { Select as BaseSelect } from "@base-ui/react/select";
1938
1954
  import { jsx as jsx30, jsxs as jsxs22 } from "react/jsx-runtime";
1939
1955
  var GAP4 = 4;
1940
1956
  var VIEWPORT_PAD4 = 8;
1941
- function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, className, ...aria }) {
1957
+ function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, disabledReason, className, ...aria }) {
1942
1958
  const selected = options.find((o) => o.value === value);
1959
+ const held = Boolean(disabledReason) && !disabled;
1960
+ const trigger = /* @__PURE__ */ jsxs22(
1961
+ BaseSelect.Trigger,
1962
+ {
1963
+ "aria-label": ariaLabel,
1964
+ "aria-required": aria["aria-required"],
1965
+ "aria-disabled": held || void 0,
1966
+ className: cn(
1967
+ /*
1968
+ * `min-w-0 max-w-full`: a trigger must never outgrow its container
1969
+ * (Katerina, 2026-09-01 — a long label stretched the files panel's
1970
+ * Lead row past its card). In a flex row the default min-width:auto
1971
+ * forbids shrinking below the label's width, which is what kept
1972
+ * `truncate` from ever engaging; in a block container max-w-full is
1973
+ * the cap. Full-width callers are unaffected.
1974
+ */
1975
+ "flex w-full min-w-0 max-w-full items-center justify-between gap-2 rounded-lg border bg-bg-inset text-left",
1976
+ "border-border-default text-text-primary outline-none transition-colors",
1977
+ // The focused border survives a hover: hover alone strengthens the
1978
+ // hairline, but hover while focused must not grey the focus colour —
1979
+ // the stacked variant outranks plain hover by specificity.
1980
+ !held && "hover:border-border-strong focus-visible:hover:border-border-focus aria-expanded:hover:border-border-focus",
1981
+ "disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled",
1982
+ held && "cursor-not-allowed bg-bg-disabled text-text-disabled",
1983
+ "focus-visible:border-border-focus aria-expanded:border-border-focus",
1984
+ "signal:transition-shadow signal:focus-visible:shadow-focus-ring",
1985
+ size === "default" && "px-3 py-2 text-input-value",
1986
+ size === "small" && "h-6 px-2 text-caption",
1987
+ className
1988
+ ),
1989
+ children: [
1990
+ /* @__PURE__ */ jsxs22("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
1991
+ selected?.leading && /* @__PURE__ */ jsx30("span", { className: "flex shrink-0 items-center", children: selected.leading }),
1992
+ /* @__PURE__ */ jsx30(BaseSelect.Value, { className: "truncate", children: () => selected?.label ?? placeholder })
1993
+ ] }),
1994
+ /* @__PURE__ */ jsx30(
1995
+ BaseSelect.Icon,
1996
+ {
1997
+ render: /* @__PURE__ */ jsx30(IconChevronDown2, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
1998
+ }
1999
+ )
2000
+ ]
2001
+ }
2002
+ );
1943
2003
  return /* @__PURE__ */ jsxs22(
1944
2004
  BaseSelect.Root,
1945
2005
  {
1946
2006
  value,
1947
- onValueChange: (next) => onChange(next),
2007
+ onValueChange: (next) => {
2008
+ if (!held) onChange(next);
2009
+ },
2010
+ ...held ? { open: false, onOpenChange: () => {
2011
+ } } : {},
1948
2012
  disabled,
1949
2013
  modal: false,
1950
2014
  children: [
1951
- /* @__PURE__ */ jsxs22(
1952
- BaseSelect.Trigger,
1953
- {
1954
- "aria-label": ariaLabel,
1955
- "aria-required": aria["aria-required"],
1956
- className: cn(
1957
- /*
1958
- * `min-w-0 max-w-full`: a trigger must never outgrow its container
1959
- * (Katerina, 2026-09-01 — a long label stretched the files panel's
1960
- * Lead row past its card). In a flex row the default min-width:auto
1961
- * forbids shrinking below the label's width, which is what kept
1962
- * `truncate` from ever engaging; in a block container max-w-full is
1963
- * the cap. Full-width callers are unaffected.
1964
- */
1965
- "flex w-full min-w-0 max-w-full items-center justify-between gap-2 rounded-lg border bg-bg-inset text-left",
1966
- "border-border-default text-text-primary outline-none transition-colors",
1967
- // The focused border survives a hover: hover alone strengthens the
1968
- // hairline, but hover while focused must not grey the focus colour —
1969
- // the stacked variant outranks plain hover by specificity.
1970
- "hover:border-border-strong focus-visible:hover:border-border-focus aria-expanded:hover:border-border-focus disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled",
1971
- "focus-visible:border-border-focus aria-expanded:border-border-focus",
1972
- "signal:transition-shadow signal:focus-visible:shadow-focus-ring",
1973
- size === "default" && "px-3 py-2 text-input-value",
1974
- size === "small" && "h-6 px-2 text-caption",
1975
- className
1976
- ),
1977
- children: [
1978
- /* @__PURE__ */ jsxs22("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
1979
- selected?.leading && /* @__PURE__ */ jsx30("span", { className: "flex shrink-0 items-center", children: selected.leading }),
1980
- /* @__PURE__ */ jsx30(BaseSelect.Value, { className: "truncate", children: () => selected?.label ?? placeholder })
1981
- ] }),
1982
- /* @__PURE__ */ jsx30(
1983
- BaseSelect.Icon,
1984
- {
1985
- render: /* @__PURE__ */ jsx30(IconChevronDown2, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
1986
- }
1987
- )
1988
- ]
1989
- }
1990
- ),
2015
+ held ? /* @__PURE__ */ jsx30(TooltipTrigger, { label: disabledReason ?? "", children: trigger }) : trigger,
1991
2016
  /* @__PURE__ */ jsx30(BaseSelect.Portal, { children: /* @__PURE__ */ jsx30(
1992
2017
  BaseSelect.Positioner,
1993
2018
  {
@@ -2515,7 +2540,7 @@ var GAP6 = 12;
2515
2540
  var VIEWPORT_PAD6 = 8;
2516
2541
  var OPEN_DELAY2 = 350;
2517
2542
  var CLOSE_DELAY = 200;
2518
- function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, wrapperClassName }) {
2543
+ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, contentClassName, wrapperClassName }) {
2519
2544
  return /* @__PURE__ */ jsxs28(BasePreviewCard.Root, { children: [
2520
2545
  /* @__PURE__ */ jsx42(
2521
2546
  BasePreviewCard.Trigger,
@@ -2537,9 +2562,9 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
2537
2562
  children: /* @__PURE__ */ jsx42(
2538
2563
  BasePreviewCard.Popup,
2539
2564
  {
2540
- className: cn("w-[360px] p-3 outline-none", className),
2565
+ className: cn("w-[360px] p-0 outline-none", className),
2541
2566
  render: /* @__PURE__ */ jsx42(MenuPanel, {}),
2542
- children: /* @__PURE__ */ jsx42(ScrollArea, { viewportClassName: "max-h-[calc(min(300px,var(--available-height))_-_1.5rem)]", contentClassName: "flex flex-col gap-3", children: content })
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 })
2543
2568
  }
2544
2569
  )
2545
2570
  }
@@ -2691,7 +2716,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
2691
2716
  import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
2692
2717
  import { useRender } from "@base-ui/react/use-render";
2693
2718
  import { Fragment as Fragment8, jsx as jsx49, jsxs as jsxs33 } from "react/jsx-runtime";
2694
- function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", render, className }) {
2719
+ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", hover = "fill", render, className }) {
2695
2720
  const titleElement = useRender({
2696
2721
  render: render ?? (chevron ? /* @__PURE__ */ jsx49("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx49("span", {})),
2697
2722
  props: {
@@ -2720,7 +2745,7 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2720
2745
  // The fill says "this does something": a row with a toggle or actions
2721
2746
  // lights up, a fixed heading over rows does not (2026-09-09, the
2722
2747
  // Sidebar's fixed group).
2723
- (chevron || actions && actions.length > 0) && "hover:bg-bg-hover",
2748
+ hover === "fill" && (chevron || actions && actions.length > 0) && "hover:bg-bg-hover",
2724
2749
  className
2725
2750
  ),
2726
2751
  children: [
@@ -2741,10 +2766,24 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2741
2766
  );
2742
2767
  }
2743
2768
 
2769
+ // src/ContainerHeader.tsx
2770
+ import { IconChevronDown as IconChevronDown3 } from "@tabler/icons-react";
2771
+ import { jsx as jsx50, jsxs as jsxs34 } from "react/jsx-runtime";
2772
+ function ContainerHeader({ title, chevron = false, actions, className }) {
2773
+ const text = typeof title === "string";
2774
+ 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" })
2778
+ ] }) }),
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 }) })
2780
+ ] });
2781
+ }
2782
+
2744
2783
  // src/CollapsibleSection.tsx
2745
2784
  import { useState as useState7 } from "react";
2746
2785
  import { Collapsible } from "@base-ui/react/collapsible";
2747
- import { jsx as jsx50, jsxs as jsxs34 } from "react/jsx-runtime";
2786
+ import { jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
2748
2787
  var OPEN = "open";
2749
2788
  var CLOSED = "closed";
2750
2789
  function readStored(key) {
@@ -2771,14 +2810,14 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
2771
2810
  writeStored(storageKey, next);
2772
2811
  onOpenChange?.(next);
2773
2812
  };
2774
- return /* @__PURE__ */ jsxs34(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
2775
- /* @__PURE__ */ jsx50(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx50(Collapsible.Trigger, {}) }),
2776
- /* @__PURE__ */ jsx50(
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(
2777
2816
  Collapsible.Panel,
2778
2817
  {
2779
2818
  hiddenUntilFound: true,
2780
2819
  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",
2781
- children: /* @__PURE__ */ jsx50("div", { className: cn("flex flex-col", contentClassName), children })
2820
+ children: /* @__PURE__ */ jsx51("div", { className: cn("flex flex-col", contentClassName), children })
2782
2821
  }
2783
2822
  )
2784
2823
  ] });
@@ -2786,9 +2825,9 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
2786
2825
 
2787
2826
  // src/Tabs.tsx
2788
2827
  import { Tabs as BaseTabs } from "@base-ui/react/tabs";
2789
- import { jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
2828
+ import { jsx as jsx52, jsxs as jsxs36 } from "react/jsx-runtime";
2790
2829
  function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
2791
- return /* @__PURE__ */ jsx51(
2830
+ return /* @__PURE__ */ jsx52(
2792
2831
  BaseTabs.Root,
2793
2832
  {
2794
2833
  value: active,
@@ -2796,14 +2835,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2796
2835
  if (details.reason === "none") onChange(value);
2797
2836
  },
2798
2837
  className,
2799
- children: /* @__PURE__ */ jsx51(
2838
+ children: /* @__PURE__ */ jsx52(
2800
2839
  BaseTabs.List,
2801
2840
  {
2802
2841
  activateOnFocus: true,
2803
2842
  "aria-label": aria["aria-label"],
2804
2843
  "aria-labelledby": aria["aria-labelledby"],
2805
2844
  className: "flex items-center gap-2",
2806
- children: tabs.map((tab) => /* @__PURE__ */ jsxs35(
2845
+ children: tabs.map((tab) => /* @__PURE__ */ jsxs36(
2807
2846
  BaseTabs.Tab,
2808
2847
  {
2809
2848
  value: tab.id,
@@ -2816,9 +2855,9 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2816
2855
  ),
2817
2856
  children: [
2818
2857
  tab.icon,
2819
- /* @__PURE__ */ jsxs35("span", { className: "flex items-baseline", children: [
2858
+ /* @__PURE__ */ jsxs36("span", { className: "flex items-baseline", children: [
2820
2859
  tab.label,
2821
- tab.count !== void 0 ? /* @__PURE__ */ jsx51("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
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
2822
2861
  ] })
2823
2862
  ]
2824
2863
  },
@@ -2834,7 +2873,7 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2834
2873
  import { createContext as createContext5, useContext as useContext5, useMemo as useMemo4 } from "react";
2835
2874
  import { Toast as BaseToast } from "@base-ui/react/toast";
2836
2875
  import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
2837
- import { jsx as jsx52, jsxs as jsxs36 } from "react/jsx-runtime";
2876
+ import { jsx as jsx53, jsxs as jsxs37 } from "react/jsx-runtime";
2838
2877
  var SURFACE_STYLES = {
2839
2878
  success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
2840
2879
  brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
@@ -2870,16 +2909,16 @@ var pillClassName = (type, hasAction, className) => cn(
2870
2909
  );
2871
2910
  function LeadingIcon({ type }) {
2872
2911
  const Icon = ICONS[type];
2873
- return /* @__PURE__ */ jsx52(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
2912
+ return /* @__PURE__ */ jsx53(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
2874
2913
  }
2875
2914
  function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
2876
2915
  const hasAction = !!(actionLabel && onAction);
2877
- return /* @__PURE__ */ jsxs36("div", { className: pillClassName(type, hasAction, className), children: [
2878
- /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2 shrink-0", children: [
2879
- leadingIcon && /* @__PURE__ */ jsx52(LeadingIcon, { type }),
2880
- /* @__PURE__ */ jsx52("span", { className: LABEL_CLASSES, children: label })
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 })
2881
2920
  ] }),
2882
- hasAction && /* @__PURE__ */ jsx52(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
2921
+ hasAction && /* @__PURE__ */ jsx53(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
2883
2922
  ] });
2884
2923
  }
2885
2924
  var ToastContext = createContext5(null);
@@ -2900,9 +2939,9 @@ function ToastProvider({ children }) {
2900
2939
  }),
2901
2940
  [manager]
2902
2941
  );
2903
- return /* @__PURE__ */ jsx52(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs36(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
2942
+ return /* @__PURE__ */ jsx53(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs37(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
2904
2943
  children,
2905
- /* @__PURE__ */ jsx52(BaseToast.Portal, { children: /* @__PURE__ */ jsx52(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx52(ToastList, {}) }) })
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, {}) }) })
2906
2945
  ] }) });
2907
2946
  }
2908
2947
  function ToastList() {
@@ -2910,25 +2949,25 @@ function ToastList() {
2910
2949
  return toasts.map((toast) => {
2911
2950
  const type = toast.type ?? "neutral";
2912
2951
  const { leadingIcon = true, actionLabel, onAction } = toast.data ?? {};
2913
- return /* @__PURE__ */ jsxs36(
2952
+ return /* @__PURE__ */ jsxs37(
2914
2953
  BaseToast.Root,
2915
2954
  {
2916
2955
  toast,
2917
2956
  swipeDirection: ["left", "down"],
2918
2957
  className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
2919
2958
  children: [
2920
- /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2 shrink-0", children: [
2921
- leadingIcon && /* @__PURE__ */ jsx52(LeadingIcon, { type }),
2922
- /* @__PURE__ */ jsx52(BaseToast.Title, { render: /* @__PURE__ */ jsx52("span", {}), className: LABEL_CLASSES })
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 })
2923
2962
  ] }),
2924
- actionLabel && /* @__PURE__ */ jsx52(
2963
+ actionLabel && /* @__PURE__ */ jsx53(
2925
2964
  BaseToast.Action,
2926
2965
  {
2927
2966
  onClick: () => {
2928
2967
  onAction?.();
2929
2968
  close(toast.id);
2930
2969
  },
2931
- render: /* @__PURE__ */ jsx52(Button, { variant: "outlined", size: "small", children: actionLabel })
2970
+ render: /* @__PURE__ */ jsx53(Button, { variant: "outlined", size: "small", children: actionLabel })
2932
2971
  }
2933
2972
  )
2934
2973
  ]
@@ -2962,6 +3001,7 @@ export {
2962
3001
  CommandPaletteSearch,
2963
3002
  CommandPaletteWorking,
2964
3003
  ConfirmDialog,
3004
+ ContainerHeader,
2965
3005
  DialogShell,
2966
3006
  Divider,
2967
3007
  EditableText,