@charcuterie/ui 3.30.0 → 3.32.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 (69) hide show
  1. package/README.md +14 -0
  2. package/dist/ActionTiles/ActionTiles.d.ts +115 -0
  3. package/dist/ActionTiles/ActionTiles.d.ts.map +1 -0
  4. package/dist/ActionTiles/ActionTiles.js +115 -0
  5. package/dist/ActionTiles/ActionTiles.js.map +1 -0
  6. package/dist/RadioGroup/RadioGroup.d.ts +10 -0
  7. package/dist/RadioGroup/RadioGroup.d.ts.map +1 -1
  8. package/dist/RadioGroup/RadioGroup.js +12 -39
  9. package/dist/RadioGroup/RadioGroup.js.map +1 -1
  10. package/dist/RadioGroup/RadioGroupOption.d.ts.map +1 -1
  11. package/dist/RadioGroup/RadioGroupOption.js +3 -33
  12. package/dist/RadioGroup/RadioGroupOption.js.map +1 -1
  13. package/dist/Tabs/PanelTabs.d.ts +56 -0
  14. package/dist/Tabs/PanelTabs.d.ts.map +1 -0
  15. package/dist/Tabs/PanelTabs.js +163 -0
  16. package/dist/Tabs/PanelTabs.js.map +1 -0
  17. package/dist/Tabs/RoutedTabs.d.ts +19 -0
  18. package/dist/Tabs/RoutedTabs.d.ts.map +1 -0
  19. package/dist/Tabs/RoutedTabs.js +28 -0
  20. package/dist/Tabs/RoutedTabs.js.map +1 -0
  21. package/dist/Tabs/TabLink.d.ts +34 -0
  22. package/dist/Tabs/TabLink.d.ts.map +1 -0
  23. package/dist/Tabs/TabLink.js +66 -0
  24. package/dist/Tabs/TabLink.js.map +1 -0
  25. package/dist/Tabs/TabTrigger.d.ts +1 -1
  26. package/dist/Tabs/TabTrigger.d.ts.map +1 -1
  27. package/dist/Tabs/TabTrigger.js +6 -30
  28. package/dist/Tabs/TabTrigger.js.map +1 -1
  29. package/dist/Tabs/Tabs.d.ts +80 -64
  30. package/dist/Tabs/Tabs.d.ts.map +1 -1
  31. package/dist/Tabs/Tabs.js +53 -182
  32. package/dist/Tabs/Tabs.js.map +1 -1
  33. package/dist/Tabs/tabItems.d.ts +36 -0
  34. package/dist/Tabs/tabItems.d.ts.map +1 -0
  35. package/dist/Tabs/tabItems.js +2 -0
  36. package/dist/Tabs/tabItems.js.map +1 -0
  37. package/dist/Tabs/tabStyles.d.ts +41 -0
  38. package/dist/Tabs/tabStyles.d.ts.map +1 -0
  39. package/dist/Tabs/tabStyles.js +79 -0
  40. package/dist/Tabs/tabStyles.js.map +1 -0
  41. package/dist/index.d.ts +4 -1
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +1 -0
  44. package/dist/index.js.map +1 -1
  45. package/dist/tileStyles.d.ts +83 -0
  46. package/dist/tileStyles.d.ts.map +1 -0
  47. package/dist/tileStyles.js +98 -0
  48. package/dist/tileStyles.js.map +1 -0
  49. package/package.json +1 -1
  50. package/src/ActionTiles/ActionTiles.mdx +131 -0
  51. package/src/ActionTiles/ActionTiles.stories.tsx +311 -0
  52. package/src/ActionTiles/ActionTiles.test.tsx +292 -0
  53. package/src/ActionTiles/ActionTiles.tsx +292 -0
  54. package/src/RadioGroup/RadioGroup.mdx +7 -0
  55. package/src/RadioGroup/RadioGroup.tsx +16 -42
  56. package/src/RadioGroup/RadioGroupOption.tsx +8 -38
  57. package/src/Tabs/PanelTabs.tsx +260 -0
  58. package/src/Tabs/RoutedTabs.tsx +58 -0
  59. package/src/Tabs/TabLink.tsx +132 -0
  60. package/src/Tabs/TabTrigger.tsx +10 -39
  61. package/src/Tabs/Tabs.mdx +70 -0
  62. package/src/Tabs/Tabs.stories.tsx +133 -1
  63. package/src/Tabs/Tabs.test.tsx +169 -0
  64. package/src/Tabs/Tabs.tsx +94 -296
  65. package/src/Tabs/tabItems.ts +40 -0
  66. package/src/Tabs/tabStyles.ts +107 -0
  67. package/src/index.ts +13 -3
  68. package/src/sourceRules.test.ts +9 -1
  69. package/src/tileStyles.ts +118 -0
package/README.md CHANGED
@@ -82,6 +82,20 @@ screen reader announces. `onClick` is required, so a pill nobody can press is a
82
82
  construction
83
83
  ([decision](../../docs/decisions/2026-08-22-a-pressable-badge-is-a-sibling-component-not-a-prop.md)).
84
84
 
