@godxjp/ui 31.23.0 → 31.24.1
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.
- package/agent/START-HERE.md +4 -4
- package/agent/components/AppShell.json +5 -0
- package/agent/components/PageContainer.json +5 -0
- package/agent/components/Sheet.json +5 -0
- package/agent/components/Sidebar.json +5 -0
- package/agent/components.json +20 -0
- package/agent/index.json +4 -4
- package/agent/llms.txt +5 -5
- package/agent/tokens.json +12 -0
- package/dist/components/feedback/sheet.d.ts +7 -1
- package/dist/components/feedback/sheet.js +2 -1
- package/dist/components/layout/app-shell.d.ts +1 -1
- package/dist/components/layout/app-shell.js +8 -4
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +12 -3
- package/dist/components/layout/sidebar.d.ts +1 -1
- package/dist/components/layout/sidebar.js +2 -0
- package/dist/contracts/measurement.json +1 -1
- package/dist/props/components/layout.prop.d.ts +19 -0
- package/dist/styles/layers.json +1 -1
- package/dist/styles/layout.css +4 -0
- package/dist/tokens/components/feedback.css +6 -0
- package/dist/tokens/components/shell.css +2 -0
- package/package.json +2 -2
package/agent/START-HERE.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
You are about to write code against a design system you did not author. This file is the whole
|
|
4
4
|
contract. Read it before you write JSX.
|
|
5
5
|
|
|
6
|
-
**This catalog describes `@godxjp/ui` 31.
|
|
6
|
+
**This catalog describes `@godxjp/ui` 31.24.1.** If the project you are editing has a different
|
|
7
7
|
version in its `package.json`, read the pinned catalog for THAT version instead
|
|
8
8
|
(`…/v<their-version>/agent/…`). A catalog newer than the installed package describes props that do
|
|
9
9
|
not exist yet; older, and it hides props that do. Neither failure announces itself.
|
|
@@ -56,10 +56,10 @@ Then ask it: `search_components`, `get_component`, `get_tokens`, `get_rule`, `li
|
|
|
56
56
|
its `importPath`, and its examples. Fetch only the handful you picked in step 1.
|
|
57
57
|
3. `rules.json` — 50 cardinal rules. The ones about raw HTML and hardcoded colour are not
|
|
58
58
|
style advice.
|
|
59
|
-
4. `tokens.json` —
|
|
59
|
+
4. `tokens.json` — 2131 design tokens, each tagged with its `tier`. **If you were handed a
|
|
60
60
|
brand, read the 211 `foundation` entries first** — `--primary`, `--background`,
|
|
61
61
|
`--radius`, `--font-size-base` are the handful everything else derives from. The
|
|
62
|
-
|
|
62
|
+
1816 `component` entries are per-part knobs; reach for one only when a role is
|
|
63
63
|
right everywhere except one component.
|
|
64
64
|
5. `anti-ai-tells.json` — 26 shapes that make generated UI look generated, each with the
|
|
65
65
|
fix. Read before you reach for a gradient hero or a wall of coloured chips.
|
|
@@ -145,7 +145,7 @@ has stopped following the brand.
|
|
|
145
145
|
|---|---|---|---|
|
|
146
146
|
| `foundation` | 211 | the seeds — `--primary`, `--background`, `--foreground`, `--radius`, `--font-size-base`, `--shadow-color`. Everything below is derived from these | **yes — this is the main road.** Handed a brand colour, this is where it goes: `:root { --primary: <H> <S>% <L>%; }` (HSL components, no `hsl()` wrapper) |
|
|
147
147
|
| `semantic` | 104 | named roles that follow the seeds — `--ring`, `--text-link`, `--primary-hover`, `--overlay-background` | only when the seed is right and ONE role must differ. That role then stops following a later brand change |
|
|
148
|
-
| `component` |
|
|
148
|
+
| `component` | 1816 | per-part knobs, `--{component}-{part}-{property}` | rarely. Most are declared `initial` with the real default at the call site — deliberate, so a scoped override re-resolves instead of freezing at `:root` |
|
|
149
149
|
|
|
150
150
|
A token whose `value` is `initial` is not empty and not broken: `initial` is the guaranteed-invalid
|
|
151
151
|
value, so the real default is computed where the element paints it. Set it and yours wins.
|
|
@@ -105,6 +105,11 @@
|
|
|
105
105
|
"name": "mobileNavLabel",
|
|
106
106
|
"type": "string"
|
|
107
107
|
},
|
|
108
|
+
{
|
|
109
|
+
"description": "Visible text beside the drawer trigger's glyph (e.g. 'Pages'); it becomes the trigger's accessible name instead of the localized 'Open navigation'. The drawer closes on a link, a Sidebar row or a menu item, or an explicit close (Esc, overlay, close button, SheetClose) — other buttons such as a tree's expand toggle leave it open (gh#1133).",
|
|
110
|
+
"name": "mobileNavTriggerLabel",
|
|
111
|
+
"type": "string"
|
|
112
|
+
},
|
|
108
113
|
{
|
|
109
114
|
"description": "Controlled open state of the mobile drawer. Omit for AppShell-owned state.",
|
|
110
115
|
"name": "mobileNavOpen",
|
|
@@ -125,6 +125,11 @@
|
|
|
125
125
|
"name": "headerLoading",
|
|
126
126
|
"type": "boolean"
|
|
127
127
|
},
|
|
128
|
+
{
|
|
129
|
+
"description": "Ref to the page's <h1>; passing it also makes the heading programmatically focusable (tabIndex -1, outside the tab order, no focus ring) so a router can focus the new page title after client-side navigation (gh#1135).",
|
|
130
|
+
"name": "titleRef",
|
|
131
|
+
"type": "React.Ref<HTMLHeadingElement>"
|
|
132
|
+
},
|
|
128
133
|
{
|
|
129
134
|
"description": "Link component used for breadcrumb / header links (e.g. an Inertia or React Router `Link`). Defaults to a native `<a>`.",
|
|
130
135
|
"name": "linkComponent",
|
|
@@ -25,6 +25,11 @@
|
|
|
25
25
|
"name": "width",
|
|
26
26
|
"type": "number | string"
|
|
27
27
|
},
|
|
28
|
+
{
|
|
29
|
+
"description": "On SheetContent (Radix name, same as DialogContent): fires on every close before focus returns to the trigger. Call event.preventDefault() and focus your own target (e.g. the new page's heading after a drawer navigation) to send focus there instead (gh#1134).",
|
|
30
|
+
"name": "onCloseAutoFocus",
|
|
31
|
+
"type": "(event: Event) => void"
|
|
32
|
+
},
|
|
28
33
|
{
|
|
29
34
|
"defaultValue": "\"side\"",
|
|
30
35
|
"description": "On SheetContent: the responsive drawer / detail-panel contract. \"side\" (default) always renders the physical `side` you named. \"auto\" renders the desktop side panel above --sheet-responsive-breakpoint-width (48rem/768px) and the mobile BOTTOM sheet at/below it, capped by --sheet-bottom-max-height (85dvh). \"bottom\" pins the bottom-sheet presentation.",
|
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
"name": "ariaLabel",
|
|
10
10
|
"type": "string"
|
|
11
11
|
},
|
|
12
|
+
{
|
|
13
|
+
"description": "Ref to the navigation's scroll container (`.sb-nav-scroll`, the overflow-y element) — persist and restore its scrollTop across navigations or remounts (gh#1136).",
|
|
14
|
+
"name": "scrollRef",
|
|
15
|
+
"type": "React.Ref<HTMLElement>"
|
|
16
|
+
},
|
|
12
17
|
{
|
|
13
18
|
"description": "The id of the currently active nav item. For group items, the parent is automatically highlighted when any descendant id matches.",
|
|
14
19
|
"name": "activeId",
|
package/agent/components.json
CHANGED
|
@@ -737,6 +737,11 @@
|
|
|
737
737
|
"name": "headerLoading",
|
|
738
738
|
"type": "boolean"
|
|
739
739
|
},
|
|
740
|
+
{
|
|
741
|
+
"description": "Ref to the page's <h1>; passing it also makes the heading programmatically focusable (tabIndex -1, outside the tab order, no focus ring) so a router can focus the new page title after client-side navigation (gh#1135).",
|
|
742
|
+
"name": "titleRef",
|
|
743
|
+
"type": "React.Ref<HTMLHeadingElement>"
|
|
744
|
+
},
|
|
740
745
|
{
|
|
741
746
|
"description": "Link component used for breadcrumb / header links (e.g. an Inertia or React Router `Link`). Defaults to a native `<a>`.",
|
|
742
747
|
"name": "linkComponent",
|
|
@@ -1191,6 +1196,11 @@
|
|
|
1191
1196
|
"name": "mobileNavLabel",
|
|
1192
1197
|
"type": "string"
|
|
1193
1198
|
},
|
|
1199
|
+
{
|
|
1200
|
+
"description": "Visible text beside the drawer trigger's glyph (e.g. 'Pages'); it becomes the trigger's accessible name instead of the localized 'Open navigation'. The drawer closes on a link, a Sidebar row or a menu item, or an explicit close (Esc, overlay, close button, SheetClose) — other buttons such as a tree's expand toggle leave it open (gh#1133).",
|
|
1201
|
+
"name": "mobileNavTriggerLabel",
|
|
1202
|
+
"type": "string"
|
|
1203
|
+
},
|
|
1194
1204
|
{
|
|
1195
1205
|
"description": "Controlled open state of the mobile drawer. Omit for AppShell-owned state.",
|
|
1196
1206
|
"name": "mobileNavOpen",
|
|
@@ -1501,6 +1511,11 @@
|
|
|
1501
1511
|
"name": "ariaLabel",
|
|
1502
1512
|
"type": "string"
|
|
1503
1513
|
},
|
|
1514
|
+
{
|
|
1515
|
+
"description": "Ref to the navigation's scroll container (`.sb-nav-scroll`, the overflow-y element) — persist and restore its scrollTop across navigations or remounts (gh#1136).",
|
|
1516
|
+
"name": "scrollRef",
|
|
1517
|
+
"type": "React.Ref<HTMLElement>"
|
|
1518
|
+
},
|
|
1504
1519
|
{
|
|
1505
1520
|
"description": "The id of the currently active nav item. For group items, the parent is automatically highlighted when any descendant id matches.",
|
|
1506
1521
|
"name": "activeId",
|
|
@@ -7801,6 +7816,11 @@
|
|
|
7801
7816
|
"name": "width",
|
|
7802
7817
|
"type": "number | string"
|
|
7803
7818
|
},
|
|
7819
|
+
{
|
|
7820
|
+
"description": "On SheetContent (Radix name, same as DialogContent): fires on every close before focus returns to the trigger. Call event.preventDefault() and focus your own target (e.g. the new page's heading after a drawer navigation) to send focus there instead (gh#1134).",
|
|
7821
|
+
"name": "onCloseAutoFocus",
|
|
7822
|
+
"type": "(event: Event) => void"
|
|
7823
|
+
},
|
|
7804
7824
|
{
|
|
7805
7825
|
"defaultValue": "\"side\"",
|
|
7806
7826
|
"description": "On SheetContent: the responsive drawer / detail-panel contract. \"side\" (default) always renders the physical `side` you named. \"auto\" renders the desktop side panel above --sheet-responsive-breakpoint-width (48rem/768px) and the mobile BOTTOM sheet at/below it, capped by --sheet-bottom-max-height (85dvh). \"bottom\" pins the bottom-sheet presentation.",
|
package/agent/index.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"components": 181,
|
|
5
5
|
"patterns": 21,
|
|
6
6
|
"rules": 50,
|
|
7
|
-
"tokens":
|
|
7
|
+
"tokens": 2131,
|
|
8
8
|
"vocabulary": 14
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
@@ -48,19 +48,19 @@
|
|
|
48
48
|
"note": "Pin to the tag that matches the @godxjp/ui version you installed. A catalog newer than your package describes props you do not have; older, and it hides props you do.",
|
|
49
49
|
"read": {
|
|
50
50
|
"live": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json",
|
|
51
|
-
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v31.
|
|
51
|
+
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v31.24.1/agent/index.json"
|
|
52
52
|
},
|
|
53
53
|
"source": "mcp/src/data — the same data @godxjp/ui-mcp serves — plus the foundation and semantic token tiers, read from src/tokens/*.css",
|
|
54
54
|
"start": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md",
|
|
55
55
|
"tokenTiers": {
|
|
56
56
|
"component": "per-part knobs, --{component}-{part}-{property}; usually leave these alone",
|
|
57
57
|
"counts": {
|
|
58
|
-
"component":
|
|
58
|
+
"component": 1816,
|
|
59
59
|
"foundation": 211,
|
|
60
60
|
"semantic": 104
|
|
61
61
|
},
|
|
62
62
|
"foundation": "the seeds a consumer is invited to set — --primary, --background, --radius",
|
|
63
63
|
"semantic": "named roles that follow the seeds — --ring, --text-link, --overlay-background"
|
|
64
64
|
},
|
|
65
|
-
"version": "31.
|
|
65
|
+
"version": "31.24.1"
|
|
66
66
|
}
|
package/agent/llms.txt
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @godxjp/ui
|
|
2
2
|
|
|
3
|
-
> A Japanese-enterprise React design system: 181 components,
|
|
4
|
-
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.
|
|
3
|
+
> A Japanese-enterprise React design system: 181 components, 2131 design tokens,
|
|
4
|
+
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.24.1.
|
|
5
5
|
|
|
6
6
|
If your client can run a process, do not read these files — run the MCP server instead
|
|
7
|
-
(`npx @godxjp/ui-mcp@31.
|
|
7
|
+
(`npx @godxjp/ui-mcp@31.24.1`). It is searchable and version-locked. These files exist for agents
|
|
8
8
|
that can only fetch URLs.
|
|
9
9
|
|
|
10
10
|
## Start
|
|
@@ -18,7 +18,7 @@ that can only fetch URLs.
|
|
|
18
18
|
- [components-index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json): 50 KB — all 181 components as name, group, tagline, plus `absorbed`: the names that do NOT exist and map to it (`Combobox` → `Select`).
|
|
19
19
|
- [components/<Name>.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components/Select.json): one file per component (1 KB–36 KB, median 6 KB). Read the index, then fetch only the ones you chose — this is the selective route, and the reason you do not need the blob.
|
|
20
20
|
- [components.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components.json): 1.2 MB — every entry in one file. Most URL fetchers truncate a response this size without saying so; prefer the per-component files.
|
|
21
|
-
- [tokens.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json): every design token with its value, the reason it exists, and its `tier` — 211 `foundation` seeds (`--primary`, `--background`, `--radius`: set these when you are handed a brand), 104 `semantic` roles,
|
|
21
|
+
- [tokens.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json): every design token with its value, the reason it exists, and its `tier` — 211 `foundation` seeds (`--primary`, `--background`, `--radius`: set these when you are handed a brand), 104 `semantic` roles, 1816 `component` knobs.
|
|
22
22
|
- [vocabulary.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/vocabulary.json): the controlled prop vocabulary — which prop name means what, across every component.
|
|
23
23
|
- [rules.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/rules.json): 50 cardinal rules.
|
|
24
24
|
- [anti-ai-tells.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/anti-ai-tells.json): 26 shapes that make generated UI look generated, each with its fix.
|
|
@@ -26,7 +26,7 @@ that can only fetch URLs.
|
|
|
26
26
|
## Pinning
|
|
27
27
|
|
|
28
28
|
Every URL above tracks `main`. To pin to the release a project actually installed, swap `main` for
|
|
29
|
-
the tag: `.../godx-jp/godxjp-ui/v31.
|
|
29
|
+
the tag: `.../godx-jp/godxjp-ui/v31.24.1/agent/...`. A catalog that does not match the installed
|
|
30
30
|
package describes props that are absent, or hides props that are present, and says nothing either way.
|
|
31
31
|
|
|
32
32
|
Pinned catalogs only exist for releases whose tag actually contains `agent/`. If `…/v<version>/agent/index.json` returns 404, that release predates this catalog: read `…/main/…` instead and compare `index.json` → `version` against the package you have, so you at least know which way it drifted.
|
package/agent/tokens.json
CHANGED
|
@@ -7229,6 +7229,12 @@
|
|
|
7229
7229
|
"tier": "component",
|
|
7230
7230
|
"value": "16px"
|
|
7231
7231
|
},
|
|
7232
|
+
{
|
|
7233
|
+
"description": "Rule #24 companion for the overlay ✕ (gh#1138): the 24px floor is the WCAG 2.5.8 AA minimum for a mouse; under a finger the target lifts to the 44px tap floor the control ladder already uses. Only the hit area grows (the `::after` above the glyph) — the 16px paint stays put.",
|
|
7234
|
+
"name": "--dialog-close-size",
|
|
7235
|
+
"tier": "component",
|
|
7236
|
+
"value": "var(--band-height-xl)"
|
|
7237
|
+
},
|
|
7232
7238
|
{
|
|
7233
7239
|
"description": "Lightweight row surfaces and hover actions; theme overrides remain scoped component knobs.",
|
|
7234
7240
|
"name": "--flex-surface-background",
|
|
@@ -11429,6 +11435,12 @@
|
|
|
11429
11435
|
"tier": "component",
|
|
11430
11436
|
"value": "var(--band-height-xl)"
|
|
11431
11437
|
},
|
|
11438
|
+
{
|
|
11439
|
+
"description": "And for the Sidebar's own rows (gh#1138): measured 32px under a finger while the Tree rows and SearchInput beside them had already grown to 44 with the control ladder.",
|
|
11440
|
+
"name": "--sidebar-nav-item-height",
|
|
11441
|
+
"tier": "component",
|
|
11442
|
+
"value": "var(--band-height-xl)"
|
|
11443
|
+
},
|
|
11432
11444
|
{
|
|
11433
11445
|
"description": "MobileShell (gh#354 §6) — the handheld app shell: a status band, an app bar, ONE scroll region, a sticky action bar and a bottom tab bar. Two facts here cannot be reached by composition, which is why they belong to the shell and not to the page: 1. The shell is the only scroll container. The root is exactly one viewport tall (`--mobile-shell-block-size`), so the document itself never scrolls and the chrome bands never leave the screen — the reason a composed `Card` + `overflow-y-auto` stack drifts on a real phone, where the URL bar collapses under the page. 2. Every band absorbs the device safe-area insets, so a notch never covers the app bar and the home indicator never covers the primary verb. The safe-area knobs are `env()` values and are therefore ZERO on every surface with no insets (desktop, jsdom, the docs frames) — the geometry below is unchanged there. The INLINE knob takes `max()` of BOTH physical insets on purpose: `env(safe-area-inset-left)` is physical, so binding it to the inline START would be wrong under `dir=\"rtl\"`. A symmetric inset is correct in both writing directions and costs at most a few px on the non-notch side in landscape. A service retunes the page gutter, the three band heights and the block padding from its theme; nothing here is reachable only through a consumer selector.",
|
|
11434
11446
|
"name": "--mobile-shell-block-size",
|
|
@@ -76,8 +76,14 @@ export interface SheetContentProps extends React.ComponentPropsWithRef<"section"
|
|
|
76
76
|
* physical `side` the consumer named, at every viewport.
|
|
77
77
|
*/
|
|
78
78
|
responsive?: SheetResponsiveProp;
|
|
79
|
+
/**
|
|
80
|
+
* Radix's name, same contract as `DialogContent`: fires on every close, before focus returns to
|
|
81
|
+
* the trigger. Call `event.preventDefault()` and focus your own target — the page heading after a
|
|
82
|
+
* navigation, say — to send focus there instead.
|
|
83
|
+
*/
|
|
84
|
+
onCloseAutoFocus?: (event: Event) => void;
|
|
79
85
|
}
|
|
80
|
-
export declare function SheetContent({ side, className, children, showCloseButton, overlayClassName, forceMount: _forceMount, width, responsive, style, ref, ...props }: SheetContentProps): React.JSX.Element | null;
|
|
86
|
+
export declare function SheetContent({ side, className, children, showCloseButton, overlayClassName, forceMount: _forceMount, width, responsive, onCloseAutoFocus, style, ref, ...props }: SheetContentProps): React.JSX.Element | null;
|
|
81
87
|
export declare namespace SheetContent {
|
|
82
88
|
var displayName: string;
|
|
83
89
|
}
|
|
@@ -118,6 +118,7 @@ function SheetContent({
|
|
|
118
118
|
forceMount: _forceMount,
|
|
119
119
|
width,
|
|
120
120
|
responsive = "side",
|
|
121
|
+
onCloseAutoFocus,
|
|
121
122
|
style,
|
|
122
123
|
ref,
|
|
123
124
|
...props
|
|
@@ -136,7 +137,7 @@ function SheetContent({
|
|
|
136
137
|
const dataState = state.isOpen ? "open" : "closed";
|
|
137
138
|
const modal = React.useContext(SheetModalContext);
|
|
138
139
|
const { contentRef, isMounted } = useNonModalPortal(state.isOpen, !modal);
|
|
139
|
-
useOverlayCloseFocus(state.isOpen,
|
|
140
|
+
useOverlayCloseFocus(state.isOpen, onCloseAutoFocus, modal ? void 0 : contentRef);
|
|
140
141
|
const overlayPortalContainer = useOverlayPortalContainer();
|
|
141
142
|
const dialog = /* @__PURE__ */ jsx(
|
|
142
143
|
RacDialog,
|
|
@@ -3,4 +3,4 @@ import type { AppShellProp } from "../../props/components/layout.prop.js";
|
|
|
3
3
|
export type { AppShellProp, AppShellProp as AppShellProps, } from "../../props/components/layout.prop.js";
|
|
4
4
|
/** Same rail boundary as shell-layout.css; SSR starts in docked mode. */
|
|
5
5
|
export declare function useAppShellNavigationMode(): "drawer" | "docked";
|
|
6
|
-
export declare function AppShell({ sidebar, topbar, topbarLeft, topbarRight, logo, logoCompact, logoCompactBelow, breadcrumb, footer, children, sidebarCollapsed, responsiveNavigation, topbarSpan, navRail, navRailPosition, navRailEnd, navRailLabel, mobileNav, mobileNavLabel, mobileNavOpen, onMobileNavOpenChange, }: AppShellProp): React.JSX.Element;
|
|
6
|
+
export declare function AppShell({ sidebar, topbar, topbarLeft, topbarRight, logo, logoCompact, logoCompactBelow, breadcrumb, footer, children, sidebarCollapsed, responsiveNavigation, topbarSpan, navRail, navRailPosition, navRailEnd, navRailLabel, mobileNav, mobileNavLabel, mobileNavTriggerLabel, mobileNavOpen, onMobileNavOpenChange, }: AppShellProp): React.JSX.Element;
|
|
@@ -31,6 +31,7 @@ function AppShell({
|
|
|
31
31
|
navRailLabel,
|
|
32
32
|
mobileNav,
|
|
33
33
|
mobileNavLabel,
|
|
34
|
+
mobileNavTriggerLabel,
|
|
34
35
|
mobileNavOpen,
|
|
35
36
|
onMobileNavOpenChange
|
|
36
37
|
}) {
|
|
@@ -52,7 +53,7 @@ function AppShell({
|
|
|
52
53
|
const setDrawerOpen = onMobileNavOpenChange ?? setUncontrolledOpen;
|
|
53
54
|
const handleDrawerClick = (event) => {
|
|
54
55
|
const target = event.target;
|
|
55
|
-
const hit = target.closest("a[href],
|
|
56
|
+
const hit = target.closest("a[href], .sb-nav-item, [role='menuitem']");
|
|
56
57
|
if (!hit) {
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
@@ -103,14 +104,17 @@ function AppShell({
|
|
|
103
104
|
);
|
|
104
105
|
const bar = !hasTopbarContent && !hasDrawer ? null : /* @__PURE__ */ jsxs("header", { className: "app-topbar ui-scale-fixed", "aria-label": t("layout.appShell.headerLabel"), children: [
|
|
105
106
|
hasDrawer && /* @__PURE__ */ jsxs(Sheet, { open: drawerOpen, onOpenChange: setDrawerOpen, children: [
|
|
106
|
-
/* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */
|
|
107
|
+
/* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
107
108
|
TopbarItem,
|
|
108
109
|
{
|
|
109
110
|
type: "button",
|
|
110
111
|
className: "app-mobile-nav-trigger",
|
|
111
|
-
"aria-label": t("layout.appShell.openNav"),
|
|
112
|
+
"aria-label": mobileNavTriggerLabel === void 0 ? t("layout.appShell.openNav") : void 0,
|
|
112
113
|
"aria-haspopup": "dialog",
|
|
113
|
-
children:
|
|
114
|
+
children: [
|
|
115
|
+
/* @__PURE__ */ jsx(Menu, { className: "size-[var(--app-shell-mobile-nav-icon-size)]", "aria-hidden": "true" }),
|
|
116
|
+
mobileNavTriggerLabel
|
|
117
|
+
]
|
|
114
118
|
}
|
|
115
119
|
) }),
|
|
116
120
|
/* @__PURE__ */ jsxs(
|
|
@@ -2,7 +2,7 @@ import type { PageContainerProp, PageInsetProp } from "../../props/components/la
|
|
|
2
2
|
export type { PageContainerProp, PageContainerProp as PageContainerProps, PageContainerExtraProp, } from "../../props/components/layout.prop.js";
|
|
3
3
|
export type { BreadcrumbItemProp, BreadcrumbItemProp as BreadcrumbItem, } from "../../props/vocabulary/navigation.prop.js";
|
|
4
4
|
export declare function PageContainerInset({ className, children, ...props }: PageInsetProp): import("react").JSX.Element;
|
|
5
|
-
declare function PageContainerRoot({ title, subtitle, status, extra, toolbar, footer, toolbarPad, footerPad, breadcrumb, breadcrumbLabel, breadcrumbAriaLabel, linkComponent: LinkComponent, headerLoading, density, variant, preset, headerLayout, headerScale, measure, stickyFooter, footerReveal, fill, children, className, }: PageContainerProp): import("react").JSX.Element;
|
|
5
|
+
declare function PageContainerRoot({ title, subtitle, status, extra, toolbar, footer, toolbarPad, footerPad, breadcrumb, breadcrumbLabel, breadcrumbAriaLabel, linkComponent: LinkComponent, headerLoading, titleRef, density, variant, preset, headerLayout, headerScale, measure, stickyFooter, footerReveal, fill, children, className, }: PageContainerProp): import("react").JSX.Element;
|
|
6
6
|
export declare const PageContainer: typeof PageContainerRoot & {
|
|
7
7
|
Inset: typeof PageContainerInset;
|
|
8
8
|
};
|
|
@@ -45,6 +45,7 @@ function PageContainerRoot({
|
|
|
45
45
|
breadcrumbAriaLabel,
|
|
46
46
|
linkComponent: LinkComponent = "a",
|
|
47
47
|
headerLoading = false,
|
|
48
|
+
titleRef,
|
|
48
49
|
density,
|
|
49
50
|
variant = "default",
|
|
50
51
|
preset = "default",
|
|
@@ -61,6 +62,7 @@ function PageContainerRoot({
|
|
|
61
62
|
const { headerRef, revealed } = useFooterReveal(reveal);
|
|
62
63
|
const { t } = useTranslation();
|
|
63
64
|
const { start: extraStart, end: extraEnd } = resolvePageExtra(extra);
|
|
65
|
+
const titleFocus = titleRef === void 0 ? void 0 : { ref: titleRef, tabIndex: -1 };
|
|
64
66
|
return /* @__PURE__ */ jsxs(
|
|
65
67
|
"div",
|
|
66
68
|
{
|
|
@@ -134,10 +136,17 @@ function PageContainerRoot({
|
|
|
134
136
|
),
|
|
135
137
|
/* @__PURE__ */ jsxs("div", { className: "ui-page-header-row", children: [
|
|
136
138
|
/* @__PURE__ */ jsxs("div", { className: "ui-page-header-heading", children: [
|
|
137
|
-
headerLoading ? /* @__PURE__ */ jsx(
|
|
138
|
-
|
|
139
|
+
headerLoading ? /* @__PURE__ */ jsx(
|
|
140
|
+
"h1",
|
|
141
|
+
{
|
|
142
|
+
...titleFocus,
|
|
143
|
+
className: "ui-page-title ui-skeleton-block ui-page-title-placeholder",
|
|
144
|
+
children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: t("layout.pageHeader.loading") })
|
|
145
|
+
}
|
|
146
|
+
) : status != null ? /* @__PURE__ */ jsxs("div", { className: "ui-page-header-title-row", children: [
|
|
147
|
+
/* @__PURE__ */ jsx("h1", { ...titleFocus, className: "ui-page-title", children: title }),
|
|
139
148
|
/* @__PURE__ */ jsx("div", { className: "ui-page-header-status", children: status })
|
|
140
|
-
] }) : /* @__PURE__ */ jsx("h1", { className: "ui-page-title", children: title }),
|
|
149
|
+
] }) : /* @__PURE__ */ jsx("h1", { ...titleFocus, className: "ui-page-title", children: title }),
|
|
141
150
|
headerLoading ? (
|
|
142
151
|
// Decorative only — the pending state is already announced once by the heading above,
|
|
143
152
|
// so a second live placeholder here would double-announce it.
|
|
@@ -47,4 +47,4 @@ export { createSidebarLink } from "./sidebar-link.js";
|
|
|
47
47
|
* Sidebar — data-driven vertical nav rail. Use {@link createSidebarLink} to adapt a router `Link`,
|
|
48
48
|
* or `SidebarItem asChild` when composing rows by hand.
|
|
49
49
|
*/
|
|
50
|
-
export declare function Sidebar({ ariaLabel: ariaLabelCamel, activeId, onSelect, sections, product, onProductClick, brand, collapsed, children, linkComponent, renderItem, footer, "aria-label": ariaLabel, }: SidebarProp): React.JSX.Element;
|
|
50
|
+
export declare function Sidebar({ ariaLabel: ariaLabelCamel, scrollRef, activeId, onSelect, sections, product, onProductClick, brand, collapsed, children, linkComponent, renderItem, footer, "aria-label": ariaLabel, }: SidebarProp): React.JSX.Element;
|
|
@@ -294,6 +294,7 @@ function CollapsedRow({ item, activeId, onSelect, linkComponent: LinkComponent }
|
|
|
294
294
|
import { createSidebarLink } from "./sidebar-link.js";
|
|
295
295
|
function Sidebar({
|
|
296
296
|
ariaLabel: ariaLabelCamel,
|
|
297
|
+
scrollRef,
|
|
297
298
|
activeId,
|
|
298
299
|
onSelect,
|
|
299
300
|
sections,
|
|
@@ -354,6 +355,7 @@ function Sidebar({
|
|
|
354
355
|
/* @__PURE__ */ jsx(
|
|
355
356
|
"nav",
|
|
356
357
|
{
|
|
358
|
+
ref: scrollRef,
|
|
357
359
|
className: "sb-nav-scroll",
|
|
358
360
|
"aria-label": ariaLabel ?? ariaLabelCamel ?? t("layout.sidebar.ariaLabel"),
|
|
359
361
|
children: children ?? resolvedSections.map((section, sectionIndex) => /* @__PURE__ */ jsx(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "AUTO-GENERATED by scripts/gen-measurement-contract.mjs — do not edit. Read this instead of guessing: docs/MEASUREMENT-CONTRACT.md.",
|
|
3
|
-
"version": "31.
|
|
3
|
+
"version": "31.24.1",
|
|
4
4
|
"targetSize": {
|
|
5
5
|
"standard": "WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px",
|
|
6
6
|
"min": 24,
|
|
@@ -58,6 +58,12 @@ export type PageContainerProp = {
|
|
|
58
58
|
* violation) so the page's heading outline never disappears mid-load.
|
|
59
59
|
*/
|
|
60
60
|
headerLoading?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Ref to the page's `<h1>`. Passing it also makes the heading programmatically focusable
|
|
63
|
+
* (`tabIndex={-1}`, outside the tab order, no focus ring), so a router can move focus to the new
|
|
64
|
+
* page's title after a client-side navigation — the pattern screen readers need to announce it.
|
|
65
|
+
*/
|
|
66
|
+
titleRef?: React.Ref<HTMLHeadingElement>;
|
|
61
67
|
/** @see PageContainerExtraProp */
|
|
62
68
|
extra?: PageContainerExtraProp;
|
|
63
69
|
/**
|
|
@@ -577,6 +583,14 @@ export type AppShellProp = {
|
|
|
577
583
|
mobileNav?: ReactNode;
|
|
578
584
|
/** Accessible title for the mobile navigation drawer. Defaults to the localized "Menu". */
|
|
579
585
|
mobileNavLabel?: string;
|
|
586
|
+
/**
|
|
587
|
+
* Visible text beside the drawer trigger's glyph (e.g. "Pages"). It becomes the trigger's
|
|
588
|
+
* accessible name, replacing the localized "Open navigation" — omit it for the glyph-only
|
|
589
|
+
* trigger. The drawer closes when a link, a Sidebar row or a menu item inside it is activated,
|
|
590
|
+
* or on an explicit close (Esc, overlay, close button, `SheetClose`); other controls — a tree's
|
|
591
|
+
* expand toggle — leave it open.
|
|
592
|
+
*/
|
|
593
|
+
mobileNavTriggerLabel?: string;
|
|
580
594
|
/** Controlled open state of the mobile drawer. Omit for AppShell-owned (uncontrolled) state. */
|
|
581
595
|
mobileNavOpen?: boolean;
|
|
582
596
|
/** Change handler for the mobile drawer open state (pairs with `mobileNavOpen`). */
|
|
@@ -1371,6 +1385,11 @@ export type AppLauncherProp = {
|
|
|
1371
1385
|
export type SidebarProp = {
|
|
1372
1386
|
/** Accessible navigation landmark name; make it unique when multiple sidebars share a document. */
|
|
1373
1387
|
ariaLabel?: string;
|
|
1388
|
+
/**
|
|
1389
|
+
* Ref to the navigation's scroll container (the element with `overflow-y: auto`), to persist
|
|
1390
|
+
* and restore its `scrollTop` across navigations or remounts.
|
|
1391
|
+
*/
|
|
1392
|
+
scrollRef?: React.Ref<HTMLElement>;
|
|
1374
1393
|
activeId: string;
|
|
1375
1394
|
onSelect?: (id: string) => void;
|
|
1376
1395
|
sections?: SidebarSectionProp[];
|
package/dist/styles/layers.json
CHANGED
package/dist/styles/layout.css
CHANGED