@aortl/admin-react 0.16.1 → 0.17.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 (86) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/dist/AdminRoot.d.ts.map +1 -1
  3. package/dist/Alert.d.ts +6 -1
  4. package/dist/Alert.d.ts.map +1 -1
  5. package/dist/Avatar.d.ts +21 -0
  6. package/dist/Avatar.d.ts.map +1 -0
  7. package/dist/Badge.d.ts +8 -2
  8. package/dist/Badge.d.ts.map +1 -1
  9. package/dist/BarChart.d.ts +4 -14
  10. package/dist/BarChart.d.ts.map +1 -1
  11. package/dist/BrandTile.d.ts +16 -3
  12. package/dist/BrandTile.d.ts.map +1 -1
  13. package/dist/Breadcrumbs.d.ts +0 -1
  14. package/dist/Breadcrumbs.d.ts.map +1 -1
  15. package/dist/Button.d.ts +4 -6
  16. package/dist/Button.d.ts.map +1 -1
  17. package/dist/ButtonGroup.d.ts +2 -5
  18. package/dist/ButtonGroup.d.ts.map +1 -1
  19. package/dist/Card.d.ts +9 -2
  20. package/dist/Card.d.ts.map +1 -1
  21. package/dist/ChartLegend.d.ts +2 -5
  22. package/dist/ChartLegend.d.ts.map +1 -1
  23. package/dist/CodeBlock.d.ts +2 -4
  24. package/dist/CodeBlock.d.ts.map +1 -1
  25. package/dist/Container.d.ts +3 -4
  26. package/dist/Container.d.ts.map +1 -1
  27. package/dist/Dialog.d.ts +3 -14
  28. package/dist/Dialog.d.ts.map +1 -1
  29. package/dist/Donut.d.ts +4 -6
  30. package/dist/Donut.d.ts.map +1 -1
  31. package/dist/Field.d.ts +3 -19
  32. package/dist/Field.d.ts.map +1 -1
  33. package/dist/Indicator.d.ts +2 -3
  34. package/dist/Indicator.d.ts.map +1 -1
  35. package/dist/Input.d.ts +6 -1
  36. package/dist/Input.d.ts.map +1 -1
  37. package/dist/Kbd.d.ts +3 -15
  38. package/dist/Kbd.d.ts.map +1 -1
  39. package/dist/Link.d.ts +5 -13
  40. package/dist/Link.d.ts.map +1 -1
  41. package/dist/Menu.d.ts +1 -5
  42. package/dist/Menu.d.ts.map +1 -1
  43. package/dist/Pagination.d.ts +2 -9
  44. package/dist/Pagination.d.ts.map +1 -1
  45. package/dist/PropertyList.d.ts +3 -7
  46. package/dist/PropertyList.d.ts.map +1 -1
  47. package/dist/Prose.d.ts +3 -12
  48. package/dist/Prose.d.ts.map +1 -1
  49. package/dist/Select.d.ts.map +1 -1
  50. package/dist/Separator.d.ts +11 -0
  51. package/dist/Separator.d.ts.map +1 -0
  52. package/dist/Sidebar.d.ts +0 -2
  53. package/dist/Sidebar.d.ts.map +1 -1
  54. package/dist/Spinner.d.ts.map +1 -1
  55. package/dist/StackedBar.d.ts +2 -9
  56. package/dist/StackedBar.d.ts.map +1 -1
  57. package/dist/StatCard.d.ts +3 -6
  58. package/dist/StatCard.d.ts.map +1 -1
  59. package/dist/Table.d.ts +5 -12
  60. package/dist/Table.d.ts.map +1 -1
  61. package/dist/Textarea.d.ts +5 -9
  62. package/dist/Textarea.d.ts.map +1 -1
  63. package/dist/Tooltip.d.ts +0 -1
  64. package/dist/Tooltip.d.ts.map +1 -1
  65. package/dist/admin.scoped.css +345 -11
  66. package/dist/chart-internal.d.ts +4 -16
  67. package/dist/chart-internal.d.ts.map +1 -1
  68. package/dist/cn.d.ts +5 -8
  69. package/dist/cn.d.ts.map +1 -1
  70. package/dist/hotkey-parse.d.ts +7 -21
  71. package/dist/hotkey-parse.d.ts.map +1 -1
  72. package/dist/hotkey-registry.d.ts +2 -14
  73. package/dist/hotkey-registry.d.ts.map +1 -1
  74. package/dist/icon.d.ts +5 -17
  75. package/dist/icon.d.ts.map +1 -1
  76. package/dist/index.cjs +185 -188
  77. package/dist/index.cjs.map +1 -1
  78. package/dist/index.d.ts +5 -3
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.mjs +183 -189
  81. package/dist/index.mjs.map +1 -1
  82. package/dist/portal-context.d.ts +5 -8
  83. package/dist/portal-context.d.ts.map +1 -1
  84. package/dist/useHotkey.d.ts +5 -20
  85. package/dist/useHotkey.d.ts.map +1 -1
  86. package/package.json +4 -3
package/dist/index.cjs CHANGED
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let clsx = require("clsx");
3
3
  let react_jsx_runtime = require("react/jsx-runtime");
4
4
  let react = require("react");
5
+ let _base_ui_react_avatar = require("@base-ui/react/avatar");
5
6
  let _base_ui_react_button = require("@base-ui/react/button");
6
7
  let _base_ui_react_input = require("@base-ui/react/input");
7
8
  let _base_ui_react_field = require("@base-ui/react/field");