85
+ **`ActionTiles` is the tile that presses**, and it is the case the
86
+ [choice-tile record](../../docs/decisions/2026-08-25-a-choice-tile-is-a-radiogroup-shape-not-a-third-component.md)
87
+ named as out of scope: mux-magic's "Pick a tool" tiles are `<a href>` and points-market's are
88
+ `<Link>`, and a link is not a radio. That record's test was *only the box changes*, and here
89
+ it is false — no role to borrow, no roving tabindex, no selection-follows-focus, no
90
+ read-only, no pending value — so the two share **the box and nothing else**, through
91
+ `tileStyles.ts`, and the test compares *computed* styles rather than class names. It exists
92
+ because QueuePilot's queue-type chooser was two `Button`s with `height: auto`: a `Button`
93
+ carries **no block padding at all**, so the override computed to `padding: 0` down the block
94
+ axis and shipped a card whose title sat flush against its top border. Nothing could report
95
+ it — the class really was in the DOM, tsc never reads the CSS, and unstyled markup passes
96
+ axe
97
+ ([decision](../../docs/decisions/2026-09-01-a-tile-that-acts-is-its-own-component-and-shares-only-the-box.md)).
98
+
85
99
  **The unified app shell adds four**: `Shell`, `Header`, `Rail`, `Main` — the fleet's largest
86
100
  single duplication, where ten of twelve UI repos hand-roll the page chrome and three of them
