@godxjp/ui 18.15.4 → 19.0.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 (145) hide show
  1. package/dist/app/date-format-labels.d.ts +1 -1
  2. package/dist/app/time-format-labels.d.ts +1 -1
  3. package/dist/components/data-display/badge.d.ts +1 -1
  4. package/dist/components/data-display/card.d.ts +4 -13
  5. package/dist/components/data-display/card.js +2 -15
  6. package/dist/components/data-display/data-table.d.ts +3 -8
  7. package/dist/components/data-display/data-table.js +106 -68
  8. package/dist/components/data-display/descriptions.js +34 -5
  9. package/dist/components/data-display/empty-state.js +1 -1
  10. package/dist/components/data-display/permission-matrix.js +7 -7
  11. package/dist/components/data-display/popover.js +2 -9
  12. package/dist/components/data-display/qr-code.d.ts +1 -1
  13. package/dist/components/data-display/scroll-area.d.ts +3 -1
  14. package/dist/components/data-display/scroll-area.js +150 -16
  15. package/dist/components/data-display/table.js +12 -3
  16. package/dist/components/data-entry/branch-scope-picker.js +4 -4
  17. package/dist/components/data-entry/calendar.js +15 -24
  18. package/dist/components/data-entry/cascader.js +67 -71
  19. package/dist/components/data-entry/checkbox.js +9 -1
  20. package/dist/components/data-entry/command.d.ts +6 -6
  21. package/dist/components/data-entry/date-picker.js +28 -15
  22. package/dist/components/data-entry/date-range-picker.js +10 -10
  23. package/dist/components/data-entry/form-field.js +7 -3
  24. package/dist/components/data-entry/index.d.ts +2 -1
  25. package/dist/components/data-entry/input.js +8 -19
  26. package/dist/components/data-entry/label.js +4 -2
  27. package/dist/components/data-entry/month-picker.js +16 -15
  28. package/dist/components/data-entry/month-range-picker.js +17 -16
  29. package/dist/components/data-entry/radio.js +6 -1
  30. package/dist/components/data-entry/search-select.js +29 -29
  31. package/dist/components/data-entry/select.js +15 -18
  32. package/dist/components/data-entry/switch.js +7 -1
  33. package/dist/components/data-entry/textarea.d.ts +56 -0
  34. package/dist/components/data-entry/textarea.js +103 -40
  35. package/dist/components/data-entry/time-picker.js +52 -52
  36. package/dist/components/data-entry/toggle-group.d.ts +1 -0
  37. package/dist/components/data-entry/toggle.d.ts +1 -1
  38. package/dist/components/data-entry/transfer.js +14 -15
  39. package/dist/components/data-entry/tree-select.js +16 -22
  40. package/dist/components/data-entry/upload-crop-dialog.js +4 -4
  41. package/dist/components/data-entry/upload.d.ts +1 -1
  42. package/dist/components/data-entry/upload.js +46 -46
  43. package/dist/components/feedback/alert.js +7 -14
  44. package/dist/components/feedback/dialog.d.ts +23 -32
  45. package/dist/components/feedback/dialog.js +16 -13
  46. package/dist/components/feedback/sheet.d.ts +1 -1
  47. package/dist/components/feedback/sheet.js +14 -14
  48. package/dist/components/feedback/skeleton.js +13 -10
  49. package/dist/components/feedback/sonner.d.ts +1 -1
  50. package/dist/components/feedback/sonner.js +17 -8
  51. package/dist/components/feedback/tooltip.js +1 -1
  52. package/dist/components/general/activity.d.ts +44 -0
  53. package/dist/components/general/activity.js +65 -0
  54. package/dist/components/general/button.d.ts +2 -2
  55. package/dist/components/general/button.js +11 -24
  56. package/dist/components/general/index.d.ts +2 -0
  57. package/dist/components/general/index.js +2 -0
  58. package/dist/components/layout/app-shell.js +5 -3
  59. package/dist/components/layout/auth-divider.d.ts +9 -2
  60. package/dist/components/layout/auth-divider.js +7 -11
  61. package/dist/components/layout/index.d.ts +1 -0
  62. package/dist/components/layout/page-container.d.ts +1 -1
  63. package/dist/components/layout/page-container.js +32 -20
  64. package/dist/components/layout/resizable.d.ts +12 -12
  65. package/dist/components/layout/separator.d.ts +1 -0
  66. package/dist/components/layout/service-role-panel.js +47 -42
  67. package/dist/components/layout/sidebar.js +13 -1
  68. package/dist/components/layout/split-pane.d.ts +12 -1
  69. package/dist/components/layout/split-pane.js +13 -4
  70. package/dist/components/navigation/app-setting-picker.js +5 -14
  71. package/dist/components/navigation/dropdown-menu.js +10 -16
  72. package/dist/components/navigation/menubar.d.ts +3 -6
  73. package/dist/components/navigation/pagination-utils.d.ts +15 -2
  74. package/dist/components/navigation/pagination-utils.js +27 -21
  75. package/dist/components/navigation/pagination.d.ts +4 -4
  76. package/dist/components/navigation/pagination.js +2 -2
  77. package/dist/components/navigation/steps.js +31 -67
  78. package/dist/components/navigation/tabs.js +17 -5
  79. package/dist/components/query/infinite-query-state.js +2 -2
  80. package/dist/components/ui/accordion.d.ts +1 -1
  81. package/dist/components/ui/avatar.d.ts +1 -1
  82. package/dist/components/ui/avatar.js +29 -10
  83. package/dist/components/ui/input-otp.d.ts +8 -6
  84. package/dist/components/ui/rating.js +1 -1
  85. package/dist/components/ui/separator.d.ts +27 -2
  86. package/dist/components/ui/separator.js +42 -11
  87. package/dist/components/ui/toggle-group.d.ts +15 -5
  88. package/dist/components/ui/toggle-group.js +43 -18
  89. package/dist/components/ui/toggle.d.ts +66 -5
  90. package/dist/components/ui/toggle.js +64 -9
  91. package/dist/i18n/messages/en.json +8 -0
  92. package/dist/i18n/messages/ja.json +8 -0
  93. package/dist/i18n/messages/vi.json +8 -0
  94. package/dist/lib/control-styles.d.ts +14 -0
  95. package/dist/lib/control-styles.js +2 -0
  96. package/dist/props/components/data-display.prop.d.ts +85 -3
  97. package/dist/props/components/data-entry.prop.d.ts +17 -0
  98. package/dist/props/components/general.prop.d.ts +52 -1
  99. package/dist/props/components/layout.prop.d.ts +137 -2
  100. package/dist/props/registry.d.ts +116 -5
  101. package/dist/props/registry.js +165 -4
  102. package/dist/props/vocabulary/index.d.ts +2 -2
  103. package/dist/props/vocabulary/interaction.prop.d.ts +15 -0
  104. package/dist/props/vocabulary/layout.prop.d.ts +8 -0
  105. package/dist/styles/alert-layout.css +69 -3
  106. package/dist/styles/badge-layout.css +2 -2
  107. package/dist/styles/base.css +6 -0
  108. package/dist/styles/card-layout.css +25 -8
  109. package/dist/styles/control.css +1150 -29
  110. package/dist/styles/data-display-layout.css +185 -11
  111. package/dist/styles/data-entry-layout.css +352 -1
  112. package/dist/styles/density.css +2 -2
  113. package/dist/styles/dialog-layout.css +203 -4
  114. package/dist/styles/focus-ring.css +155 -0
  115. package/dist/styles/form-layout.css +50 -5
  116. package/dist/styles/index.css +1 -0
  117. package/dist/styles/layout.css +412 -23
  118. package/dist/styles/motion.css +178 -0
  119. package/dist/styles/navigation-layout.css +398 -22
  120. package/dist/styles/shell-layout.css +137 -39
  121. package/dist/styles/table-layout.css +153 -22
  122. package/dist/styles/toggle.css +59 -0
  123. package/dist/tokens/base.css +5 -0
  124. package/dist/tokens/components/activity.css +64 -0
  125. package/dist/tokens/components/badge.css +7 -0
  126. package/dist/tokens/components/card.css +14 -10
  127. package/dist/tokens/components/chart.css +1 -1
  128. package/dist/tokens/components/control.css +358 -8
  129. package/dist/tokens/components/data-display.css +75 -0
  130. package/dist/tokens/components/data-entry.css +25 -0
  131. package/dist/tokens/components/descriptions.css +22 -0
  132. package/dist/tokens/components/feedback.css +143 -4
  133. package/dist/tokens/components/form.css +16 -0
  134. package/dist/tokens/components/legal-document.css +5 -1
  135. package/dist/tokens/components/navigation.css +109 -0
  136. package/dist/tokens/components/scroll-area.css +21 -0
  137. package/dist/tokens/components/separator.css +52 -0
  138. package/dist/tokens/components/shell.css +132 -20
  139. package/dist/tokens/components/table.css +52 -3
  140. package/dist/tokens/components/toggle.css +82 -0
  141. package/dist/tokens/components/upload.css +107 -0
  142. package/dist/tokens/foundation.css +171 -10
  143. package/dist/tokens/semantic/layout.css +120 -1
  144. package/package.json +84 -68
  145. package/scripts/ui-audit.mjs +51 -2