@@ -15,10 +16,9 @@ let _base_ui_react_tooltip = require("@base-ui/react/tooltip");
15
16
  let _base_ui_react_dialog = require("@base-ui/react/dialog");
16
17
  //#region src/cn.ts
17
18
  /**
18
- * Every admin class name is prefixed so the bundle can coexist with a host
19
- * page's CSS without colliding on common names like `.btn` or `.card`. The
20
- * matching CSS lives in `@aortl/admin-css/admin.scoped.css` (built by
21
- * `wrap-scoped.mjs`), which carries the same prefix on every selector.
19
+ * Every admin class is prefixed so the bundle coexists with host-page CSS
20
+ * without colliding on common names like `.btn`. Must match the selector
21
+ * prefix `wrap-scoped.mjs` bakes into `@aortl/admin-css/admin.scoped.css`.
22
22
  */
23
23
  var PREFIX = "_ao-";
24
24
  function prefixTokens(value) {
@@ -67,14 +67,11 @@ var Accordion = Object.assign(AccordionRoot, {
67
67
  //#endregion
68
68
  //#region src/portal-context.ts
69
69
  /**
70
- * Container that Base UI popups (Select, Tooltip, etc.) should portal into.
71
- * `<AdminRoot>` publishes its own element here so popups render inside the
72
- * scoped subtree and match the `@scope (._ao-admin-root)` CSS without it
73
- * they portal to `document.body`, outside the scope, and render unstyled. A
74
- * `<Dialog>` ancestor overrides it with its own `<dialog>` element so popups
75
- * join the top layer, painting above the backdrop and escaping its
76
- * `overflow: hidden`. With no provider the context is null and popups fall
77
- * back to `document.body`.
70
+ * Container Base UI popups portal into. `<AdminRoot>` publishes its element so
71
+ * popups stay inside the `@scope (._ao-admin-root)` subtree portaled to
72
+ * `document.body` they fall outside the scope and render unstyled. A `<Dialog>`
73
+ * ancestor overrides it with its `<dialog>` so popups join the top layer above
74
+ * the backdrop. Null falls back to `document.body`.
78
75
  */
79
76
  var PortalContainerContext = (0, react.createContext)(null);
80
77
  //#endregion
@@ -104,14 +101,9 @@ function AdminRoot({ className, theme, systemAccent, style, ref, ...rest }) {
104
101
  //#endregion
105
102
  //#region src/icon.ts
106
103
  /**
107
- * Render an `IconProp` to a React node, defaulting to `size="1em" aria-hidden`
108
- * when given a component reference. The `"1em"` default makes SVG icons inherit
109
- * the host's `font-size`, matching how the Tabler webfont (`<i class="ti …">`)
110
- * renders in the vanilla bundle — so both previews end up the same size.
111
- *
112
- * Anything that is not `null`/`undefined` and not already a React element is
113
- * treated as a component type — `createElement` accepts function components,
114
- * `forwardRef`s (e.g. `@tabler/icons-react`), `memo`, etc.
104
+ * Render an `IconProp`, defaulting component references to `size="1em"
105
+ * aria-hidden`. `"1em"` makes SVG icons inherit the host `font-size`, matching
106
+ * the Tabler webfont in the vanilla bundle.
115
107
  */
116
108
  function renderIcon(icon, size = "1em") {
117
109
  if (icon == null) return null;
@@ -123,7 +115,7 @@ function renderIcon(icon, size = "1em") {
123
115
  }
124
116
  //#endregion
125
117
  //#region src/Alert.tsx
126
- function AlertRoot({ variant, icon, title, description, className, role, children, ...rest }) {
118
+ function AlertRoot({ variant, icon, title, description, action, className, role, children, ...rest }) {
127
119
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
128
120
  role: role ?? (variant === "danger" || variant === "warning" ? "alert" : "status"),
129
121
  className: cn(["alert", `alert-${variant}`], className),
@@ -132,7 +124,8 @@ function AlertRoot({ variant, icon, title, description, className, role, childre
132
124
  renderIcon(icon),
133
125
  title !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AlertTitle, { children: title }) : null,
134
126
  description !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AlertDescription, { children: description }) : null,
135
- children
127
+ children,
128
+ action !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AlertAction, { children: action }) : null
136
129
  ]
137
130
  });
138
131
  }
@@ -148,9 +141,16 @@ function AlertDescription({ className, ...rest }) {
148
141
  ...rest
149
142
  });
150
143
  }
144
+ function AlertAction({ className, ...rest }) {
145
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
146
+ className: cn("alert-action", className),
147
+ ...rest
148
+ });
149
+ }
151
150
  var Alert = Object.assign(AlertRoot, {
152
151
  Title: AlertTitle,
153
- Description: AlertDescription
152
+ Description: AlertDescription,
153
+ Action: AlertAction
154
154
  });
155
155
  //#endregion
156
156
  //#region src/AppShell.tsx