87
101
  have a file named `AppShell.tsx` (two of those headers are a *byte-identical* class string,
@@ -0,0 +1,115 @@
1
+ import type { ControlSize } from "@charcuterie/tokens";
2
+ import type { ReactNode } from "react";
3
+ export type ActionTileItem = {
4
+ /**
5
+ * A line of help under the name. Drawn one step down the type ramp
6
+ * in `content-muted`, **inside** the tile — so `getByRole` computes
7
+ * it into the accessible name. A hint a screen reader never reads
8
+ * is a hint half the audience does not have.
9
+ */
10
+ hint?: ReactNode;
11
+ /**
12
+ * Makes this tile a real `<a href>`: middle-click, ctrl-click,
13
+ * "open in new tab", "copy link address" and the status bar all
14
+ * come from the element rather than from the paint. Routed through
15
+ * the injected `RouterLink` when the destination is same-origin and
16
+ * not a fragment.
17
+ *
18
+ * Without one, the tile is a `<button>` that calls the set's
19
+ * `onChoose`. A set may mix the two.
20
+ */
21
+ href?: string;
22
+ /**
23
+ * Leading content, above the name. A `Badge`, an app's own icon, a
24
+ * count.
25
+ *
26
+ * `aria-hidden` by construction: the name it sits above is inside
27
+ * the same tile, so an announced icon is the label read twice.
28
+ */
29
+ icon?: ReactNode;
30
+ isDisabled?: boolean;
31
+ /** Opens in a new tab, and says so to a screen reader. `href` only. */
32
+ isExternal?: boolean;
33
+ label: ReactNode;
34
+ /**
35
+ * Identity. The React key, and what `onChoose` is handed.
36
+ *
37
+ * Required even on a tile that navigates, so a set can mix the two
38
+ * without one half losing its key — the same reason `RadioItem`
39
+ * carries one.
40
+ */
41
+ value: string;
42
+ };
43
+ export type ActionTilesProps = {
44
+ className?: string;
45
+ items: readonly ActionTileItem[];
46
+ /** The set's accessible name. Required. */
47
+ label: string;
48
+ /**
49
+ * The narrowest a tile track may be, in CSS px.
50
+ *
51
+ * It is the grid's floor and not the tile's width: tracks below it
52
+ * are not created, and the ones that are share the row evenly.
53
+ */
54
+ minTileInlineSize?: number;
55
+ /** Fired by a tile that carries no `href`. */
56
+ onChoose?: (value: string) => void;
57
+ /** What `isExternal` announces. Not shown. */
58
+ newTabLabel?: string;
59
+ size?: ControlSize;
60
+ };
61
+ /**
62
+ * A set of ACTIONS drawn as tiles — a bordered card carrying a name
63
+ * and a line of help, in a grid that gains columns with its
64
+ * container.
65
+ *
66
+ * This is `RadioGroup`'s `itemShape="tile"` with the radio taken
67
+ * away. The
68
+ * [2026-08-25 record](../../../../docs/decisions/2026-08-25-a-choice-tile-is-a-radiogroup-shape-not-a-third-component.md)
69
+ * that made the choice tile a `RadioGroup` shape named this case
70
+ * under *"What this deliberately does not cover"* — mux-magic's "Pick
71
+ * a tool" tiles are `<a href>` and points-market's are `<Link>`, and
72
+ * *"a link is not a radio, and giving one `aria-checked` would be
73
+ * worse than the paint it replaced"*. So the box is shared through
74
+ * `tileStyles.ts` and nothing else is.
75
+ *
76
+ * ### Which of the two you want
77
+ *
78
+ * Ask what a press does.
79
+ *
80
+ * - It **records a value** the user will then submit, or that
81
+ * filters what is below it — `RadioGroup itemShape="tile"`. The
82
+ * set announces "3 of 6", the arrow keys move the choice, and one
83
+ * tile stays selected.
84
+ * - It **goes somewhere or starts something** — this. Nothing stays
85
+ * selected, because nothing was chosen: the page moved on. Tab
86
+ * reaches each tile, Enter and Space press it, and a `href` tile
87
+ * is a real anchor.
88
+ *
89
+ * A first step that opens the next step is the second kind, which is
90
+ * why QueuePilot's "Queue type" chooser is here and its Tonight
91
+ * activity filter is not.
92
+ *
93
+ * ### Why this is not a `Button` with a `className`
94
+ *
95
+ * A `Button` is sized by `h-(--control-height-md)` and carries **no
96
+ * block padding at all** — one line of text, by contract. An app that
97
+ * wants a wrapping two-line card reaches for `height: auto`, which
98
+ * deletes the height and leaves `padding: 0` down the block axis:
99
+ * a title flush against the top border and a description flush
100
+ * against the bottom one, with nothing to report it. That shipped in
101
+ * QueuePilot and is what this component exists to have made
102
+ * impossible.
103
+ *
104
+ * ### `role="group"`, and no roving tabindex
105
+ *
106
+ * These are ordinary buttons and anchors, so the platform already
107
+ * owns the keyboard: Tab reaches each one, Enter and Space press it,
108
+ * and a link opens in a new tab on ctrl-click. A radio group borrows
109
+ * one tab stop and moves the choice with the arrow keys because
110
+ * exactly one of its options is true at a time; nothing here is
111
+ * true, so imposing that model would only cost a keyboard user the
112
+ * ability to Tab to the second tile.
113
+ */
114
+ export declare const ActionTiles: ({ className, items, label, minTileInlineSize, newTabLabel, onChoose, size, }: ActionTilesProps) => ReactNode;
115
+ //# sourceMappingURL=ActionTiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActionTiles.d.ts","sourceRoot":"","sources":["../../src/ActionTiles/ActionTiles.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAiBrD,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;;;;;;;OASG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,uEAAuE;IACvE,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,KAAK,EAAE,SAAS,CAAA;IAChB;;;;;;OAMG;IACH,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,SAAS,cAAc,EAAE,CAAA;IAChC,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,WAAW,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,eAAO,MAAM,WAAW,GAAI,8EAQzB,gBAAgB,KAAG,SAwJrB,CAAA"}
@@ -0,0 +1,115 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { FOCUS_RING_CLASS } from "../intentStyles.js";
3
+ import { useRouterLink } from "../RouterLink/RouterLinkProvider.js";
4
+ import { getIsRoutedHref } from "../RouterLink/routerLink.js";
5
+ import { TILE_BOX_CLASS, TILE_COLUMNS_CLASS, TILE_GAP_CLASS, TILE_HINT_TEXT_CLASS, TILE_MIN_INLINE_SIZE_PROPERTY, TILE_PADDING_CLASS, TILE_TEXT_SIZE_CLASS, } from "../tileStyles.js";
6
+ import { toClassName } from "../toClassName.js";
7
+ import { VisuallyHidden } from "../VisuallyHidden/VisuallyHidden.js";
8
+ /**
9
+ * A set of ACTIONS drawn as tiles — a bordered card carrying a name
10
+ * and a line of help, in a grid that gains columns with its
11
+ * container.
12
+ *
13
+ * This is `RadioGroup`'s `itemShape="tile"` with the radio taken
14
+ * away. The
15
+ * [2026-08-25 record](../../../../docs/decisions/2026-08-25-a-choice-tile-is-a-radiogroup-shape-not-a-third-component.md)
16
+ * that made the choice tile a `RadioGroup` shape named this case
17
+ * under *"What this deliberately does not cover"* — mux-magic's "Pick
18
+ * a tool" tiles are `<a href>` and points-market's are `<Link>`, and
19
+ * *"a link is not a radio, and giving one `aria-checked` would be
20
+ * worse than the paint it replaced"*. So the box is shared through
21
+ * `tileStyles.ts` and nothing else is.
22
+ *
23
+ * ### Which of the two you want
24
+ *
25
+ * Ask what a press does.
26
+ *
27
+ * - It **records a value** the user will then submit, or that
28
+ * filters what is below it — `RadioGroup itemShape="tile"`. The
29
+ * set announces "3 of 6", the arrow keys move the choice, and one
30
+ * tile stays selected.
31
+ * - It **goes somewhere or starts something** — this. Nothing stays
32
+ * selected, because nothing was chosen: the page moved on. Tab
33
+ * reaches each tile, Enter and Space press it, and a `href` tile
34
+ * is a real anchor.
35
+ *
36
+ * A first step that opens the next step is the second kind, which is
37
+ * why QueuePilot's "Queue type" chooser is here and its Tonight
38
+ * activity filter is not.
39
+ *
40
+ * ### Why this is not a `Button` with a `className`
41
+ *
42
+ * A `Button` is sized by `h-(--control-height-md)` and carries **no
43
+ * block padding at all** — one line of text, by contract. An app that
44
+ * wants a wrapping two-line card reaches for `height: auto`, which
45
+ * deletes the height and leaves `padding: 0` down the block axis:
46
+ * a title flush against the top border and a description flush
47
+ * against the bottom one, with nothing to report it. That shipped in
48
+ * QueuePilot and is what this component exists to have made
49
+ * impossible.
50
+ *
51
+ * ### `role="group"`, and no roving tabindex
52
+ *
53
+ * These are ordinary buttons and anchors, so the platform already
54
+ * owns the keyboard: Tab reaches each one, Enter and Space press it,
55
+ * and a link opens in a new tab on ctrl-click. A radio group borrows
56
+ * one tab stop and moves the choice with the arrow keys because
57
+ * exactly one of its options is true at a time; nothing here is
58
+ * true, so imposing that model would only cost a keyboard user the
59
+ * ability to Tab to the second tile.
60
+ */
61
+ export const ActionTiles = ({ className, items, label, minTileInlineSize = 200, newTabLabel = "(opens in a new tab)", onChoose, size = "md", }) => {
62
+ const RouterLink = useRouterLink();
63
+ return (_jsx("div", { "aria-label": label, className: toClassName("grid", TILE_COLUMNS_CLASS, TILE_GAP_CLASS[size], className), role: "group", style: {
64
+ [TILE_MIN_INLINE_SIZE_PROPERTY]: `${minTileInlineSize}px`,
65
+ }, children: items.map(({ hint, href, icon, isDisabled = false, isExternal = false, label: tileLabel, value, }) => {
66
+ const tileClassName = toClassName(
67
+ // `flex`, not `inline-flex`: a grid item stretches to its
68
+ // track, and an inline box would sit at max-content
69
+ // inside it. `min-w-0` with `wrap-anywhere` below,
70
+ // because a grid item's automatic minimum is its
71
+ // min-content width — one unbroken token would otherwise
72
+ // set the track's floor and shove the grid out of its
73
+ // container.
74
+ "flex min-w-0 flex-col gap-0.5 text-start wrap-anywhere transition-colors duration-(--duration-fast) ease-standard", TILE_BOX_CLASS, TILE_PADDING_CLASS[size], TILE_TEXT_SIZE_CLASS[size],
75
+ // Disabled turns the whole tile down with `opacity-60`,
76
+ // the same family treatment as `Checkbox`, `Switch` and
77
+ // the radio tile, rather than fading the border to a
78
+ // token that disappeared on a pale theme.
79
+ isDisabled
80
+ ? "cursor-not-allowed opacity-60"
81
+ : "cursor-pointer hover:border-border-strong", FOCUS_RING_CLASS);
82
+ const content = (_jsxs(_Fragment, { children: [icon === undefined ? null : (_jsx("span", { "aria-hidden": true, className: "flex", children: icon })), _jsx("span", { className: "font-semibold text-content-primary", children: tileLabel }), hint === undefined ? null : (_jsx("span", { className: toClassName("font-normal text-content-muted", TILE_HINT_TEXT_CLASS[size]), children: hint })), isExternal && href !== undefined ? (_jsx(VisuallyHidden, { children: newTabLabel })) : null] }));
83
+ if (href !== undefined && !isDisabled) {
84
+ // An external destination or a fragment is never the
85
+ // router's — pushing `https://…` or `#credits` onto the
86
+ // history stack navigates the SPA to a route that does
87
+ // not exist. Same destination test as `ButtonLink`.
88
+ const LinkElement = isExternal || !getIsRoutedHref(href)
89
+ ? "a"
90
+ : RouterLink;
91
+ return (_jsx(LinkElement, { className: tileClassName, href: href,
92
+ // `noreferrer` alongside `noopener` on purpose:
93
+ // `noopener` closes the `window.opener` hole, and
94
+ // `noreferrer` is what keeps a private app's URL out
95
+ // of the destination's logs.
96
+ rel: isExternal
97
+ ? "noopener noreferrer"
98
+ : undefined, target: isExternal ? "_blank" : undefined, children: content }, value));
99
+ }
100
+ if (href !== undefined) {
101
+ // `isDisabled` drops `href` entirely rather than shipping
102
+ // a focusable anchor that silently ignores clicks — an
103
+ // anchor with no `href` is inert by the platform's own
104
+ // rules, and the explicit `role`/`aria-disabled` keeps it
105
+ // *announced* as a link that is currently unavailable
106
+ // rather than vanishing from the tree. `ButtonLink`'s
107
+ // rule, unchanged.
108
+ return (_jsx("a", { "aria-disabled": "true", className: tileClassName, role: "link", children: content }, value));
109
+ }
110
+ return (_jsx("button", { className: tileClassName, disabled: isDisabled, onClick: () => {
111
+ onChoose?.(value);
112
+ }, type: "button", children: content }, value));
113
+ }) }));
114
+ };
115
+ //# sourceMappingURL=ActionTiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActionTiles.js","sourceRoot":"","sources":["../../src/ActionTiles/ActionTiles.tsx"],"names":[],"mappings":";AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAsC,CAAA;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAC7D,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,6BAA6B,EAC7B,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAsC,CAAA;AA8DrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAC1B,SAAS,EACT,KAAK,EACL,KAAK,EACL,iBAAiB,GAAG,GAAG,EACvB,WAAW,GAAG,sBAAsB,EACpC,QAAQ,EACR,IAAI,GAAG,IAAI,GACM,EAAa,EAAE;IAChC,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAElC,OAAO,CAEL,4BACc,KAAK,EACjB,SAAS,EAAE,WAAW,CACpB,MAAM,EACN,kBAAkB,EAClB,cAAc,CAAC,IAAI,CAAC,EACpB,SAAS,CACV,EACD,IAAI,EAAC,OAAO,EACZ,KAAK,EACH;YACE,CAAC,6BAA6B,CAAC,EAAE,GAAG,iBAAiB,IAAI;SACzC,YAGnB,KAAK,CAAC,GAAG,CACR,CAAC,EACC,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,UAAU,GAAG,KAAK,EAClB,UAAU,GAAG,KAAK,EAClB,KAAK,EAAE,SAAS,EAChB,KAAK,GACN,EAAE,EAAE;YACH,MAAM,aAAa,GAAG,WAAW;YAC/B,0DAA0D;YAC1D,oDAAoD;YACpD,mDAAmD;YACnD,iDAAiD;YACjD,yDAAyD;YACzD,sDAAsD;YACtD,aAAa;YACb,mHAAmH,EACnH,cAAc,EACd,kBAAkB,CAAC,IAAI,CAAC,EACxB,oBAAoB,CAAC,IAAI,CAAC;YAC1B,wDAAwD;YACxD,wDAAwD;YACxD,qDAAqD;YACrD,0CAA0C;YAC1C,UAAU;gBACR,CAAC,CAAC,+BAA+B;gBACjC,CAAC,CAAC,2CAA2C,EAC/C,gBAAgB,CACjB,CAAA;YAED,MAAM,OAAO,GAAG,CACd,8BACG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAC3B,oCAAkB,SAAS,EAAC,MAAM,YAC/B,IAAI,GACA,CACR,EAED,eAAM,SAAS,EAAC,oCAAoC,YACjD,SAAS,GACL,EAEN,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAC3B,eACE,SAAS,EAAE,WAAW,CACpB,gCAAgC,EAChC,oBAAoB,CAAC,IAAI,CAAC,CAC3B,YAEA,IAAI,GACA,CACR,EAEA,UAAU,IAAI,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAClC,KAAC,cAAc,cACZ,WAAW,GACG,CAClB,CAAC,CAAC,CAAC,IAAI,IACP,CACJ,CAAA;YAED,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,UAAU,EAAE,CAAC;gBACtC,qDAAqD;gBACrD,wDAAwD;gBACxD,uDAAuD;gBACvD,oDAAoD;gBACpD,MAAM,WAAW,GACf,UAAU,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;oBAClC,CAAC,CAAC,GAAG;oBACL,CAAC,CAAC,UAAU,CAAA;gBAEhB,OAAO,CACL,KAAC,WAAW,IACV,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE,IAAI;oBAEV,gDAAgD;oBAChD,kDAAkD;oBAClD,qDAAqD;oBACrD,6BAA6B;oBAC7B,GAAG,EACD,UAAU;wBACR,CAAC,CAAC,qBAAqB;wBACvB,CAAC,CAAC,SAAS,EAEf,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,YAExC,OAAO,IAZH,KAAK,CAaE,CACf,CAAA;YACH,CAAC;YAED,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,0DAA0D;gBAC1D,uDAAuD;gBACvD,uDAAuD;gBACvD,0DAA0D;gBAC1D,sDAAsD;gBACtD,sDAAsD;gBACtD,mBAAmB;gBACnB,OAAO,CAEL,6BACgB,MAAM,EACpB,SAAS,EAAE,aAAa,EAExB,IAAI,EAAC,MAAM,YAEV,OAAO,IAHH,KAAK,CAIR,CACL,CAAA;YACH,CAAC;YAED,OAAO,CACL,iBACE,SAAS,EAAE,aAAa,EACxB,QAAQ,EAAE,UAAU,EAEpB,OAAO,EAAE,GAAG,EAAE;oBACZ,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAA;gBACnB,CAAC,EACD,IAAI,EAAC,QAAQ,YAEZ,OAAO,IANH,KAAK,CAOH,CACV,CAAA;QACH,CAAC,CACF,GACG,CACP,CAAA;AACH,CAAC,CAAA"}
@@ -97,6 +97,16 @@ export type RadioGroupProps = {
97
97
  * and `isReadOnly` are the ones already tested here. `SegmentedControl`
98
98
  * earns its own file by being a different control — one connected
99
99
  * strip, no radio affordance; a tile is this control with a border.
100
+ *
101
+ * ### A tile that ACTS is `ActionTiles`
102
+ *
103
+ * Same box, read from `tileStyles.ts`, and nothing else in common:
104
+ * no `radio` role, no roving tabindex, no selection to follow focus,
105
+ * no read-only. Ask what a press does. It records a value something
106
+ * below reads — this. It goes somewhere or starts something, and
107
+ * nothing stays selected — `ActionTiles`. Inverting every clause of
108
+ * the paragraph above is what earned that one its own file
109
+ * (`docs/decisions/2026-09-01-a-tile-that-acts-is-its-own-component-and-shares-only-the-box.md`).
100
110
  */
101
111
  export declare const RadioGroup: ({ className, itemShape, items, isReadOnly, label, minTileInlineSize, onChange, selectedValue, size, }: RadioGroupProps) => ReactNode;
102
112
  //# sourceMappingURL=RadioGroup.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RadioGroup.d.ts","sourceRoot":"","sources":["../../src/RadioGroup/RadioGroup.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAMrD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,CAAA;AAE3C,MAAM,MAAM,SAAS,GAAG;IACtB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,KAAK,EAAE,SAAS,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAA;IAC1B,KAAK,EAAE,SAAS,SAAS,EAAE,CAAA;IAC3B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IACjD,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,IAAI,CAAC,EAAE,WAAW,CAAA;CACnB,CAAA;AAiDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,UAAU,GAAI,uGAUxB,eAAe,KAAG,SA4JpB,CAAA"}
1
+ {"version":3,"file":"RadioGroup.d.ts","sourceRoot":"","sources":["../../src/RadioGroup/RadioGroup.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAWrD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,CAAA;AAE3C,MAAM,MAAM,SAAS,GAAG;IACtB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,KAAK,EAAE,SAAS,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAA;IAC1B,KAAK,EAAE,SAAS,SAAS,EAAE,CAAA;IAC3B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IACjD,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,IAAI,CAAC,EAAE,WAAW,CAAA;CACnB,CAAA;AAQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,UAAU,GAAI,uGAUxB,eAAe,KAAG,SA4JpB,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { selectTabIndex, useRovingFocus, useSinglePicker, } from "@charcuterie/logic";
3
3
  import { useCallback, useEffect, useRef } from "react";
4
+ import { TILE_COLUMNS_CLASS, TILE_GAP_CLASS, TILE_MIN_INLINE_SIZE_PROPERTY, } from "../tileStyles.js";
4
5
  import { toClassName } from "../toClassName.js";
5
6
  import { RadioGroupOption } from "./RadioGroupOption.js";
6
7
  const GAP_CLASS = {
@@ -8,44 +9,6 @@ const GAP_CLASS = {
8
9
  md: "gap-1.5",
9
10
  lg: "gap-2",
10
11
  };
11
- /**
12
- * Wider than the row gaps: rows are separated by their leading, and
13
- * tiles by nothing but the gap, so the same 6px that reads as a list
14
- * reads as a seam between two cards.
15
- */
16
- const TILE_GAP_CLASS = {
17
- sm: "gap-1.5",
18
- md: "gap-2",
19
- lg: "gap-3",
20
- };
21
- /**
22
- * `auto-fill`, and deliberately not `auto-fit`.
23
- *
24
- * `auto-fit` collapses the empty tracks and lets the ones that
25
- * remain share the whole row, so six tiles in a 2560px container
26
- * become six 420px slabs — the full-width-row shape in a new
27
- * costume. `auto-fill` keeps the empty tracks, so a tile stays a
28
- * tile and the grid simply has room to spare.
29
- *
30
- * `min(…, 100%)` is what stops the floor overflowing a container
31
- * narrower than one tile, which is the Narrow View and is otherwise
32
- * a horizontal scrollbar on a phone.
33
- *
34
- * The floor arrives as a custom property rather than an interpolated
35
- * class because Tailwind scans source *text* for complete class
36
- * strings: `` `grid-cols-[…${n}px…]` `` generates nothing, paints
37
- * nothing and reports nothing. One written-out literal reading
38
- * `var(--charcuterie-tile-min-inline-size)` covers every width an
39
- * app can ask for — the same reason `Card`'s accent edge goes
40
- * through one property.
41
- *
42
- * This is **not** `useAdaptiveColumns`, and the difference is the
43
- * question being asked. That hook buys a column with height, for an
44
- * unbounded gallery that will scroll; a radio group is a bounded set
45
- * of options inside a form section, where the only question is how
46
- * many fit across the box it was given.
47
- */
48
- const TILE_COLUMNS_CLASS = "grid-cols-[repeat(auto-fill,minmax(min(var(--charcuterie-tile-min-inline-size),100%),1fr))]";
49
12
  /**
50
13
  * One choice out of many, each on its own row with a label the size
51
14
  * of prose — the stacked sibling of `SegmentedControl`.
@@ -77,6 +40,16 @@ const TILE_COLUMNS_CLASS = "grid-cols-[repeat(auto-fill,minmax(min(var(--charcut
77
40
  * and `isReadOnly` are the ones already tested here. `SegmentedControl`
78
41
  * earns its own file by being a different control — one connected
79
42
  * strip, no radio affordance; a tile is this control with a border.
43
+ *
44
+ * ### A tile that ACTS is `ActionTiles`
45
+ *
46
+ * Same box, read from `tileStyles.ts`, and nothing else in common:
47
+ * no `radio` role, no roving tabindex, no selection to follow focus,
48
+ * no read-only. Ask what a press does. It records a value something
49
+ * below reads — this. It goes somewhere or starts something, and
50
+ * nothing stays selected — `ActionTiles`. Inverting every clause of
51
+ * the paragraph above is what earned that one its own file
52
+ * (`docs/decisions/2026-09-01-a-tile-that-acts-is-its-own-component-and-shares-only-the-box.md`).
80
53
  */
81
54
  export const RadioGroup = ({ className, itemShape = "row", items, isReadOnly = false, label, minTileInlineSize = 200, onChange, selectedValue, size = "md", }) => {
82
55
  const groupRef = useRef(null);
@@ -158,7 +131,7 @@ export const RadioGroup = ({ className, itemShape = "row", items, isReadOnly = f
158
131
  }
159
132
  }, ref: groupRef, style: isTile
160
133
  ? {
161
- "--charcuterie-tile-min-inline-size": `${minTileInlineSize}px`,
134
+ [TILE_MIN_INLINE_SIZE_PROPERTY]: `${minTileInlineSize}px`,
162
135
  }
163
136
  : undefined, role: "radiogroup", children: items.map((item) => (_jsx(RadioGroupOption, { isChecked: checkedValue === item.value, isReadOnly: isReadOnly, item: item, itemShape: itemShape, onChoose: chooseOption, registerFocus: focus.register, registerSelection: selection.register, size: size,
164
137
  // The roving-tabindex rule read from the core rather than
@@ -1 +1 @@
1
- {"version":3,"file":"RadioGroup.js","sourceRoot":"","sources":["../../src/RadioGroup/RadioGroup.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RadioGroup.js","sourceRoot":"","sources":["../../src/RadioGroup/RadioGroup.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"RadioGroupOption.d.ts","sourceRoot":"","sources":["../../src/RadioGroup/RadioGroupOption.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACf,MAAM,kBAAkB,CAAA;AAEzB,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,OAAO,CAAA;IAClB,UAAU,EAAE,OAAO,CAAA;IACnB,IAAI,EAAE,SAAS,CAAA;IACf,SAAS,EAAE,cAAc,CAAA;IACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,kEAAkE;IAClE,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,IAAI,CAAA;IAC5C,0DAA0D;IAC1D,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,IAAI,CAAA;IAChD,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,CACZ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,iBAAiB,GAAG,IAAI,KAC9B,IAAI,CAAA;CACV,CAAA;AAqDD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gBAAgB,GAAI,uHAW9B,qBAAqB,KAAG,SA0J1B,CAAA"}
1
+ {"version":3,"file":"RadioGroupOption.d.ts","sourceRoot":"","sources":["../../src/RadioGroup/RadioGroupOption.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAWtC,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACf,MAAM,kBAAkB,CAAA;AAEzB,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,OAAO,CAAA;IAClB,UAAU,EAAE,OAAO,CAAA;IACnB,IAAI,EAAE,SAAS,CAAA;IACf,SAAS,EAAE,cAAc,CAAA;IACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,kEAAkE;IAClE,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,IAAI,CAAA;IAC5C,0DAA0D;IAC1D,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,IAAI,CAAA;IAChD,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,CACZ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,iBAAiB,GAAG,IAAI,KAC9B,IAAI,CAAA;CACV,CAAA;AAiBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gBAAgB,GAAI,uHAW9B,qBAAqB,KAAG,SA0J1B,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect } from "react";
3
3
  import { FOCUS_RING_CLASS } from "../intentStyles.js";
4
+ import { TILE_BOX_CLASS, TILE_HINT_TEXT_CLASS, TILE_PADDING_CLASS, TILE_TEXT_SIZE_CLASS, } from "../tileStyles.js";
4
5
  import { toClassName } from "../toClassName.js";
5
6
  // Deliberately the `Switch`'s `THUMB_SIZE_CLASS`, value for value — a
6
7
  // radio's ring and a switch's knob are then the same circle at every
@@ -15,37 +16,6 @@ const DOT_SIZE_CLASS = {
15
16
  md: "size-2",
16
17
  lg: "size-2.5",
17
18
  };
18
- const TEXT_SIZE_CLASS = {
19
- sm: "text-sm",
20
- md: "text-md",
21
- lg: "text-lg",
22
- };
23
- /**
24
- * One step down from the option's own text, and never below `xs`:
25
- * a hint that keeps shrinking with the density axis is the 11px
26
- * caption the 2026-08-10 ramp rebuild exists to have removed.
27
- */
28
- const HINT_TEXT_CLASS = {
29
- sm: "text-xs",
30
- md: "text-xs",
31
- lg: "text-sm",
32
- };
33
- /**
34
- * A tile is a card, so its padding is a card's rather than a
35
- * control's — enough that the border reads as a box around content
36
- * and not as an outline on a line of text.
37
- */
38
- const TILE_PADDING_CLASS = {
39
- sm: "px-3 py-2.5",
40
- md: "px-3.5 py-3",
41
- lg: "px-4 py-3.5",
42
- };
43
- /**
44
- * The box, and only the box. Every state below it is a **border and
45
- * a surface**, never colour alone — the same reason `Stepper`
46
- * refuses to say "done" with a hue.
47
- */
48
- const TILE_BOX_CLASS = "rounded-lg border border-border-subtle bg-surface-raised";
49
19
  /**
50
20
  * Its own file for the same reason `SegmentedOption` is: **both
51
21
  * registrations are effects**, and an effect cannot run in a loop.
@@ -82,7 +52,7 @@ export const RadioGroupOption = ({ isChecked, isReadOnly, item, itemShape, onCho
82
52
  // centred against both sits beside neither.
83
53
  hint === undefined
84
54
  ? "items-center"
85
- : "items-start"), TEXT_SIZE_CLASS[size],
55
+ : "items-start"), TILE_TEXT_SIZE_CLASS[size],
86
56
  // Disabled turns the whole option down with `opacity-60`, the
87
57
  // same family treatment as `Checkbox` and `Switch`, rather than
88
58
  // fading the ring to a token that disappeared on a pale theme.
@@ -127,6 +97,6 @@ export const RadioGroupOption = ({ isChecked, isReadOnly, item, itemShape, onCho
127
97
  ? "bg-intent-neutral-solid"
128
98
  : "bg-intent-accent-solid", isChecked ? "scale-100" : "scale-0", DOT_SIZE_CLASS[size]) }) }), hint === undefined && !isTile ? (_jsx("span", { children: label })) : (_jsxs("span", { className: "flex min-w-0 flex-col gap-0.5 wrap-anywhere", children: [icon !== undefined && isTile ? (_jsx("span", { "aria-hidden": true, className: "flex", children: icon })) : null, _jsx("span", { className: isTile
129
99
  ? "font-semibold text-content-primary"
130
- : undefined, children: label }), hint === undefined ? null : (_jsx("span", { className: toClassName("font-normal text-content-muted", HINT_TEXT_CLASS[size]), children: hint }))] }))] }));
100
+ : undefined, children: label }), hint === undefined ? null : (_jsx("span", { className: toClassName("font-normal text-content-muted", TILE_HINT_TEXT_CLASS[size]), children: hint }))] }))] }));
131
101
  };
132
102
  //# sourceMappingURL=RadioGroupOption.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RadioGroupOption.js","sourceRoot":"","sources":["../../src/RadioGroup/RadioGroupOption.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RadioGroupOption.js","sourceRoot":"","sources":["../../src/RadioGroup/RadioGroupOption.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import type { ReactNode } from "react";
2
+ import type { TabsPanelProps } from "./Tabs.tsx";
3
+ /**
4
+ * The panel bar — every tab a `<button>`, every section a
5
+ * `role="tabpanel"` this component renders and hides. See `Tabs`
6
+ * for which of the two bars a screen wants.
7
+ *
8
+ * The composition is two hooks and one decision:
9
+ *
10
+ * ```ts
11
+ * const selection = useSinglePicker({ selectedValue: initialKey })
12
+ * const focus = useRovingFocus({ activeValue: initialKey })
13
+ *
14
+ * // `automatic` is this line, and `manual` is its absence.
15
+ * if (activation === "automatic") selection.select(focus.activeValue)
16
+ * ```
17
+ *
18
+ * ### Selection, not visibility — and the difference is not cosmetic
19
+ *
20
+ * M4 built this on `VisibilityGroup`, and the panels do end up
21
+ * one-at-a-time either way, because the two cores are the same
22
+ * shape. But the thing that **registers** here is the tab, not the
23
+ * panel, and what a tab bar is asking is *which one did you pick*.
24
+ * `SinglePicker` is the kind that answers that; the panel's
25
+ * `hidden` is derived from the answer.
26
+ *
27
+ * Reading it the other way round cost something concrete: it made
28
+ * `aria-selected` a report about a *panel's* visibility, so a
29
+ * consumer wanting a tab bar with no panels at all — a segmented
30
+ * filter, a view switcher that swaps a route — had to model its
31
+ * choice as a group of visibilities it did not have. `Alert`'s
32
+ * sibling `SegmentedControl` is exactly that consumer, and it now
33
+ * shares this component's core rather than hand-rolling a fourth
34
+ * one.
35
+ * [Decision](../../../../docs/decisions/2026-07-30-tab-selection-is-a-single-picker.md).
36
+ *
37
+ * ### What it does not use, and why that is the right answer
38
+ *
39
+ * The plan expected `createLinkedIds` here as well. It does not
40
+ * fit, and forcing it would have been the wrong call: that kind
41
+ * exists for a **dynamic** trigger↔target pair — a `Popover` whose
42
+ * panel mounts and unmounts, where the multiset is what stops
43
+ * `aria-controls` pointing at a node React has already removed. A
44
+ * tab bar's pairing is static and known at render, so the ids come
45
+ * from one `useUniqueId` and cannot get out of step at all.
46
+ *
47
+ * ### Focus is moved deliberately, and only then
48
+ *
49
+ * `RovingFocus` is state; something still has to call `.focus()`.
50
+ * That happens only while the tablist already contains the focused
51
+ * element — otherwise mounting a tab bar, or any parent re-render
52
+ * that moved `activeValue`, yanks the caret out of whatever the
53
+ * user was actually doing.
54
+ */
55
+ export declare const PanelTabs: ({ activation, activeKey, className, label, onChange, orientation, tabs, }: TabsPanelProps) => ReactNode;
56
+ //# sourceMappingURL=PanelTabs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PanelTabs.d.ts","sourceRoot":"","sources":["../../src/Tabs/PanelTabs.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAgBhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,eAAO,MAAM,SAAS,GAAI,2EAQvB,cAAc,KAAG,SA6KnB,CAAA"}