@@ -56,7 +56,7 @@ const SheetOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PU
56
56
  className: cn(
57
57
  // Scrim colour comes from the shared --overlay-background token (see dialog-layout.css),
58
58
  // so a service tints every overlay's backdrop from one knob instead of a baked bg-black/50.
59
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 fixed inset-0 z-50",
59
+ "ui-sheet-overlay data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 fixed",
60
60
  className
61
61
  ),
62
62
  ...props
@@ -64,7 +64,7 @@ const SheetOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PU
64
64
  ));
65
65
  SheetOverlay.displayName = DialogPrimitive.Overlay.displayName;
66
66
  const sheetVariants = cva(
67
- "fixed z-50 flex flex-col gap-[var(--space-chrome-gap)] bg-background px-[var(--sheet-pad-x)] py-[var(--sheet-pad-y)] shadow-lg transition ease-in-out data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:animate-in data-[state=open]:duration-500",
67
+ "ui-sheet-panel fixed flex flex-col gap-[var(--space-chrome-gap)] bg-background px-[var(--sheet-pad-x)] py-[var(--sheet-pad-y)] transition ease-in-out data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:animate-in data-[state=open]:duration-500",
68
68
  {
69
69
  variants: {
70
70
  // `side` is a deliberately PHYSICAL API (left/right/top/bottom) — a sheet
@@ -75,8 +75,8 @@ const sheetVariants = cva(
75
75
  right: "inset-y-0 right-0 h-full w-[min(var(--sheet-width-default),100%)] max-w-none border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right",
76
76
  /* rtl-ignore: named physical side */
77
77
  left: "inset-y-0 left-0 h-full w-[min(var(--sheet-width-default),100%)] max-w-none border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left",
78
- top: "inset-x-0 top-0 h-auto border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
79
- bottom: "inset-x-0 bottom-0 h-auto border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom"
78
+ top: "inset-x-0 h-auto data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
79
+ bottom: "inset-x-0 h-auto data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom"
80
80
  }
81
81
  },
82
82
  defaultVariants: { side: "right" }
@@ -127,9 +127,9 @@ const SheetContent = React.forwardRef(
127
127
  DialogPrimitive.Close,
128
128
  {
129
129
  "data-slot": "sheet-close",
130
- className: "ring-offset-background focus:ring-ring absolute end-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none",
130
+ className: "ui-sheet-close ring-offset-background focus:ring-ring focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none",
131
131
  children: [
132
- /* @__PURE__ */ jsx(X, { className: "size-4", "aria-hidden": "true" }),
132
+ /* @__PURE__ */ jsx(X, { className: "ui-sheet-close-icon", "aria-hidden": "true" }),
133
133
  /* @__PURE__ */ jsx("span", { className: "sr-only", children: t("feedback.alert.dismiss") })
134
134
  ]
135
135
  }
@@ -156,18 +156,18 @@ const SheetHeader = ({
156
156
  "data-slot": "sheet-header",
157
157
  "data-tone": tone,
158
158
  className: cn(
159
- "-mx-[var(--sheet-pad-x)] -mt-[var(--sheet-pad-y)] flex flex-col gap-1.5 px-[var(--sheet-pad-x)] py-[var(--sheet-pad-y)]",
159
+ "ui-sheet-header -mx-[var(--sheet-pad-x)] -mt-[var(--sheet-pad-y)] px-[var(--sheet-pad-x)] py-[var(--sheet-pad-y)]",
160
160
  overlayHeaderToneClass[tone],
161
161
  className
162
162
  ),
163
163
  ...props,
164
164
  children: children ?? // `pe-8` reserves room for the absolute close button (end-4) so title/extra never sit under it.
165
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3 pe-8", children: [
166
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
165
+ /* @__PURE__ */ jsxs("div", { className: "ui-sheet-title-row", children: [
166
+ /* @__PURE__ */ jsxs("div", { className: "ui-sheet-title-block", children: [
167
167
  title != null && /* @__PURE__ */ jsx(SheetTitle, { children: title }),
168
168
  subtitle != null && /* @__PURE__ */ jsx(SheetDescription, { children: subtitle })
169
169
  ] }),
170
- extra != null && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-2 whitespace-nowrap", children: extra })
170
+ extra != null && /* @__PURE__ */ jsx("div", { className: "ui-sheet-extra", children: extra })
171
171
  ] })
172
172
  }
173
173
  );
@@ -183,7 +183,7 @@ const SheetBody = ({ className, ...props }) => (
183
183
  {
184
184
  "data-slot": "sheet-body",
185
185
  className: cn(
186
- "-mx-[var(--sheet-pad-x)] min-h-0 flex-1 scroll-py-1 overflow-y-auto px-[var(--sheet-pad-x)] py-1",
186
+ "ui-sheet-body-space -mx-[var(--sheet-pad-x)] flex-1 overflow-y-auto px-[var(--sheet-pad-x)]",
187
187
  className
188
188
  ),
189
189
  ...props
@@ -201,7 +201,7 @@ const SheetFooter = ({ className, ...props }) => (
201
201
  {
202
202
  "data-slot": "sheet-footer",
203
203
  className: cn(
204
- "-mx-[var(--sheet-pad-x)] mt-auto -mb-[var(--sheet-pad-y)] flex flex-wrap items-center justify-end gap-2 px-[var(--sheet-pad-x)] py-[var(--sheet-pad-y)]",
204
+ "ui-sheet-footer-row -mx-[var(--sheet-pad-x)] mt-auto -mb-[var(--sheet-pad-y)] px-[var(--sheet-pad-x)] py-[var(--sheet-pad-y)]",
205
205
  className
206
206
  ),
207
207
  ...props
@@ -213,7 +213,7 @@ const SheetTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE
213
213
  {
214
214
  ref,
215
215
  "data-slot": "sheet-title",
216
- className: cn("text-foreground text-lg font-medium", className),
216
+ className: cn("ui-sheet-title", className),
217
217
  ...props
218
218
  }
219
219
  ));
@@ -223,7 +223,7 @@ const SheetDescription = React.forwardRef(({ className, ...props }, ref) => /* @
223
223
  {
224
224
  ref,
225
225
  "data-slot": "sheet-description",
226
- className: cn("text-foreground/80 text-sm", className),
226
+ className: cn("ui-sheet-description", className),
227
227
  ...props
228
228
  }
229
229
  ));
@@ -16,19 +16,22 @@ function SkeletonRows({ rows = 6, columns = 4, className }) {
16
16
  return /* @__PURE__ */ jsx("div", { className: cn("ui-skeleton-rows", className), "aria-busy": "true", children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsx("div", { className: "ui-skeleton-row", children: Array.from({ length: columns }).map((_2, j) => /* @__PURE__ */ jsx(
17
17
  Skeleton,
18
18
  {
19
- className: cn("h-4", j === 0 ? "w-1/4" : j === columns - 1 ? "w-1/6" : "flex-1")
19
+ className: cn(
20
+ "ui-skeleton-line",
21
+ j === 0 ? "w-1/4" : j === columns - 1 ? "w-1/6" : "flex-1"
22
+ )
20
23
  },
21
24
  j
22
25
  )) }, i)) });
23
26
  }
24
27
  function SkeletonTable({ rows = 8, columns = 5 }) {
25
28
  return /* @__PURE__ */ jsxs("div", { className: "ui-skeleton-table", "aria-busy": "true", children: [
26
- /* @__PURE__ */ jsx("div", { className: cn("ui-skeleton-table-head", tableCellPaddingClass, tableRowHeightClass), children: Array.from({ length: columns }).map((_, j) => /* @__PURE__ */ jsx(Skeleton, { className: cn("h-3", j === 0 ? "w-1/5" : "flex-1") }, j)) }),
29
+ /* @__PURE__ */ jsx("div", { className: cn("ui-skeleton-table-head", tableCellPaddingClass, tableRowHeightClass), children: Array.from({ length: columns }).map((_, j) => /* @__PURE__ */ jsx(Skeleton, { className: cn("ui-skeleton-caption", j === 0 ? "w-1/5" : "flex-1") }, j)) }),
27
30
  /* @__PURE__ */ jsx("div", { className: "ui-skeleton-table-body", children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsx(
28
31
  "div",
29
32
  {
30
33
  className: cn("ui-skeleton-table-row", tableCellPaddingClass, tableRowHeightClass),
31
- children: Array.from({ length: columns }).map((_2, j) => /* @__PURE__ */ jsx(Skeleton, { className: cn("h-4", j === 0 ? "w-1/5" : "flex-1") }, j))
34
+ children: Array.from({ length: columns }).map((_2, j) => /* @__PURE__ */ jsx(Skeleton, { className: cn("ui-skeleton-line", j === 0 ? "w-1/5" : "flex-1") }, j))
32
35
  },
33
36
  i
34
37
  )) })
@@ -36,19 +39,19 @@ function SkeletonTable({ rows = 8, columns = 5 }) {
36
39
  }
37
40
  function SkeletonDetail() {
38
41
  return /* @__PURE__ */ jsxs("div", { className: "ui-skeleton-detail ui-skeleton-detail-stack", "aria-busy": "true", children: [
39
- /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-1/3" }),
40
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-1/2" }),
42
+ /* @__PURE__ */ jsx(Skeleton, { className: "ui-skeleton-title w-1/3" }),
43
+ /* @__PURE__ */ jsx(Skeleton, { className: "ui-skeleton-line w-1/2" }),
41
44
  /* @__PURE__ */ jsx("div", { className: "ui-skeleton-detail-box ui-skeleton-detail-stack", children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "ui-skeleton-detail-stack", children: [
42
- /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" }),
43
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full max-w-md" })
45
+ /* @__PURE__ */ jsx(Skeleton, { className: "ui-skeleton-detail-label" }),
46
+ /* @__PURE__ */ jsx(Skeleton, { className: "ui-skeleton-detail-value" })
44
47
  ] }, i)) })
45
48
  ] });
46
49
  }
47
50
  function SkeletonStat() {
48
51
  return /* @__PURE__ */ jsxs("div", { className: "ui-skeleton-stat", "aria-busy": "true", children: [
49
- /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" }),
50
- /* @__PURE__ */ jsx(Skeleton, { className: "h-[length:var(--control-height)] w-32" }),
51
- /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-20" })
52
+ /* @__PURE__ */ jsx(Skeleton, { className: "ui-skeleton-detail-label" }),
53
+ /* @__PURE__ */ jsx(Skeleton, { className: "ui-skeleton-stat-value" }),
54
+ /* @__PURE__ */ jsx(Skeleton, { className: "ui-skeleton-stat-caption" })
52
55
  ] });
53
56
  }
54
57
  export {
@@ -1,4 +1,4 @@
1
1
  import * as React from "react";
2
2
  import { type ToasterProps } from "sonner";
3
- declare function Toaster({ ...props }: ToasterProps): React.JSX.Element;
3
+ declare function Toaster({ style, ...props }: ToasterProps): React.JSX.Element;
4
4
  export { Toaster };
@@ -20,7 +20,7 @@ function useDocumentTheme() {
20
20
  () => "light"
21
21
  );
22
22
  }
23
- function Toaster({ ...props }) {
23
+ function Toaster({ style, ...props }) {
24
24
  const theme = useDocumentTheme();
25
25
  return /* @__PURE__ */ jsx(
26
26
  Sonner,
@@ -28,11 +28,11 @@ function Toaster({ ...props }) {
28
28
  theme,
29
29
  className: "toaster group",
30
30
  icons: {
31
- success: /* @__PURE__ */ jsx(CheckCircle2, { className: "size-4", "aria-hidden": "true" }),
32
- info: /* @__PURE__ */ jsx(Info, { className: "size-4", "aria-hidden": "true" }),
33
- warning: /* @__PURE__ */ jsx(TriangleAlert, { className: "size-4", "aria-hidden": "true" }),
34
- error: /* @__PURE__ */ jsx(OctagonX, { className: "size-4", "aria-hidden": "true" }),
35
- loading: /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": "true" })
31
+ success: /* @__PURE__ */ jsx(CheckCircle2, { className: "ui-toast-icon", "aria-hidden": "true" }),
32
+ info: /* @__PURE__ */ jsx(Info, { className: "ui-toast-icon", "aria-hidden": "true" }),
33
+ warning: /* @__PURE__ */ jsx(TriangleAlert, { className: "ui-toast-icon", "aria-hidden": "true" }),
34
+ error: /* @__PURE__ */ jsx(OctagonX, { className: "ui-toast-icon", "aria-hidden": "true" }),
35
+ loading: /* @__PURE__ */ jsx(Loader2, { className: "ui-toast-icon animate-spin", "aria-hidden": "true" })
36
36
  },
37
37
  style: {
38
38
  // Color tokens are raw HSL triplets (consumed as hsl(var(--token)));
@@ -42,10 +42,19 @@ function Toaster({ ...props }) {
42
42
  "--normal-bg": "hsl(var(--popover))",
43
43
  "--normal-text": "hsl(var(--popover-foreground))",
44
44
  "--normal-border": "hsl(var(--border))",
45
- "--border-radius": "var(--radius)"
45
+ "--border-radius": "var(--radius)",
46
+ // MERGED, never spread over. `style` used to arrive with the rest of `{...props}` AFTER
47
+ // this object, so a consumer passing ANY style (a z-index, a width) replaced the whole
48
+ // object and wiped all four vars — and an unset `--normal-bg` renders the toast
49
+ // transparent. Merging keeps the surface intact and still lets a consumer override one
50
+ // var by name.
51
+ ...style
46
52
  },
47
53
  position: "bottom-right",
48
- mobileOffset: { bottom: "16px", right: "16px" },
54
+ mobileOffset: {
55
+ bottom: "var(--toast-mobile-offset)",
56
+ right: "var(--toast-mobile-offset)"
57
+ },
49
58
  ...props
50
59
  }
51
60
  );
@@ -23,7 +23,7 @@ const TooltipContent = React.forwardRef(({ className, sideOffset = 6, children,
23
23
  "data-slot": "tooltip-content",
24
24
  sideOffset,
25
25
  className: cn(
26
- "bg-popover text-popover-foreground z-50 w-fit max-w-xs rounded-md border px-2 py-1 text-xs shadow-md outline-none",
26
+ "ui-tooltip-content",
27
27
  "data-[state=delayed-open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=delayed-open]:fade-in-0",
28
28
  "data-[side=bottom]:slide-in-from-top-1 data-[side=top]:slide-in-from-bottom-1",
29
29
  "data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1",
@@ -0,0 +1,44 @@
1
+ import * as React from "react";
2
+ import type { SizeProp } from "../../props/vocabulary/index.js";
3
+ export type { ActivityProp, ActivityProp as ActivityProps, } from "../../props/components/general.prop.js";
4
+ /**
5
+ * Activity — the official AMBIENT-motion primitive: a continuous, unbounded "something is happening
6
+ * right now, elsewhere". The LOOP counterpart to `Reveal`'s one-shot entrance, so a consumer never
7
+ * hand-rolls a looping `@keyframes` + its own `prefers-reduced-motion` guard. Every interval,
8
+ * stagger, offset, size and colour reads a DS token (`--activity-interval`,
9
+ * `--activity-stagger-step`, `--activity-mark-offset`, `--activity-color`, …), so a service retunes
10
+ * the whole ambient feel from its theme.
11
+ *
12
+ * NOT `Skeleton` (content is LOADING — it hard-codes `aria-busy` + an unconditional live region, so
13
+ * reusing it for a typing indicator tells every screen reader the region is busy for as long as
14
+ * anyone is typing). NOT `Button loading` (THIS ACTION is in flight, on a control).
15
+ * `Activity` means: someone is typing, a sync is running, a response is streaming, a recording is
16
+ * live — indefinitely, and not here.
17
+ *
18
+ * ACCESSIBILITY — the half consumers get wrong, owned here:
19
+ * - The mark is decorative and always `aria-hidden`; the `label` (or `children`) carries the
20
+ * meaning, so the indicator is never animation-only.
21
+ * - `announce` defaults to `false` and then emits NO live region at all. An ambient indicator
22
+ * flickers on and off with every socket event; a live region there re-announces continuously.
23
+ * `announce="polite"` wraps ONLY the label in one `aria-live="polite" aria-atomic="true"` region.
24
+ * - No `aria-busy`: activity elsewhere does not make THIS region busy, and `aria-busy` would
25
+ * suppress the surrounding content's own updates.
26
+ * - Not focusable, not a tab stop, no pointer affordance — it is a status mark, not a control.
27
+ * - Under `prefers-reduced-motion: reduce` the loop is dropped and every mark falls back to a
28
+ * DESIGNED resting state (three solid dots / a solid pulse mark / a bar segment parked at the
29
+ * reading-start), never to nothing, with no layout shift (WCAG 2.2 SC 2.3.3 and SC 2.2.2).
30
+ *
31
+ * Copy is consumer-owned and localized — pass a `t()`-translated `label`, and derive
32
+ * "N people are typing" from `Intl.PluralRules`. The library never invents the string.
33
+ *
34
+ * Pure/server-safe: no hooks, no effects, no timers — the loop is CSS.
35
+ */
36
+ export declare const Activity: React.ForwardRefExoticComponent<Omit<React.HTMLAttributes<HTMLSpanElement>, "color"> & {
37
+ variant?: import("../../props/index.js").ActivityVariantProp;
38
+ size?: SizeProp;
39
+ tone?: import("../../props/index.js").TextToneProp;
40
+ label?: import("../../props/index.js").LabelProp;
41
+ children?: import("../../props/index.js").ChildrenProp;
42
+ announce?: import("../../props/index.js").ActivityAnnounceProp;
43
+ className?: import("../../props/index.js").ClassNameProp;
44
+ } & React.RefAttributes<HTMLSpanElement>>;
@@ -0,0 +1,65 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cn } from "../../lib/utils.js";
4
+ import { Text } from "./typography.js";
5
+ const LABEL_SIZE = {
6
+ xs: "2xs",
7
+ sm: "xs",
8
+ md: "sm",
9
+ lg: "lg"
10
+ };
11
+ function ActivityMark({ variant }) {
12
+ if (variant === "pulse") return /* @__PURE__ */ jsx("span", { className: "ui-activity-pulse" });
13
+ if (variant === "bar") {
14
+ return /* @__PURE__ */ jsx("span", { className: "ui-activity-bar", children: /* @__PURE__ */ jsx("span", { className: "ui-activity-bar-segment" }) });
15
+ }
16
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
17
+ /* @__PURE__ */ jsx("span", { className: "ui-activity-dot" }),
18
+ /* @__PURE__ */ jsx("span", { className: "ui-activity-dot" }),
19
+ /* @__PURE__ */ jsx("span", { className: "ui-activity-dot" })
20
+ ] });
21
+ }
22
+ const Activity = React.forwardRef(function Activity2({
23
+ variant = "dots",
24
+ size = "sm",
25
+ tone = "muted",
26
+ label,
27
+ announce = false,
28
+ children,
29
+ className,
30
+ ...props
31
+ }, ref) {
32
+ const hasChildren = children !== void 0 && children !== null && children !== false;
33
+ const visible = hasChildren ? children : label;
34
+ const describedOnly = hasChildren && label !== void 0 && label !== null ? label : void 0;
35
+ const text = visible === void 0 || visible === null ? null : /* @__PURE__ */ jsx(Text, { as: "span", size: LABEL_SIZE[size], tone, className: "ui-activity-label", children: visible });
36
+ const description = describedOnly === void 0 ? null : /* @__PURE__ */ jsx("span", { "data-slot": "activity-description", className: "sr-only", children: describedOnly });
37
+ const body = /* @__PURE__ */ jsxs(Fragment, { children: [
38
+ text,
39
+ description
40
+ ] });
41
+ return /* @__PURE__ */ jsxs(
42
+ "span",
43
+ {
44
+ ref,
45
+ "data-slot": "activity",
46
+ "data-variant": variant,
47
+ "data-size": size,
48
+ "data-tone": tone,
49
+ className: cn("ui-activity", className),
50
+ ...props,
51
+ children: [
52
+ /* @__PURE__ */ jsx("span", { className: "ui-activity-mark", "data-slot": "activity-mark", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ActivityMark, { variant }) }),
53
+ announce === "polite" ? (
54
+ // The region wraps ONLY the label and is atomic, so a change is announced once as a whole.
55
+ // It is rendered even while empty so a label that arrives later is heard — an inserted
56
+ // region is not reliably announced. The mark stays outside it.
57
+ /* @__PURE__ */ jsx("span", { "aria-live": "polite", "aria-atomic": "true", "data-slot": "activity-live", children: body })
58
+ ) : body
59
+ ]
60
+ }
61
+ );
62
+ });
63
+ export {
64
+ Activity
65
+ };
@@ -1,7 +1,7 @@
1
1
  import * as React from "react";
2
2
  declare const buttonVariants: (props?: ({
3
- variant?: "default" | "ghost" | "destructive" | "outline" | "dashed" | "secondary" | "link" | null | undefined;
4
- size?: "default" | "sm" | "md" | "lg" | "xs" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
3
+ variant?: "dashed" | "default" | "destructive" | "ghost" | "link" | "outline" | "secondary" | null | undefined;
4
+ size?: "default" | "icon" | "icon-lg" | "icon-sm" | "icon-xs" | "lg" | "md" | "sm" | "xs" | null | undefined;
5
5
  shape?: "default" | "pill" | "sharp" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  export type { ButtonProp, ButtonProp as ButtonProps } from "../../props/components/general.prop.js";
@@ -6,20 +6,11 @@ import { cva } from "class-variance-authority";
6
6
  import { Loader2 } from "lucide-react";
7
7
  import { cn } from "../../lib/utils.js";
8
8
  import { useTranslation } from "../../i18n/use-translation.js";
9
- const buttonCountClass = {
10
- default: "bg-primary-foreground/15",
11
- destructive: "bg-destructive-foreground/15",
12
- secondary: "bg-secondary-foreground/15",
13
- outline: "bg-foreground/8 text-muted-foreground",
14
- dashed: "bg-foreground/8 text-muted-foreground",
15
- ghost: "bg-foreground/8 text-muted-foreground",
16
- link: "bg-foreground/8 text-muted-foreground"
17
- };
18
9
  const buttonVariants = cva("ui-button", {
19
10
  variants: {
20
11
  variant: {
21
12
  default: "ui-button--default bg-primary text-primary-foreground hover:bg-primary/90",
22
- destructive: "ui-button--destructive bg-destructive text-destructive-foreground focus-visible:ring-destructive/20",
13
+ destructive: "ui-button--destructive bg-destructive text-destructive-foreground",
23
14
  outline: "ui-button--outline border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
24
15
  dashed: "ui-button--dashed border border-dashed bg-background hover:bg-accent hover:text-accent-foreground",
25
16
  secondary: "ui-button--secondary bg-secondary text-secondary-foreground hover:bg-secondary/80",
@@ -27,13 +18,16 @@ const buttonVariants = cva("ui-button", {
27
18
  link: "ui-button--link text-primary underline-offset-4 hover:underline"
28
19
  },
29
20
  size: {
30
- default: "ui-button--default-size py-2 has-[>svg]:px-3",
31
- md: "ui-button--default-size py-2 has-[>svg]:px-3",
32
- xs: "h-[calc(var(--control-height)-0.75rem)] gap-1 px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
33
- sm: "ui-button--sm gap-1.5 has-[>svg]:px-2.5",
34
- lg: "ui-button--lg has-[>svg]:px-4",
21
+ default: "ui-button--default-size",
22
+ md: "ui-button--default-size",
23
+ // The glyph rules stay UTILITIES, not a components-layer rule: Tailwind v4 orders
24
+ // utilities after components, so only a utility can out-rank a child's own `size-*`.
25
+ // They read the token, so the value is still themeable.
26
+ xs: "ui-button--xs [&_svg:not([class*='size-'])]:size-[var(--button-xs-icon-size)]",
27
+ sm: "ui-button--sm",
28
+ lg: "ui-button--lg",
35
29
  icon: "ui-button--icon",
36
- "icon-xs": "ui-button--icon-xs [&_svg]:size-3 [&_svg]:shrink-0",
30
+ "icon-xs": "ui-button--icon-xs [&_svg]:size-[var(--button-xs-icon-size)] [&_svg]:shrink-0",
37
31
  "icon-sm": "ui-button--icon-sm",
38
32
  "icon-lg": "ui-button--icon-lg"
39
33
  },
@@ -79,10 +73,7 @@ const Button = React.forwardRef(
79
73
  "span",
80
74
  {
81
75
  "data-slot": "button-count",
82
- className: cn(
83
- "inline-flex min-w-4 items-center justify-center rounded-[var(--radius-pill)] px-1 text-xs leading-none tabular-nums",
84
- buttonCountClass[variant ?? "default"]
85
- ),
76
+ className: "ui-button-count",
86
77
  children: countLabel
87
78
  }
88
79
  ) : null;
@@ -99,11 +90,7 @@ const Button = React.forwardRef(
99
90
  disabled: isLoading || disabled,
100
91
  type: asChild ? void 0 : type ?? "button",
101
92
  className: cn(
102
- "inline-flex shrink-0 items-center justify-center gap-2 text-sm font-medium whitespace-nowrap transition-all outline-none",
103
93
  fullWidth && "w-full",
104
- "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
105
- "disabled:pointer-events-none disabled:opacity-50",
106
- "data-[loading]:pointer-events-none",
107
94
  "aria-invalid:border-destructive aria-invalid:ring-destructive/20",
108
95
  "[&_svg]:pointer-events-none [&_svg]:shrink-0",
109
96
  buttonVariants({ variant, size, shape, className })
@@ -6,3 +6,5 @@ export { Logo } from "./logo.js";
6
6
  export type { LogoMark, LogoProps, LogoSize, LogoTone } from "./logo.js";
7
7
  export { Reveal } from "./reveal.js";
8
8
  export type { RevealProp, RevealProps } from "./reveal.js";
9
+ export { Activity } from "./activity.js";
10
+ export type { ActivityProp, ActivityProps } from "./activity.js";
@@ -2,7 +2,9 @@ import { Button, buttonVariants } from "./button.js";
2
2
  import { Text, Heading } from "./typography.js";
3
3
  import { Logo } from "./logo.js";
4
4
  import { Reveal } from "./reveal.js";
5
+ import { Activity } from "./activity.js";
5
6
  export {
7
+ Activity,
6
8
  Button,
7
9
  Heading,
8
10
  Logo,
@@ -35,6 +35,7 @@ function AppShell({
35
35
  setDrawerOpen(false);
36
36
  }
37
37
  };
38
+ const hasTopbarContent = topbar !== void 0 || topbarLeft !== void 0 || topbarRight !== void 0 || logo !== void 0;
38
39
  const resolvedTopbar = topbar !== void 0 ? topbar : /* @__PURE__ */ jsxs("div", { className: "app-topbar-rail", children: [
39
40
  logo !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-logo", children: logo }),
40
41
  topbarLeft !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-left", children: topbarLeft }),
@@ -42,7 +43,7 @@ function AppShell({
42
43
  topbarRight !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-right", children: topbarRight })
43
44
  ] });
44
45
  const rail = /* @__PURE__ */ jsx("aside", { className: "app-sidebar", "aria-label": t("layout.appShell.sidebarLabel"), children: sidebar });
45
- const bar = /* @__PURE__ */ jsxs("header", { className: "app-topbar ui-scale-fixed", "aria-label": t("layout.appShell.headerLabel"), children: [
46
+ const bar = !hasTopbarContent && !hasDrawer ? null : /* @__PURE__ */ jsxs("header", { className: "app-topbar ui-scale-fixed", "aria-label": t("layout.appShell.headerLabel"), children: [
46
47
  hasDrawer && /* @__PURE__ */ jsxs(Sheet, { open: drawerOpen, onOpenChange: setDrawerOpen, children: [
47
48
  /* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
48
49
  Button,
@@ -53,7 +54,7 @@ function AppShell({
53
54
  className: "app-mobile-nav-trigger hidden max-[900px]:inline-flex",
54
55
  "aria-label": t("layout.appShell.openNav"),
55
56
  "aria-haspopup": "dialog",
56
- children: /* @__PURE__ */ jsx(Menu, { className: "size-5", "aria-hidden": "true" })
57
+ children: /* @__PURE__ */ jsx(Menu, { className: "size-[var(--app-shell-mobile-nav-icon-size)]", "aria-hidden": "true" })
57
58
  }
58
59
  ) }),
59
60
  /* @__PURE__ */ jsxs(
@@ -77,7 +78,7 @@ function AppShell({
77
78
  }
78
79
  )
79
80
  ] }),
80
- resolvedTopbar
81
+ hasTopbarContent && resolvedTopbar
81
82
  ] });
82
83
  return /* @__PURE__ */ jsxs(
83
84
  "div",
@@ -85,6 +86,7 @@ function AppShell({
85
86
  className: "app-root",
86
87
  "data-collapsed": sidebarCollapsed ? "true" : void 0,
87
88
  "data-responsive-navigation": responsiveNavigation,
89
+ "data-topbar": hasTopbarContent ? void 0 : "none",
88
90
  "data-topbar-span": topbarSpan === "full" ? "full" : void 0,
89
91
  children: [
90
92
  topbarSpan === "full" ? bar : rail,
@@ -1,7 +1,14 @@
1
1
  import type { AuthDividerProp } from "../../props/components/layout.prop.js";
2
2
  export type { AuthDividerProp, AuthDividerProp as AuthDividerProps, } from "../../props/components/layout.prop.js";
3
3
  /**
4
- * AuthDivider — a centred, localized conjunction between two equal separator rules. The grid
5
- * composition keeps the label optically and geometrically centred regardless of translation.
4
+ * AuthDivider — a centred, localized conjunction between two equal separator rules.
5
+ *
6
+ * Since gh#308 this is a thin PRESET over `Separator label`, not a parallel implementation: the
7
+ * grid, the accessible-name contract and the rule geometry all live on the primitive, and
8
+ * `.ui-auth-divider` only re-points Separator's `--separator-*` knobs at the `--auth-shell-divider-*`
9
+ * layer. That keeps #263's canonical login geometry byte-for-byte identical while breaking the
10
+ * coupling the issue reported — a service retuning its login divider no longer retunes every day
11
+ * divider in its message streams, and vice versa. New code that wants a labelled rule outside an
12
+ * auth form should use `<Separator label>` directly.
6
13
  */
7
14
  export declare function AuthDivider({ label, className }: AuthDividerProp): import("react").JSX.Element;
@@ -1,18 +1,14 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
2
3
  import { cn } from "../../lib/utils.js";
4
+ import { Separator } from "../ui/separator.js";
3
5
  function AuthDivider({ label, className }) {
4
- return /* @__PURE__ */ jsxs(
5
- "div",
6
+ return /* @__PURE__ */ jsx(
7
+ Separator,
6
8
  {
7
9
  "data-slot": "auth-divider",
8
- className: cn("ui-auth-divider", className),
9
- role: "separator",
10
- "aria-label": label,
11
- children: [
12
- /* @__PURE__ */ jsx("span", { className: "ui-auth-divider-rule", "aria-hidden": "true" }),
13
- /* @__PURE__ */ jsx("span", { className: "ui-auth-divider-label", "aria-hidden": "true", children: label }),
14
- /* @__PURE__ */ jsx("span", { className: "ui-auth-divider-rule", "aria-hidden": "true" })
15
- ]
10
+ label,
11
+ className: cn("ui-auth-divider", className)
16
12
  }
17
13
  );
18
14
  }
@@ -39,6 +39,7 @@ export type { MasterDetailProps } from "./master-detail.js";
39
39
  export { SplitPane } from "./split-pane.js";
40
40
  export type { SplitPaneProps } from "./split-pane.js";
41
41
  export { Separator } from "./separator.js";
42
+ export type { SeparatorProp, SeparatorProps } from "./separator.js";
42
43
  export { AspectRatio } from "./aspect-ratio.js";
43
44
  export { LegalDocumentShell } from "./legal-document-shell.js";
44
45
  export type { LegalDocumentSectionProp, LegalDocumentShellProp, LegalDocumentShellProps, } from "./legal-document-shell.js";
@@ -2,7 +2,7 @@ import type { PageContainerProp, PageInsetProp } from "../../props/components/la
2
2
  export type { PageContainerProp, PageContainerProp as PageContainerProps, } from "../../props/components/layout.prop.js";
3
3
  export type { BreadcrumbItemProp, BreadcrumbItemProp as BreadcrumbItem, } from "../../props/vocabulary/navigation.prop.js";
4
4
  export declare function PageContainerInset({ className, children, ...props }: PageInsetProp): import("react").JSX.Element;
5
- declare function PageContainerRoot({ title, subtitle, status, extra, footer, breadcrumb, breadcrumbLabel, breadcrumbAriaLabel, linkComponent: LinkComponent, headerLoading, density, variant, preset, headerLayout, measure, stickyFooter, footerReveal, fill, children, className, }: PageContainerProp): import("react").JSX.Element;
5
+ declare function PageContainerRoot({ title, subtitle, status, extra, toolbar, footer, breadcrumb, breadcrumbLabel, breadcrumbAriaLabel, linkComponent: LinkComponent, headerLoading, density, variant, preset, headerLayout, headerScale, measure, stickyFooter, footerReveal, fill, children, className, }: PageContainerProp): import("react").JSX.Element;
6
6
  export declare const PageContainer: typeof PageContainerRoot & {
7
7
  Inset: typeof PageContainerInset;
8
8
  };
@@ -38,6 +38,7 @@ function PageContainerRoot({
38
38
  subtitle,
39
39
  status,
40
40
  extra,
41
+ toolbar,
41
42
  footer,
42
43
  breadcrumb,
43
44
  breadcrumbLabel,
@@ -48,6 +49,7 @@ function PageContainerRoot({
48
49
  variant = "default",
49
50
  preset = "default",
50
51
  headerLayout = "stack",
52
+ headerScale = "document",
51
53
  measure = "default",
52
54
  stickyFooter = false,
53
55
  footerReveal = "always",
@@ -63,6 +65,7 @@ function PageContainerRoot({
63
65
  {
64
66
  "data-preset": preset,
65
67
  "data-measure": measure,
68
+ "data-header-scale": headerScale === "chrome" ? "chrome" : void 0,
66
69
  "data-revealed": revealed ? "true" : void 0,
67
70
  className: cn(
68
71
  "ui-page-container",
@@ -91,30 +94,38 @@ function PageContainerRoot({
91
94
  className: "ui-breadcrumb",
92
95
  children: /* @__PURE__ */ jsx("ol", { className: "ui-breadcrumb-list", children: breadcrumb.map((item, i) => {
93
96
  const isLast = i === breadcrumb.length - 1;
94
- return /* @__PURE__ */ jsxs("li", { className: "ui-inline-xs", children: [
95
- item.to && !isLast ? /* @__PURE__ */ jsx(
96
- LinkComponent,
97
- {
98
- href: item.to,
99
- to: item.to,
100
- className: "hover:text-foreground hover:underline",
101
- children: item.label
102
- }
103
- ) : /* @__PURE__ */ jsx(
104
- "span",
105
- {
106
- className: isLast ? "text-foreground" : "",
107
- "aria-current": isLast ? "page" : void 0,
108
- children: item.label
109
- }
110
- ),
111
- !isLast && /* @__PURE__ */ jsx(ChevronRight, { className: "size-3", "aria-hidden": "true" })
112
- ] }, i);
97
+ return (
98
+ // The package's own breadcrumb item hook (gh#319): same
99
+ // `--space-inline-xs` gap the previous `.ui-inline-xs` gave, and it brings
100
+ // `.ui-breadcrumb-item svg { 0.75rem }` with it, so the separator glyph no
101
+ // longer carries a `size-3` literal. It also drops `.ui-inline-xs`'s
102
+ // `flex-wrap: wrap` — a crumb must not break between its label and its
103
+ // chevron; the LIST wraps instead, exactly as <Breadcrumb> already behaves.
104
+ /* @__PURE__ */ jsxs("li", { className: "ui-breadcrumb-item", children: [
105
+ item.to && !isLast ? /* @__PURE__ */ jsx(
106
+ LinkComponent,
107
+ {
108
+ href: item.to,
109
+ to: item.to,
110
+ className: "hover:text-foreground hover:underline",
111
+ children: item.label
112
+ }
113
+ ) : /* @__PURE__ */ jsx(
114
+ "span",
115
+ {
116
+ className: isLast ? "text-foreground" : "",
117
+ "aria-current": isLast ? "page" : void 0,
118
+ children: item.label
119
+ }
120
+ ),
121
+ !isLast && /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true" })
122
+ ] }, i)
123
+ );
113
124
  }) })
114
125
  }
115
126
  ),
116
127
  /* @__PURE__ */ jsxs("div", { className: "ui-page-header-row", children: [
117
- /* @__PURE__ */ jsxs("div", { className: "ui-page-header-heading min-w-0", children: [
128
+ /* @__PURE__ */ jsxs("div", { className: "ui-page-header-heading", children: [
118
129
  headerLoading ? /* @__PURE__ */ jsx("h1", { className: "ui-page-title ui-skeleton-block ui-page-title-placeholder", children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: t("layout.pageHeader.loading") }) }) : status != null ? /* @__PURE__ */ jsxs("div", { className: "ui-page-header-title-row", children: [
119
130
  /* @__PURE__ */ jsx("h1", { className: "ui-page-title", children: title }),
120
131
  /* @__PURE__ */ jsx("div", { className: "ui-page-header-status", children: status })
@@ -136,6 +147,7 @@ function PageContainerRoot({
136
147
  ]
137
148
  }
138
149
  ),
150
+ toolbar != null && /* @__PURE__ */ jsx("div", { className: "ui-page-toolbar", children: toolbar }),
139
151
  children != null && /* @__PURE__ */ jsx("div", { className: "ui-page-body", children }),
140
152
  footer && /* @__PURE__ */ jsx("footer", { className: "ui-page-footer", children: footer })
141
153
  ]