@@ -198,25 +198,97 @@ function AppShellMain({ className, ...rest }) {
198
198
  var AppShell = Object.assign(AppShellRoot, { Main: AppShellMain });
199
199
  //#endregion
200
200
  //#region src/Badge.tsx
201
- function Badge({ variant = "neutral", size = "md", icon, className, children, ...rest }) {
201
+ function RemoveIcon() {
202
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
203
+ width: "1em",
204
+ height: "1em",
205
+ viewBox: "0 0 24 24",
206
+ fill: "none",
207
+ stroke: "currentColor",
208
+ strokeWidth: "2",
209
+ strokeLinecap: "round",
210
+ strokeLinejoin: "round",
211
+ "aria-hidden": "true",
212
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M18 6 6 18" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m6 6 12 12" })]
213
+ });
214
+ }
215
+ function Badge({ variant = "neutral", size = "md", icon, soft = false, onRemove, removeLabel = "Remove", className, children, ...rest }) {
202
216
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
203
217
  className: cn([
204
218
  "badge",
205
219
  variant !== "neutral" && `badge-${variant}`,
206
- size !== "md" && `badge-${size}`
220
+ size !== "md" && `badge-${size}`,
221
+ soft && "badge-soft"
207
222
  ], className),
208
223
  ...rest,
209
- children: [renderIcon(icon), children]
224
+ children: [
225
+ renderIcon(icon),
226
+ children,
227
+ onRemove ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
228
+ type: "button",
229
+ className: cn("badge-remove", void 0),
230
+ "aria-label": removeLabel,
231
+ onClick: onRemove,
232
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RemoveIcon, {})
233
+ }) : null
234
+ ]
210
235
  });
211
236
  }
212
237
  //#endregion
213
238
  //#region src/BrandTile.tsx
214
- function BrandTile({ monogram, icon, className, children, ...rest }) {
239
+ /**
240
+ * Brand/system mark for the navbar — monogram, icon, or shop logo. Precedence
241
+ * is `src` > `icon` > `monogram`. Monogram/icon tiles are `aria-hidden`; image
242
+ * tiles expose `alt` to assistive tech instead.
243
+ */
244
+ function BrandTile({ variant = "solid", size = "md", monogram, icon, src, alt = "", className, children, ...rest }) {
245
+ const classes = cn([
246
+ "brand-tile",
247
+ variant !== "solid" && `brand-tile-${variant}`,
248
+ size === "lg" && "brand-tile-lg"
249
+ ], className);
250
+ if (src) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
251
+ className: classes,
252
+ ...rest,
253
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
254
+ src,
255
+ alt
256
+ })
257
+ });
215
258
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
216
- className: cn("brand-tile", className),
259
+ className: classes,
217
260
  "aria-hidden": true,
218
261
  ...rest,
219
- children: icon ? renderIcon(icon, 14) : children ?? monogram
262
+ children: icon ? renderIcon(icon) : children ?? monogram
263
+ });
264
+ }
265
+ //#endregion
266
+ //#region src/Avatar.tsx
267
+ /**
268
+ * Image avatar with an initials fallback. Initials show until the image loads
269
+ * (and again, React-only, if it errors); the vanilla CSS layers the `<img>`
270
+ * over the initials instead.
271
+ */
272
+ function Avatar({ src, alt, initials, size = "md", shape = "circle", className, children, ...rest }) {
273
+ const fallback = children ?? initials;
274
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_base_ui_react_avatar.Avatar.Root, {
275
+ className: cn([
276
+ "avatar",
277
+ size !== "md" && `avatar-${size}`,
278
+ shape === "square" && "avatar-square"
279
+ ], className),
280
+ ...rest,
281
+ children: [fallback !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_avatar.Avatar.Fallback, { children: fallback }) : null, src !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_avatar.Avatar.Image, {
282
+ src,
283
+ alt
284
+ }) : null]
285
+ });
286
+ }
287
+ /** Overlapping stack of avatars; later children paint on top. */
288
+ function AvatarGroup({ className, ...rest }) {
289
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
290
+ className: cn("avatar-group", className),
291
+ ...rest
220
292
  });
221
293
  }
222
294
  //#endregion
@@ -227,12 +299,6 @@ var MOD_ORDER = [
227
299
  "alt",
228
300
  "meta"
229
301
  ];
230
- /**
231
- * Resolve the modifier `mod` aliases to. Apple platforms use ⌘ (`meta`) as the
232
- * primary command modifier; everywhere else it's Ctrl. Detected once at module
233
- * load (SSR-safe — the registry never dispatches server-side) and shared by the
234
- * parse and display layers so the binding and its `<Kbd>` chip always agree.
235
- */
236
302
  function detectApplePlatform() {
237
303
  if (typeof navigator === "undefined") return false;
238
304
  const platform = navigator.userAgentData?.platform || navigator.platform || "";
@@ -281,11 +347,7 @@ function canonicalize(chord) {
281
347
  parts.push(chord.key);
282
348
  return parts.join("+");
283
349
  }
284
- /**
285
- * Normalize a keyboard event to its canonical chord string. Returns `null`
286
- * if the event is a bare modifier press (`Shift` by itself, etc.) so callers
287
- * can short-circuit before a map lookup.
288
- */
350
+ /** Canonical chord string for a keyboard event; `null` for a bare modifier press. */
289
351
  function normalizeEvent(e) {
290
352
  const key = e.key.toLowerCase();
291
353
  if (key === "control" || key === "shift" || key === "alt" || key === "meta") return null;
@@ -299,7 +361,6 @@ function normalizeEvent(e) {
299
361
  key
300
362
  });
301
363
  }
302
- /** A single printable symbol (`?`, `+`, `:`, …) — not a letter, digit, or named key. */
303
364
  function isShiftedSymbol(key) {
304
365
  return key.length === 1 && !/[a-z0-9]/.test(key);
305
366
  }
@@ -351,26 +412,13 @@ function toAriaPart(chord) {
351
412
  parts.push(chord.key.length === 1 ? chord.key.toUpperCase() : chord.key);
352
413
  return parts.join("+");
353
414
  }
