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