354
- /**
355
- * Serialize one or more chords to the `aria-keyshortcuts` format
356
- * (space-separated alternatives, modifiers as `Control`/`Shift`/etc.).
357
- */
415
+ /** Serialize chords to `aria-keyshortcuts` format (space-separated alternatives). */
358
416
  function toAriaKeyShortcuts(chords) {
359
417
  return chords.map(toAriaPart).join(" ");
360
418
  }
361
419
  //#endregion
362
420
  //#region src/Kbd.tsx
363
- /**
364
- * Visual representation of a keyboard shortcut. Two shapes:
365
- *
366
- * ```tsx
367
- * <Kbd keys="mod+s" /> // parsed: <Ctrl><S> in a .kbd-group
368
- * <Kbd>Esc</Kbd> // literal: single <kbd>Esc</kbd>
369
- * ```
370
- *
371
- * Render outside of action surfaces (tooltips, help dialogs) or inside them
372
- * via the `hotkey` prop on `<Button>` / `<Menu.Item>`.
373
- */
421
+ /** Keyboard shortcut chips — parsed via `keys`, or a single literal chip via `children`. */
374
422
  function Kbd({ keys, children, className, ...rest }) {
375
423
  if (keys != null) {
376
424
  const chord = parseKeys(keys)[0];
@@ -422,11 +470,7 @@ function dispatch(e) {
422
470
  e.preventDefault();
423
471
  for (const entry of bucket) entry.handlerRef.current?.(e);
424
472
  }
425
- /**
426
- * Register a hotkey entry under each of its canonical chord strings.
427
- * Returns an unregister function that removes the entry from every bucket
428
- * and detaches the listener if the registry is empty.
429
- */
473
+ /** Returns an unregister function. */
430
474
  function register(canonicalChords, entry) {
431
475
  for (const chord of canonicalChords) {
432
476
  let bucket = registry.get(chord);
@@ -450,16 +494,9 @@ function register(canonicalChords, entry) {
450
494
  //#endregion
451
495
  //#region src/useHotkey.ts
452
496
  /**
453
- * Register a keyboard shortcut. The handler is latched in a ref internally so
454
- * callers don't need to memoize it. Passing nullish `keys` is a no-op, so
455
- * the hook is safe to call unconditionally from components that may or may
456
- * not have a binding (e.g. the `hotkey` prop on `<Button>`).
457
- *
458
- * @example
459
- * useHotkey("mod+s", save);
460
- * useHotkey(["mod+s", "mod+enter"], save, { enabled: !isLoading });
461
- *
462
- * Returns derived strings for rendering — see {@link HotkeyInfo}.
497
+ * Register a keyboard shortcut, e.g. `useHotkey("mod+s", save)`. The handler
498
+ * is latched in a ref, so callers need not memoize it. Nullish `keys` is a
499
+ * no-op, so the hook is safe to call unconditionally.
463
500
  */
464
501
  function useHotkey(keys, handler, options) {
465
502
  const enabled = options?.enabled ?? true;
@@ -579,8 +616,8 @@ var Breadcrumbs = Object.assign(BreadcrumbsRoot, {
579
616
  });
580
617
  //#endregion
581
618
  //#region src/Input.tsx
582
- function Input({ variant = "bordered", inputSize = "md", className, type = "text", ...rest }) {
583
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_input.Input, {
619
+ function Input({ variant = "bordered", inputSize = "md", icon, iconTrailing, className, type = "text", ...rest }) {
620
+ const input = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_input.Input, {
584
621
  type,
585
622
  className: cn([
586
623
  "input",
@@ -589,6 +626,15 @@ function Input({ variant = "bordered", inputSize = "md", className, type = "text
589
626
  ], className),
590
627
  ...rest
591
628
  });
629
+ if (icon == null && iconTrailing == null) return input;
630
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
631
+ className: cn("input-icon", void 0),
632
+ children: [
633
+ renderIcon(icon),
634
+ input,
635
+ renderIcon(iconTrailing)
636
+ ]
637
+ });
592
638
  }
593
639
  //#endregion
594
640
  //#region src/FileInput.tsx
@@ -656,11 +702,7 @@ function Indicator({ label, variant = "neutral", size = "sm", icon, placement =
656
702
  }
657
703
  //#endregion
658
704
  //#region src/Link.tsx
659
- /**
660
- * A text link — a plain `<a>` with the design system's link styling: primary
661
- * color, hover shift, underline, and a focus-visible ring. Pass `external` for
662
- * the new-tab affordance.
663
- */
705
+ /** A plain `<a>` with the design system's link styling. */
664
706
  function Link({ external, icon, iconTrailing, className, target, rel, children, ...rest }) {
665
707
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
666
708
  target: target ?? (external ? "_blank" : void 0),
@@ -675,13 +717,22 @@ function Link({ external, icon, iconTrailing, className, target, rel, children,
675
717
  });
676
718
  }
677
719
  //#endregion
678
- //#region src/Pagination.tsx
720
+ //#region src/Separator.tsx
679
721
  /**
680
- * Compute the items to render for a given `page` / `total`. Always returns:
681
- * previous, ...numbers/ellipses, next
682
- * with `boundaryCount` items on each end and `siblingCount` items around `page`.
683
- * Pure: no React state, safe to call during render.
722
+ * A styled `<hr>` (implicit `role="separator"`). Margins are zeroed — spacing
723
+ * comes from the parent's gap or margin utilities.
684
724
  */
725
+ function Separator({ orientation = "horizontal", className, ...rest }) {
726
+ const vertical = orientation === "vertical";
727
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("hr", {
728
+ className: cn(["separator", vertical && "separator-vertical"], className),
729
+ "aria-orientation": vertical ? "vertical" : void 0,
730
+ ...rest
731
+ });
732
+ }
733
+ //#endregion
734
+ //#region src/Pagination.tsx
735
+ /** Pure (safe during render): previous, numbers/ellipses (`boundaryCount` at each end, `siblingCount` around `page`), next. */
685
736
  function getPaginationItems({ page, total, siblingCount = 1, boundaryCount = 1 }) {
686
737
  if (total <= 0) return [{
687
738
  type: "previous",
@@ -837,11 +888,9 @@ function defaultRender(item, onPageChange, prev, next) {
837
888
  //#endregion
838
889
  //#region src/Textarea.tsx
839
890
  /**
840
- * Multi-line text input. Rendered through Base UI's `Field.Control` with a
841
- * `<textarea>` swapped in for the default `<input>`, so inside a `<Field>` it
842
- * gets the same wiring as `<Input>`: a generated id, label `htmlFor`
843
- * association, and validity-driven `:user-valid` / `<Field.Error>`. Works
844
- * standalone too — `Field.Control` falls back to a default context.
891
+ * Multi-line input via Base UI `Field.Control` with a `<textarea>` swapped in,
892
+ * so inside a `<Field>` it gets the same wiring as `<Input>` (generated id,
893
+ * label association, validity). Works standalone via the default context.
845
894
  */
846
895
  function Textarea({ variant = "bordered", textareaSize = "md", autoResize, className, ...rest }) {
847
896
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_field.Field.Control, {
@@ -1053,10 +1102,9 @@ var Select = Object.assign(SelectRoot, {
1053
1102
  //#endregion
1054
1103
  //#region src/Container.tsx
1055
1104
  /**
1056
- * Page content region: a centered, max-width column that also owns the
1057
- * vertical gap between stacked sections. Place inside `<AppShell.Main>`,
1058
- * which provides no padding of its own. Distinct from the `.Container`
1059
- * escape hatch (e.g. `Card.Container`) — this is a standalone page region.
1105
+ * Page content region: a centered, max-width column that owns the vertical
1106
+ * gap between stacked sections. Place inside `<AppShell.Main>`, which has no
1107
+ * padding of its own. Not the `.Container` escape hatch (`Card.Container`).
1060
1108
  */
1061
1109
  function Container({ size = "md", compact, className, ...rest }) {
1062
1110
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -1074,13 +1122,14 @@ function Container({ size = "md", compact, className, ...rest }) {
1074
1122
  * The bare `.card` container — no body, no title. Use this when you need to
1075
1123
  * compose the internals yourself (e.g. a media block above the body).
1076
1124
  */
1077
- function CardContainer({ variant = "default", bordered, compact, className, ...rest }) {
1125
+ function CardContainer({ variant = "default", bordered, compact, scroll, className, ...rest }) {
1078
1126
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1079
1127
  className: cn([
1080
1128
  "card",
1081
1129
  variant !== "default" && `card-${variant}`,
1082
1130
  bordered && "card-bordered",
1083
- compact && "card-compact"
1131
+ compact && "card-compact",
1132
+ scroll && "card-scroll"
1084
1133
  ], className),
1085
1134
  ...rest
1086
1135
  });
@@ -1090,23 +1139,29 @@ function CardContainer({ variant = "default", bordered, compact, className, ...r
1090
1139
  * an optional title (with icon), description, children, and actions. For
1091
1140
  * anything outside that shape, use `<Card.Container>` and compose by hand.
1092
1141
  */
1093
- function CardRoot({ variant, bordered, compact, icon, title, description, toolbar, actions, className, children, ...rest }) {
1142
+ function CardRoot({ variant, bordered, compact, media, icon, title, description, toolbar, actions, className, children, ...rest }) {
1094
1143
  const titleEl = icon !== void 0 || title !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardTitle, {
1095
1144
  icon,
1096
1145
  children: title
1097
1146
  }) : null;
1098
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardContainer, {
1147
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CardContainer, {
1099
1148
  variant,
1100
1149
  bordered,
1101
1150
  compact,
1102
1151
  className,
1103
1152
  ...rest,
1104
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CardBody, { children: [
1153
+ children: [media !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardMedia, { children: media }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CardBody, { children: [
1105
1154
  toolbar !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CardHeader, { children: [titleEl, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardToolbar, { children: toolbar })] }) : titleEl,
1106
1155
  description !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardDescription, { children: description }) : null,
1107
1156
  children,
1108
1157
  actions !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardActions, { children: actions }) : null
1109
- ] })
1158
+ ] })]
1159
+ });
1160
+ }
1161
+ function CardMedia({ className, ...rest }) {
1162
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1163
+ className: cn("card-media", className),
1164
+ ...rest
1110
1165
  });
1111
1166
  }
1112
1167
  function CardBody({ className, ...rest }) {
@@ -1148,6 +1203,7 @@ function CardActions({ className, ...rest }) {
1148
1203
  }
1149
1204
  var Card = Object.assign(CardRoot, {
1150
1205
  Container: CardContainer,
1206
+ Media: CardMedia,
1151
1207
  Body: CardBody,
1152
1208
  Header: CardHeader,
1153
1209
  Toolbar: CardToolbar,
@@ -1158,12 +1214,9 @@ var Card = Object.assign(CardRoot, {
1158
1214
  //#endregion
1159
1215
  //#region src/StatCard.tsx
1160
1216
  /**
1161
- * Compact KPI tile — `label / value / detail`. Renders a `.card` shell (so it
1162
- * shares the surface, border, radius, shadow, and every card modifier) with an
1163
- * inverted inner hierarchy: the value dominates, the label is a small
1164
- * annotation. `compact`/`bordered` map to the shared `.card-compact`/
1165
- * `.card-bordered` modifiers. For free-form tiles, use `<Card>`; for
1166
- * label/value tables, use `<PropertyList>`.
1217
+ * Compact KPI tile (label / value / detail) on a `.card` shell, so it shares
1218
+ * every card modifier `compact`/`bordered` map to `.card-compact`/`.card-bordered`.
1219
+ * Free-form tiles: `<Card>`; label/value tables: `<PropertyList>`.
1167
1220
  */
1168
1221
  function StatCard({ variant = "default", label, value, detail, icon, compact, bordered, className, children, ...rest }) {
1169
1222
  const hasLabel = label !== void 0;
@@ -1196,11 +1249,8 @@ function StatCard({ variant = "default", label, value, detail, icon, compact, bo
1196
1249
  //#endregion
1197
1250
  //#region src/chart-internal.ts
1198
1251
  /**
1199
- * Multi-series palette references EXISTING Flexoki palette tokens, NOT a new
1200
- * token layer. Cycled by index (`SERIES[i % len]`); a datum's own `color`
1201
- * overrides. Vanilla authors copy the same sequence (it's documented), so both
1202
- * bundles render identical colours. Single-series charts ignore this entirely
1203
- * and follow `currentColor`.
1252
+ * Multi-series palette of existing Flexoki tokens, not a new token layer. The
1253
+ * documented vanilla sequence copies this exactly both bundles must match.
1204
1254
  */
1205
1255
  var SERIES = [
1206
1256
  "var(--color-blue-500)",
@@ -1212,7 +1262,6 @@ var SERIES = [
1212
1262
  "var(--color-yellow-500)",
1213
1263
  "var(--color-red-400)"
1214
1264
  ];
1215
- /** Resolve a segment's colour: explicit `datum.color` wins, else cycle SERIES. */
1216
1265
  function seriesColor(datum, index) {
1217
1266
  return datum.color ?? SERIES[index % SERIES.length];
1218
1267
  }
@@ -1221,11 +1270,7 @@ function computeMax(data, explicit) {
1221
1270
  if (explicit !== void 0) return explicit;
1222
1271
  return Math.max(1, ...data.map((d) => d.value));
1223
1272
  }
1224
- /**
1225
- * Build the cumulative `conic-gradient` stop string for a donut/pie:
1226
- * `<color> <from>deg <to>deg, …`. Degrees accumulate across segments. A
1227
- * non-positive total yields a single neutral fill so the ring isn't blank.
1228
- */
1273
+ /** Cumulative `conic-gradient` stops. A non-positive total yields a neutral fill so the ring isn't blank. */
1229
1274
  function buildDonutSegments(data) {
1230
1275
  const total = data.reduce((sum, d) => sum + Math.max(0, d.value), 0);
1231
1276
  if (total <= 0) return "var(--color-surface-strong) 0 100%";
@@ -1246,10 +1291,7 @@ var TYPE_NOUN = {
1246
1291
  donut: "Donut chart",
1247
1292
  pie: "Pie chart"
1248
1293
  };
1249
- /**
1250
- * Auto-generated summary for the chart root's `aria-label`. Callers that pass
1251
- * their own `aria-label` skip this. Example: "Bar chart. Mon: 80, Tue: 52."
1252
- */
1294
+ /** Chart-root `aria-label` summary, e.g. "Bar chart. Mon: 80, Tue: 52." */
1253
1295
  function buildAriaLabel(type, data) {
1254
1296
  const parts = data.map((d) => d.label !== void 0 ? `${d.label}: ${d.value}` : `${d.value}`);
1255
1297
  return `${TYPE_NOUN[type]}. ${parts.join(", ")}.`;
@@ -1267,10 +1309,7 @@ function mergeStyle(vars, incoming) {
1267
1309
  }
1268
1310
  //#endregion
1269
1311
  //#region src/BarChart.tsx
1270
- /**
1271
- * The bare bar-chart grid — no bars. Compose `<BarChart.Bar>` children by hand
1272
- * (e.g. to interleave a reference line). Sets `role="img"`; pass `aria-label`.
1273
- */
1312
+ /** Bare grid, no bars — compose `<BarChart.Bar>` by hand. Sets `role="img"`; pass `aria-label`. */
1274
1313
  function BarChartContainer({ orientation = "horizontal", size = "md", showValues, inline, variant = "info", className, ...rest }) {
1275
1314
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1276
1315
  role: "img",
@@ -1287,10 +1326,8 @@ function BarChartContainer({ orientation = "horizontal", size = "md", showValues
1287
1326
  });
1288
1327
  }
1289
1328
  /**
1290
- * One bar. Renders a label (only when present), the fill (with a native
1291
- * `title`), and an always-present value cell (hidden by CSS unless the chart
1292
- * carries `.chart-values`). Stays `currentColor` unless an explicit colour is
1293
- * given — single-series bars never cycle the SERIES palette.
1329
+ * One bar. The value cell always renders (CSS hides it without `.chart-values`);
1330
+ * fill stays `currentColor` single-series bars never cycle SERIES.
1294
1331
  */
1295
1332
  function Bar({ datum, value, label, color, className, style, ...rest }) {
1296
1333
  const v = datum?.value ?? value ?? 0;
@@ -1322,12 +1359,7 @@ function Bar({ datum, value, label, color, className, style, ...rest }) {
1322
1359
  ]
1323
1360
  });
1324
1361
  }
1325
- /**
1326
- * Single-series bar chart. Computes the max, sets `--chart-max` on the
1327
- * container (bars inherit it), and generates an overridable `aria-label`.
1328
- * Horizontal by default; pass `orientation="vertical"` for columns. For
1329
- * hand-composed layouts use `<BarChart.Container>` + `<BarChart.Bar>`.
1330
- */
1362
+ /** Single-series bar chart. For hand-composed layouts use `<BarChart.Container>` + `<BarChart.Bar>`. */
1331
1363
  function BarChartRoot({ data, max, orientation = "horizontal", size = "md", showValues, inline, variant = "info", style, "aria-label": ariaLabel, ...rest }) {
1332
1364
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BarChartContainer, {
1333
1365
  orientation,
@@ -1348,11 +1380,8 @@ var BarChart = Object.assign(BarChartRoot, {
1348
1380
  //#endregion
1349
1381
  //#region src/ChartLegend.tsx
1350
1382
  /**
1351
- * Shared legend for `<Donut>` and `<StackedBar>` one swatch + label per
1352
- * datum. Each row carries its own `title`, which is where the donut's
1353
- * per-slice read-out lives (a conic-gradient slice has no element to hang a
1354
- * `title` on). The swatch colour mirrors `seriesColor`, so legend and chart
1355
- * stay in sync.
1383
+ * Each row's `title` carries the donut's per-slice read-out a conic-gradient
1384
+ * slice has no element to hang a `title` on.
1356
1385
  */
1357
1386
  function ChartLegend({ data, className, ...rest }) {
1358
1387
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
@@ -1375,7 +1404,7 @@ function Figure({ size = "md", className, ...rest }) {
1375
1404
  ...rest
1376
1405
  });
1377
1406
  }
1378
- /** The masked conic-gradient ring. Builds `--donut-segments` from the data. */
1407
+ /** The masked conic-gradient ring. */
1379
1408
  function Ring({ data, pie, thickness, className, style, ...rest }) {
1380
1409
  const vars = { "--donut-segments": buildDonutSegments(data) };
1381
1410
  if (thickness !== void 0 && !pie) vars["--donut-thickness"] = thickness;
@@ -1393,11 +1422,9 @@ function Center({ className, ...rest }) {
1393
1422
  });
1394
1423
  }
1395
1424
  /**
1396
- * Donut (or `pie`) breakdown. Builds the cumulative conic-gradient string from
1397
- * `data`, overlays an optional `centerLabel`, and generates an overridable
1398
- * `aria-label`. Per-slice read-outs live on the optional `legend` rows — a
1399
- * conic slice has no element to carry a `title`. Resize by overriding
1400
- * `--chart-size` (it inherits to the figure) or via `size`.
1425
+ * Donut (or `pie`) breakdown. Per-slice read-outs live on the `legend` rows
1426
+ * a conic slice has no element to carry a `title`. Resize via `size` or
1427
+ * `--chart-size`.
1401
1428
  */
1402
1429
  function DonutRoot({ data, size = "md", thickness, pie, centerLabel, legend, inline, className, "aria-label": ariaLabel, ...rest }) {
1403
1430
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -1430,10 +1457,7 @@ function Track({ className, ...rest }) {
1430
1457
  ...rest
1431
1458
  });
1432
1459
  }
1433
- /**
1434
- * One proportion segment, sized by `flex: var(--value)`. Multi-series by
1435
- * default: takes its colour from `seriesColor` (SERIES cycle or `datum.color`).
1436
- */
1460
+ /** One proportion segment, sized by `flex: var(--value)`; SERIES-cycle colours by default. */
1437
1461
  function Segment({ datum, index = 0, value, color, className, style, ...rest }) {
1438
1462
  const v = datum?.value ?? value ?? 0;
1439
1463
  const segColor = datum !== void 0 ? seriesColor(datum, index) : color;
@@ -1447,11 +1471,7 @@ function Segment({ datum, index = 0, value, color, className, style, ...rest })
1447
1471
  ...rest
1448
1472
  });
1449
1473
  }
1450
- /**
1451
- * Single horizontal proportion bar — a "60% A / 30% B / 10% C" breakdown.
1452
- * Segments are sized by their flex ratios (no max needed) and coloured from the
1453
- * SERIES palette by default. Generates an overridable `aria-label`.
1454
- */
1474
+ /** Single horizontal proportion bar. Segments size by flex ratio — no max needed. */
1455
1475
  function StackedBarRoot({ data, legend, inline, className, "aria-label": ariaLabel, ...rest }) {
1456
1476
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1457
1477
  role: "img",
@@ -1486,11 +1506,7 @@ function DefaultCloseIcon() {
1486
1506
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M18 6 6 18" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m6 6 12 12" })]
1487
1507
  });
1488
1508
  }
1489
- /**
1490
- * The bare `<dialog>` primitive — no opinions about header, body, or footer.
1491
- * Use this when the default `<Dialog>` layout doesn't fit (custom header,
1492
- * media block, multi-step content).
1493
- */
1509
+ /** The bare `<dialog>` primitive — for layouts the default `<Dialog>` doesn't fit. */
1494
1510
  function DialogContainer({ open, onOpenChange, size = "md", closedby = "any", className, children, ref: consumerRef, ...rest }) {
1495
1511
  const ref = (0, react.useRef)(null);
1496
1512
  const onOpenChangeRef = (0, react.useRef)(onOpenChange);
@@ -1572,11 +1588,7 @@ function DialogCloseButton({ icon, className, children, onClick, type = "button"
1572
1588
  children: children ?? (icon !== void 0 ? renderIcon(icon) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultCloseIcon, {}))
1573
1589
  });
1574
1590
  }
1575
- /**
1576
- * Standard modal: a `<dialog>` with an opinionated header / body / footer
1577
- * layout driven by shorthand props. For anything outside that shape, use
1578
- * `<Dialog.Container>` and compose by hand.
1579
- */
1591
+ /** Standard modal with shorthand-driven header/body/footer. For other shapes, compose `<Dialog.Container>` by hand. */
1580
1592
  function DialogRoot({ icon, title, description, actions, dismissible = true, closeLabel = "Close", children, ...containerProps }) {
1581
1593
  const hasTitle = title !== void 0 || icon !== void 0;
1582
1594
  const showHeader = hasTitle || dismissible;
@@ -1604,23 +1616,14 @@ var Dialog = Object.assign(DialogRoot, {
1604
1616
  });
1605
1617
  //#endregion
1606
1618
  //#region src/Field.tsx
1607
- /**
1608
- * The bare `.field` container. Use this when the default layout doesn't fit —
1609
- * multiple validity-keyed `<Field.Error>` messages, a control that needs to
1610
- * sit between description and error, etc.
1611
- */
1619
+ /** The bare `.field` container — for layouts the default `<Field>` doesn't fit. */
1612
1620
  function FieldContainer({ className, ...rest }) {
1613
1621
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_field.Field.Root, {
1614
1622
  className: cn("field", className),
1615
1623
  ...rest
1616
1624
  });
1617
1625
  }
1618
- /**
1619
- * Standard field: a `.field` container that lays out an optional label, the
1620
- * control passed as `children`, an optional description, and an optional
1621
- * single-message error. For anything outside that shape, use
1622
- * `<Field.Container>` and compose by hand.
1623
- */
1626
+ /** Standard field — label, control (`children`), description, error. For other shapes, compose `<Field.Container>` by hand. */
1624
1627
  function FieldRoot({ label, description, error, required, inline, className, children, ...rest }) {
1625
1628
  const labelEl = label !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldLabel, {
1626
1629
  required,
@@ -1894,8 +1897,7 @@ var Tabs = Object.assign(TabsRoot, {
1894
1897
  /**
1895
1898
  * Styled `<pre>` for logs, JSON dumps, terminal output, raw model output.
1896
1899
  * Theme-following surface via `--color-code-surface` / `--color-code-text`.
1897
- * Wraps by default; opt out with `nowrap`. No syntax highlighting layer
1898
- * Shiki/Prism on a nested `<code>` if needed.
1900
+ * No syntax highlighting layer Shiki/Prism on a nested `<code>` if needed.
1899
1901
  */
1900
1902
  function CodeBlock({ nowrap, className, ...rest }) {
1901
1903
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
@@ -1906,18 +1908,9 @@ function CodeBlock({ nowrap, className, ...rest }) {
1906
1908
  //#endregion
1907
1909
  //#region src/Prose.tsx
1908
1910
  /**
1909
- * A styled container for HTML the system can't annotate with its semantic class
1910
- * names — backend-rendered markdown, CMS bodies, model output. Styles its
1911
- * descendant flow elements (`p`, `ul`, `a`, `code`, `blockquote`, `table`, …)
1912
- * from the design tokens, scoped to this wrapper so the rest of the admin UI
1913
- * keeps the global element reset.
1914
- *
1915
- * ```tsx
1916
- * <Prose dangerouslySetInnerHTML={{ __html: renderedMarkdown }} />
1917
- * ```
1918
- *
1919
- * Accepts children too — `<Prose><h2>…</h2><p>…</p></Prose>` — for content
1920
- * authored directly in JSX.
1911
+ * Styled container for HTML the system can't annotate with its class names —
1912
+ * backend-rendered markdown, CMS bodies, model output. Element styles are
1913
+ * scoped to this wrapper; the rest of the admin UI keeps the global reset.
1921
1914
  */
1922
1915
  function Prose({ className, ...rest }) {
1923
1916
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -2108,6 +2101,7 @@ function TableBody({ className, ...rest }) {
2108
2101
  ...rest
2109
2102
  });
2110
2103
  }
2104
+ /** Footer rows are semibold by default; the first row gets a strong top divider against the body. */
2111
2105
  function TableFoot({ className, ...rest }) {
2112
2106
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tfoot", {
2113
2107
  className,
@@ -2316,6 +2310,8 @@ exports.Accordion = Accordion;
2316
2310
  exports.AdminRoot = AdminRoot;
2317
2311
  exports.Alert = Alert;
2318
2312
  exports.AppShell = AppShell;
2313
+ exports.Avatar = Avatar;
2314
+ exports.AvatarGroup = AvatarGroup;
2319
2315
  exports.Badge = Badge;
2320
2316
  exports.BarChart = BarChart;
2321
2317
  exports.BrandTile = BrandTile;
@@ -2347,6 +2343,7 @@ exports.Radio = Radio;
2347
2343
  exports.RadioGroup = RadioGroup;
2348
2344
  exports.SERIES = SERIES;
2349
2345
  exports.Select = Select;
2346
+ exports.Separator = Separator;
2350
2347
  exports.Sidebar = Sidebar;
2351
2348
  exports.Spinner = Spinner;
2352
2349
  exports.StackedBar = StackedBar;