@godxjp/ui 18.3.0 → 18.5.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.
- package/README.md +18 -3
- package/dist/app/theme-axes.d.ts +11 -3
- package/dist/app/theme-axes.js +2 -1
- package/dist/components/charts/chart-frame.d.ts +17 -3
- package/dist/components/charts/chart-frame.js +7 -1
- package/dist/components/charts/chart-summary.d.ts +21 -0
- package/dist/components/charts/chart-summary.js +32 -5
- package/dist/components/charts/compact-bar-trend.d.ts +29 -0
- package/dist/components/charts/compact-bar-trend.js +74 -0
- package/dist/components/charts/index.d.ts +3 -0
- package/dist/components/charts/index.js +2 -0
- package/dist/components/data-display/badge.d.ts +8 -0
- package/dist/components/data-display/badge.js +7 -1
- package/dist/components/data-display/data-table.d.ts +16 -1
- package/dist/components/data-display/data-table.js +56 -0
- package/dist/components/data-display/index.d.ts +3 -1
- package/dist/components/data-display/index.js +10 -1
- package/dist/components/data-display/list-row.d.ts +22 -4
- package/dist/components/data-display/list-row.js +21 -3
- package/dist/components/data-display/service-launcher-card.d.ts +40 -0
- package/dist/components/data-display/service-launcher-card.js +97 -0
- package/dist/components/data-entry/command-palette.d.ts +37 -0
- package/dist/components/data-entry/command-palette.js +125 -0
- package/dist/components/data-entry/index.d.ts +2 -0
- package/dist/components/data-entry/index.js +2 -0
- package/dist/components/feedback/dialog.d.ts +2 -0
- package/dist/components/feedback/dialog.js +42 -33
- package/dist/components/feedback/index.d.ts +4 -1
- package/dist/components/feedback/index.js +6 -2
- package/dist/components/feedback/sheet.d.ts +26 -4
- package/dist/components/feedback/sheet.js +54 -7
- package/dist/components/feedback/two-factor-setup.d.ts +31 -0
- package/dist/components/feedback/two-factor-setup.js +97 -0
- package/dist/components/general/index.d.ts +1 -1
- package/dist/components/general/logo.d.ts +42 -8
- package/dist/components/general/logo.js +67 -14
- package/dist/components/layout/app-shell.js +22 -6
- package/dist/components/layout/auth-divider.d.ts +7 -0
- package/dist/components/layout/auth-divider.js +21 -0
- package/dist/components/layout/auth-footer.d.ts +5 -0
- package/dist/components/layout/auth-footer.js +24 -0
- package/dist/components/layout/auth-identity.d.ts +5 -0
- package/dist/components/layout/auth-identity.js +17 -0
- package/dist/components/layout/auth-shell.d.ts +8 -1
- package/dist/components/layout/auth-shell.js +25 -6
- package/dist/components/layout/auth-stack.d.ts +4 -0
- package/dist/components/layout/auth-stack.js +8 -0
- package/dist/components/layout/centered-shell.d.ts +5 -2
- package/dist/components/layout/centered-shell.js +2 -1
- package/dist/components/layout/index.d.ts +18 -3
- package/dist/components/layout/index.js +17 -2
- package/dist/components/layout/legal-document-shell.d.ts +34 -0
- package/dist/components/layout/legal-document-shell.js +186 -0
- package/dist/components/layout/master-detail.d.ts +24 -0
- package/dist/components/layout/master-detail.js +48 -0
- package/dist/components/layout/org-switcher.d.ts +9 -0
- package/dist/components/layout/org-switcher.js +218 -0
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +3 -2
- package/dist/components/layout/sidebar-link.d.ts +43 -0
- package/dist/components/layout/sidebar-link.js +13 -0
- package/dist/components/layout/sidebar.d.ts +42 -5
- package/dist/components/layout/sidebar.js +170 -85
- package/dist/components/navigation/app-setting-picker.js +17 -6
- package/dist/components/navigation/filter-bar.d.ts +12 -3
- package/dist/components/navigation/filter-bar.js +8 -2
- package/dist/components/navigation/index.d.ts +2 -2
- package/dist/components/navigation/index.js +3 -1
- package/dist/components/navigation/tabs-scroll.d.ts +70 -0
- package/dist/components/navigation/tabs-scroll.js +76 -0
- package/dist/components/navigation/tabs.js +35 -20
- package/dist/email/brand-mark.d.ts +92 -0
- package/dist/email/brand-mark.js +83 -0
- package/dist/email/color.d.ts +52 -0
- package/dist/email/color.js +37 -0
- package/dist/email/geometry.d.ts +112 -0
- package/dist/email/geometry.js +89 -0
- package/dist/email/index.d.ts +78 -0
- package/dist/email/index.js +76 -0
- package/dist/email/inline-style.d.ts +25 -0
- package/dist/email/inline-style.js +21 -0
- package/dist/email/tokens.generated.d.ts +147 -0
- package/dist/email/tokens.generated.js +142 -0
- package/dist/i18n/messages/en.json +21 -2
- package/dist/i18n/messages/ja.json +21 -2
- package/dist/i18n/messages/vi.json +21 -2
- package/dist/inertia/index.d.ts +50 -0
- package/dist/inertia/index.js +5 -0
- package/dist/props/components/app.prop.d.ts +11 -1
- package/dist/props/components/charts.prop.d.ts +40 -1
- package/dist/props/components/data-display.prop.d.ts +13 -1
- package/dist/props/components/feedback.prop.d.ts +10 -0
- package/dist/props/components/index.d.ts +2 -2
- package/dist/props/components/layout.prop.d.ts +374 -11
- package/dist/props/components/layout.prop.js +1 -0
- package/dist/props/components/navigation.prop.d.ts +19 -1
- package/dist/props/registry.d.ts +291 -7
- package/dist/props/registry.js +341 -7
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/props/vocabulary/interaction.prop.d.ts +1 -1
- package/dist/props/vocabulary/layout.prop.d.ts +18 -0
- package/dist/styles/base.css +9 -3
- package/dist/styles/card-layout.css +162 -8
- package/dist/styles/chart-layout.css +97 -0
- package/dist/styles/control.css +48 -2
- package/dist/styles/data-display-layout.css +52 -6
- package/dist/styles/dialog-layout.css +105 -4
- package/dist/styles/fonts.css +29 -20
- package/dist/styles/index.css +11 -3
- package/dist/styles/layout.css +368 -2
- package/dist/styles/logo-layout.css +62 -0
- package/dist/styles/navigation-layout.css +43 -0
- package/dist/styles/shell-layout.css +505 -62
- package/dist/theme/dxs.canonical.css +76 -0
- package/dist/tokens/axes.css +39 -0
- package/dist/tokens/base.css +5 -0
- package/dist/tokens/components/card.css +52 -5
- package/dist/tokens/components/chart.css +47 -0
- package/dist/tokens/components/control.css +16 -0
- package/dist/tokens/components/email.css +66 -0
- package/dist/tokens/components/feedback.css +17 -0
- package/dist/tokens/components/legal-document.css +67 -0
- package/dist/tokens/components/list-row.css +23 -2
- package/dist/tokens/components/logo.css +32 -0
- package/dist/tokens/components/navigation.css +13 -0
- package/dist/tokens/components/sheet.css +19 -0
- package/dist/tokens/components/shell.css +149 -1
- package/dist/tokens/components/sidebar.css +33 -0
- package/dist/tokens/foundation.css +5 -2
- package/dist/tokens/semantic/layout.css +44 -2
- package/package.json +17 -6
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
/** Layout component prop types — @see docs/COMPONENTS.md#layout */
|
|
2
2
|
import type * as React from "react";
|
|
3
3
|
import type { ComponentType, ReactNode, SVGProps } from "react";
|
|
4
|
-
import type { BreadcrumbProp, TitleProp, SubtitleProp, ExtraProp, FooterProp, PageDensityProp, PageContainerVariantProp, CenteredShellWidthProp, GapProp, ClassNameProp, ChildrenProp } from "../vocabulary/index.js";
|
|
4
|
+
import type { BreadcrumbProp, TitleProp, SubtitleProp, ExtraProp, FooterProp, PageDensityProp, PageContainerVariantProp, CenteredShellWidthProp, CenteredShellAlignProp, AuthShellPresetProp, BreakpointProp, GapProp, ClassNameProp, ChildrenProp, IdProp } from "../vocabulary/index.js";
|
|
5
|
+
/**
|
|
6
|
+
* Arrangement of the page header's title band and its `extra` slot below the 640px step.
|
|
7
|
+
* `stack` (default) is the historical arrangement — `extra` drops onto its own full-width line
|
|
8
|
+
* under the subtitle. `responsive-inline` keeps `extra` beside the title band at the
|
|
9
|
+
* `--page-header-extra-measure` measure, letting the title/subtitle wrap into what is left.
|
|
10
|
+
*/
|
|
11
|
+
export type PageContainerHeaderLayoutProp = "stack" | "responsive-inline";
|
|
5
12
|
/** @see PageContainer */
|
|
6
13
|
export type PageContainerProp = {
|
|
7
14
|
title: TitleProp;
|
|
@@ -21,6 +28,14 @@ export type PageContainerProp = {
|
|
|
21
28
|
linkComponent?: React.ElementType;
|
|
22
29
|
density?: PageDensityProp;
|
|
23
30
|
variant?: PageContainerVariantProp;
|
|
31
|
+
/**
|
|
32
|
+
* How the title band and `extra` share the header row below the 640px step. Defaults to
|
|
33
|
+
* `stack` — the historical arrangement, where `extra` wraps onto its own full-width line under
|
|
34
|
+
* the subtitle. Use `responsive-inline` to keep ONE compact control (a search field, a single
|
|
35
|
+
* primary action) beside the title at 390px, at the token-owned
|
|
36
|
+
* `--page-header-extra-measure`. At >=640px both arrangements are identical.
|
|
37
|
+
*/
|
|
38
|
+
headerLayout?: PageContainerHeaderLayoutProp;
|
|
24
39
|
/** Pin footer to viewport bottom on scroll — pairs well with `variant="narrow"`. */
|
|
25
40
|
stickyFooter?: boolean;
|
|
26
41
|
/**
|
|
@@ -59,6 +74,52 @@ export type ResponsiveGridColumnsProp = number | {
|
|
|
59
74
|
md?: number;
|
|
60
75
|
lg?: number;
|
|
61
76
|
};
|
|
77
|
+
export type MasterDetailRailWidthProp = "compact" | "standard";
|
|
78
|
+
export type MasterDetailRailProp = "master" | "detail";
|
|
79
|
+
/**
|
|
80
|
+
* Bounded viewport preset for the master collection. `auto` (default) never bounds it — the
|
|
81
|
+
* region grows with its content, exactly as before. `compact` / `standard` cap its block size
|
|
82
|
+
* with the `--master-detail-master-viewport-*` tokens and scroll the collection inside the
|
|
83
|
+
* region, so a long list cannot push the detail below the fold once the layout stacks.
|
|
84
|
+
*/
|
|
85
|
+
export type MasterDetailMasterViewportProp = "auto" | "compact" | "standard";
|
|
86
|
+
/** @see MasterDetail */
|
|
87
|
+
export type MasterDetailProp = {
|
|
88
|
+
/** Selectable collection; always first in DOM order, so the stacked order stays list-then-detail. */
|
|
89
|
+
master: ReactNode;
|
|
90
|
+
/** Detail surface for the current selection. */
|
|
91
|
+
children: ChildrenProp;
|
|
92
|
+
/**
|
|
93
|
+
* Which region is the fixed-width rail; the other one is fluid. Defaults to `detail` — the
|
|
94
|
+
* canonical fluid-list + fixed-detail-rail composition. Use `master` for a leading
|
|
95
|
+
* category/navigator rail beside a fluid detail surface.
|
|
96
|
+
*/
|
|
97
|
+
rail?: MasterDetailRailProp;
|
|
98
|
+
/** Rail track width: `compact` = 300px; `standard` = 320px. */
|
|
99
|
+
railWidth?: MasterDetailRailWidthProp;
|
|
100
|
+
/**
|
|
101
|
+
* Bound the master collection to a scrollable viewport instead of letting it grow with its
|
|
102
|
+
* content. `auto` (default) keeps the unbounded behaviour. `compact` (20rem) / `standard`
|
|
103
|
+
* (28rem) read the `--master-detail-master-viewport-*` tokens, scroll the collection INSIDE the
|
|
104
|
+
* region, and make it a keyboard-reachable scroll container. Pair with `masterLabel` so the
|
|
105
|
+
* scroll region is announced.
|
|
106
|
+
*/
|
|
107
|
+
masterViewport?: MasterDetailMasterViewportProp;
|
|
108
|
+
/**
|
|
109
|
+
* Stack the two regions below this breakpoint (`false` never stacks). Omit to inherit the
|
|
110
|
+
* themeable `--master-detail-collapse-below` token (default 40rem / the `sm` step).
|
|
111
|
+
*/
|
|
112
|
+
collapseBelow?: BreakpointProp | false;
|
|
113
|
+
/** Accessible name for the master region. */
|
|
114
|
+
masterLabel?: string;
|
|
115
|
+
/** Accessible name for the detail region. */
|
|
116
|
+
detailLabel?: string;
|
|
117
|
+
/**
|
|
118
|
+
* Id of the detail region, so the selection controls inside `master` can point at it with
|
|
119
|
+
* `aria-controls` and the app can move focus to it after a selection.
|
|
120
|
+
*/
|
|
121
|
+
detailId?: IdProp;
|
|
122
|
+
};
|
|
62
123
|
/** @see PageContainer.Inset — full-bleed inset region inside the page padding. */
|
|
63
124
|
export type PageInsetProp = React.HTMLAttributes<HTMLDivElement> & {
|
|
64
125
|
children?: ChildrenProp;
|
|
@@ -76,7 +137,7 @@ export type AppShellProp = {
|
|
|
76
137
|
footer?: ReactNode;
|
|
77
138
|
sidebarCollapsed?: boolean;
|
|
78
139
|
/**
|
|
79
|
-
* Navigation shown in the mobile drawer
|
|
140
|
+
* Navigation shown in the mobile drawer at the DXS 900px breakpoint, where the docked sidebar is
|
|
80
141
|
* hidden. AppShell OWNS the drawer: it renders a hamburger trigger in the topbar and a focus-
|
|
81
142
|
* trapped Sheet (Esc + overlay close, focus returns to the trigger) — hiding the sidebar without
|
|
82
143
|
* a reachable alternative is invalid (gh#165). Defaults to `sidebar`, so the same nav is
|
|
@@ -106,6 +167,78 @@ export type AuthShellProp = {
|
|
|
106
167
|
brand?: ReactNode;
|
|
107
168
|
/** Footer slot pinned to the bottom (legal links, locale switch, support). */
|
|
108
169
|
footer?: ReactNode;
|
|
170
|
+
/**
|
|
171
|
+
* Visual contract for the auth surface. `"canonical"` applies the shared DXS compact geometry
|
|
172
|
+
* (36px controls, 22.5rem card measure, and responsive page insets) through component tokens.
|
|
173
|
+
* Default `"default"` preserves the existing comfortable shell.
|
|
174
|
+
*/
|
|
175
|
+
variant?: "default" | "canonical";
|
|
176
|
+
/**
|
|
177
|
+
* Named flow MEASURE — the page geometry contract for one canonical hosted-identity flow: the
|
|
178
|
+
* auth card's max-width plus the desktop and mobile page gutters, all owned by component tokens
|
|
179
|
+
* (`--auth-shell-{device,context,recovery}-*`). Selecting a preset replaces every consumer-side
|
|
180
|
+
* `--auth-shell-card-max-width` override.
|
|
181
|
+
*
|
|
182
|
+
* - `"default"` (default) — the shell's own measure; nothing changes.
|
|
183
|
+
* - `"device-authorization"` — 380px card measure with a 5px inline page gutter at a 390px
|
|
184
|
+
* viewport (canonical device-grant artboard).
|
|
185
|
+
* - `"context-selection"` — 25rem card measure on desktop/tablet, edge-to-edge on mobile, and a
|
|
186
|
+
* tokenized rhythm between the intro, the card and the trailing "remember" row.
|
|
187
|
+
* - `"account-recovery"` — 27rem/432px panel measure with a 15px inline page gutter at 390px
|
|
188
|
+
* (panel x=15, width=360). One measure for BOTH canonical SCR-008 panels: password recovery
|
|
189
|
+
* (request · sent · new-password · expired) and the sign-in MFA challenge (OTP · recovery-code
|
|
190
|
+
* · passkey-failure), whose title and description sit INSIDE the bordered surface.
|
|
191
|
+
*
|
|
192
|
+
* Orthogonal to `variant`: presets are applied AFTER it, so `variant="canonical"` keeps owning
|
|
193
|
+
* control density and heading size while the preset re-measures the page.
|
|
194
|
+
*/
|
|
195
|
+
preset?: AuthShellPresetProp;
|
|
196
|
+
/**
|
|
197
|
+
* Vertical density scoped to auth-card descendants. The canonical variant defaults to
|
|
198
|
+
* `"compact"`; the default variant defaults to `"comfortable"`.
|
|
199
|
+
*/
|
|
200
|
+
density?: "comfortable" | "compact";
|
|
201
|
+
className?: ClassNameProp;
|
|
202
|
+
};
|
|
203
|
+
/** @see AuthDivider */
|
|
204
|
+
export type AuthDividerProp = {
|
|
205
|
+
/** Short localized conjunction rendered between the two separator rules (for example, "or"). */
|
|
206
|
+
label: string;
|
|
207
|
+
className?: ClassNameProp;
|
|
208
|
+
};
|
|
209
|
+
/**
|
|
210
|
+
* @see AuthFooter — the canonical hosted-identity legal line (host · Terms · Privacy · locale).
|
|
211
|
+
* AuthFooter owns ONLY the geometry: the mono type ramp, the wrap behaviour and the `·`
|
|
212
|
+
* separators between the slots that are actually present (tokens `--auth-footer-*`). Every slot
|
|
213
|
+
* is consumer-owned content — real localized links and a real locale control — so the library
|
|
214
|
+
* never invents navigation. Drop it into `AuthShell`'s `footer` slot (which supplies the
|
|
215
|
+
* `contentinfo` landmark); it renders a plain `div`, so it can also sit inside an existing footer.
|
|
216
|
+
*/
|
|
217
|
+
export type AuthFooterProp = {
|
|
218
|
+
/** Product / host identity — the operator of the auth surface (e.g. "GoDX ID"). */
|
|
219
|
+
product: ReactNode;
|
|
220
|
+
/** Terms-of-service link or localized text. */
|
|
221
|
+
terms: ReactNode;
|
|
222
|
+
/** Privacy-policy link or localized text. */
|
|
223
|
+
privacy: ReactNode;
|
|
224
|
+
/** Optional consumer-owned locale control (e.g. `<AppSettingPicker kind="locale" compact />`). */
|
|
225
|
+
locale?: ReactNode;
|
|
226
|
+
className?: ClassNameProp;
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* @see AuthIdentity — the canonical hosted-identity heading block: the brand-green GoDX mark
|
|
230
|
+
* (`Logo mark="godx"`, independent of `--primary`), the `h1` auth heading, and an optional
|
|
231
|
+
* requesting-client line for delegated flows (device grant, OAuth consent). Centred, token-spaced
|
|
232
|
+
* (`--auth-identity-gap` / `--auth-requester-*`) — a consumer never re-centres or re-spaces it.
|
|
233
|
+
*/
|
|
234
|
+
export type AuthIdentityProp = {
|
|
235
|
+
/** Primary auth heading, rendered as the page `h1`. */
|
|
236
|
+
title: ReactNode;
|
|
237
|
+
/**
|
|
238
|
+
* Optional real requesting-client context ("Attendance is requesting sign in"). Pass it ONLY
|
|
239
|
+
* when the client identity is authoritative — never a placeholder.
|
|
240
|
+
*/
|
|
241
|
+
requester?: ReactNode;
|
|
109
242
|
className?: ClassNameProp;
|
|
110
243
|
};
|
|
111
244
|
/**
|
|
@@ -134,6 +267,15 @@ export type CenteredShellProp = {
|
|
|
134
267
|
* wider than AuthShell's 24rem auth card. A service retunes each tier via `--centered-shell-width-*`.
|
|
135
268
|
*/
|
|
136
269
|
width?: CenteredShellWidthProp;
|
|
270
|
+
/**
|
|
271
|
+
* Block alignment of the centred column inside the `100dvh` shell. `"start"` (default) keeps the
|
|
272
|
+
* top-aligned flowing/scrolling page shape. `"center"` centres the column in the viewport — the
|
|
273
|
+
* SYSTEM-level standalone surface (a 500/503 error page, a maintenance notice) whose full-page
|
|
274
|
+
* geometry must stay package-owned instead of a consumer re-implementing `min-h-dvh` + flex
|
|
275
|
+
* centring. Overflowing content still scrolls from the top (auto block offsets collapse to 0), so
|
|
276
|
+
* a long localized message is never clipped.
|
|
277
|
+
*/
|
|
278
|
+
align?: CenteredShellAlignProp;
|
|
137
279
|
className?: ClassNameProp;
|
|
138
280
|
};
|
|
139
281
|
/** @see Sidebar */
|
|
@@ -146,14 +288,24 @@ export type SidebarProductProp = {
|
|
|
146
288
|
export type SidebarItemProp = {
|
|
147
289
|
id: string;
|
|
148
290
|
label: string;
|
|
291
|
+
/**
|
|
292
|
+
* Leading 16px glyph — REQUIRED: the collapsed rail is icon-only and the expanded rail aligns
|
|
293
|
+
* every label to the icon column. Untyped/API-driven data that omits it no longer crashes the
|
|
294
|
+
* shell (the row renders an empty `.sb-icon` slot, keeping the 32px row / 10px gap), but the rail
|
|
295
|
+
* reads as a hole. Its colour is themeable separately from the label via
|
|
296
|
+
* `--sidebar-nav-icon-foreground` (see {@link SidebarProp}).
|
|
297
|
+
*/
|
|
149
298
|
icon: ComponentType<SVGProps<SVGSVGElement>>;
|
|
150
299
|
badge?: ReactNode;
|
|
151
300
|
disabled?: boolean;
|
|
152
301
|
/**
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
302
|
+
* Destination of the row. It is the SOLE interactive element (no nested `<button>`), so
|
|
303
|
+
* right-click / open-in-new-tab / middle-click all work. Omit for SPA rows that only report
|
|
304
|
+
* selection via `onSelect(id)`.
|
|
305
|
+
*
|
|
306
|
+
* With `Sidebar.linkComponent` this same `href` is what the framework router `<Link>` receives —
|
|
307
|
+
* the LIBRARY still composes the row (icon · label · badge · active · collapsed), so a router
|
|
308
|
+
* link never has to reconstruct row markup (gh#213).
|
|
157
309
|
*/
|
|
158
310
|
href?: string;
|
|
159
311
|
/** Nested rows — renders a collapsible submenu group (the parent reads active when any child is). */
|
|
@@ -161,11 +313,121 @@ export type SidebarItemProp = {
|
|
|
161
313
|
};
|
|
162
314
|
/** @see Sidebar */
|
|
163
315
|
export type SidebarItemData = SidebarItemProp;
|
|
316
|
+
/**
|
|
317
|
+
* Props the Sidebar hands to `Sidebar.linkComponent` for one nav row (gh#213).
|
|
318
|
+
*
|
|
319
|
+
* Every field is ANCHOR-SAFE — a router `<Link>` may spread the whole object onto its `<a>` without
|
|
320
|
+
* emitting an unknown-DOM-attribute warning. `children` is the LIBRARY-COMPOSED row content (the
|
|
321
|
+
* `.sb-icon` slot, the `.sb-label`, the `.sb-badge`); render it as-is and never rebuild it, which is
|
|
322
|
+
* what makes icons/badges survive a consumer link (the reported production regression).
|
|
323
|
+
*/
|
|
324
|
+
export type SidebarLinkProp = {
|
|
325
|
+
/** `SidebarItemProp.href`. Absent for a disabled row — render an inert `<a>` with no navigation. */
|
|
326
|
+
href?: string;
|
|
327
|
+
/** Library-composed row content: icon slot + label + badge (icon only on the collapsed rail). */
|
|
328
|
+
children: ReactNode;
|
|
329
|
+
/** Canonical row class (`sb-nav-item`, plus `sb-nav-item--sub` for a submenu child). */
|
|
330
|
+
className: string;
|
|
331
|
+
/** Present only on the active row — drives `--sidebar-item-active-*`. */
|
|
332
|
+
"data-active"?: "true";
|
|
333
|
+
/** WAI-ARIA current-page semantics for the active row. */
|
|
334
|
+
"aria-current"?: "page";
|
|
335
|
+
/** Set when the item (or its row) is disabled; the row must not navigate. */
|
|
336
|
+
"aria-disabled"?: true;
|
|
337
|
+
/** Accessible name for the icon-only collapsed rail, where the visible label is hidden. */
|
|
338
|
+
"aria-label"?: string;
|
|
339
|
+
/** `"menuitem"` inside the collapsed rail's portaled flyout menu; absent for ordinary rows. */
|
|
340
|
+
role?: "menuitem";
|
|
341
|
+
/** Reports selection to `Sidebar.onSelect` after the router link runs its own handler. */
|
|
342
|
+
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
|
343
|
+
};
|
|
344
|
+
/**
|
|
345
|
+
* A framework router link component driven by {@link SidebarLinkProp} — Inertia's `<Link href>`,
|
|
346
|
+
* a React Router / TanStack link wrapped by `createSidebarLink(Link, "to")`, or any component that
|
|
347
|
+
* renders a single `<a>`. It must forward its `ref` to that anchor so the collapsed rail's Tooltip
|
|
348
|
+
* can anchor to it.
|
|
349
|
+
*/
|
|
350
|
+
export type SidebarLinkComponentProp = ComponentType<SidebarLinkProp>;
|
|
351
|
+
/**
|
|
352
|
+
* Row state supplied to the DEPRECATED `Sidebar.renderItem`.
|
|
353
|
+
*
|
|
354
|
+
* @deprecated Prefer `Sidebar.linkComponent` (or `SidebarItem asChild`), where the library composes
|
|
355
|
+
* the row and the consumer supplies only the element. `renderItem` leaves row CONTENT to the
|
|
356
|
+
* consumer, which is how a `<Link>{item.label}</Link>` silently dropped every icon and badge
|
|
357
|
+
* (gh#213). Spreading `rowProps` — including its `children` — now yields the canonical row.
|
|
358
|
+
*/
|
|
359
|
+
export type SidebarRenderItemProp = {
|
|
360
|
+
className: string;
|
|
361
|
+
"data-active"?: "true";
|
|
362
|
+
"aria-current"?: "page";
|
|
363
|
+
"aria-disabled"?: true;
|
|
364
|
+
/**
|
|
365
|
+
* Library-composed row content (icon slot · label · badge). Spread `rowProps` onto your element,
|
|
366
|
+
* or render `rowProps.children` explicitly, to keep the canonical row while adding an affix.
|
|
367
|
+
*/
|
|
368
|
+
children?: ReactNode;
|
|
369
|
+
};
|
|
164
370
|
/** @see Sidebar */
|
|
165
371
|
export type SidebarSectionProp = {
|
|
166
372
|
label?: string;
|
|
167
373
|
items: SidebarItemProp[];
|
|
168
374
|
};
|
|
375
|
+
/** One selectable organization in the public {@link OrgSwitcher} contract. */
|
|
376
|
+
export type OrgSwitcherOrganization = {
|
|
377
|
+
id: string;
|
|
378
|
+
name: string;
|
|
379
|
+
/** Secondary organization context, for example the member's role or tenant identifier. */
|
|
380
|
+
meta?: ReactNode;
|
|
381
|
+
/** Optional owned mark/avatar. When omitted, OrgSwitcher renders the first name character. */
|
|
382
|
+
avatar?: ReactNode;
|
|
383
|
+
/**
|
|
384
|
+
* Status/plan affordance rendered end-aligned in the expanded trigger and in the menu row
|
|
385
|
+
* (e.g. `<Badge tone="warning">Trial</Badge>`). Hidden in the collapsed rail, which only has room
|
|
386
|
+
* for the mark. Pair a non-textual badge with {@link OrgSwitcherOrganization.badgeLabel}.
|
|
387
|
+
*/
|
|
388
|
+
badge?: ReactNode;
|
|
389
|
+
/**
|
|
390
|
+
* Localized screen-reader text for `badge`. Required whenever the badge carries meaning the
|
|
391
|
+
* accessible name would otherwise lose (WCAG 1.1.1 / 1.4.1): the trigger's `aria-label` owns its
|
|
392
|
+
* accessible name, so the badge is announced through `aria-describedby` instead. When omitted, a
|
|
393
|
+
* textual badge is still announced inside the menu row but NOT on the trigger.
|
|
394
|
+
*/
|
|
395
|
+
badgeLabel?: string;
|
|
396
|
+
disabled?: boolean;
|
|
397
|
+
};
|
|
398
|
+
/** Localized copy owned by the consuming product, never hard-coded by the component. */
|
|
399
|
+
export type OrgSwitcherLabels = {
|
|
400
|
+
trigger: (organizationName: string) => string;
|
|
401
|
+
title: string;
|
|
402
|
+
search: string;
|
|
403
|
+
empty: string;
|
|
404
|
+
loading: string;
|
|
405
|
+
retry?: string;
|
|
406
|
+
};
|
|
407
|
+
/** @see OrgSwitcher */
|
|
408
|
+
export type OrgSwitcherProp = {
|
|
409
|
+
organizations: readonly OrgSwitcherOrganization[];
|
|
410
|
+
value?: string;
|
|
411
|
+
onValueChange?: (value: string) => void;
|
|
412
|
+
collapsed?: boolean;
|
|
413
|
+
disabled?: boolean;
|
|
414
|
+
loading?: boolean;
|
|
415
|
+
/** Error content replaces the list while preserving the trigger and retry affordance. */
|
|
416
|
+
error?: ReactNode;
|
|
417
|
+
onRetry?: () => void;
|
|
418
|
+
labels: OrgSwitcherLabels;
|
|
419
|
+
/**
|
|
420
|
+
* `"auto"` (default) uses the desktop popover above `--sheet-responsive-breakpoint-width` and a
|
|
421
|
+
* focus-trapped bottom Sheet at/below it — the SAME token that drives `SheetContent
|
|
422
|
+
* responsive="auto"`, resolved through the shared `useSheetResponsiveMode()` hook, so a service
|
|
423
|
+
* moves the drawer line once for every overlay instead of per component.
|
|
424
|
+
* Explicit modes are useful for deterministic embedded surfaces and component tests.
|
|
425
|
+
*/
|
|
426
|
+
responsive?: "auto" | "popover" | "sheet";
|
|
427
|
+
open?: boolean;
|
|
428
|
+
onOpenChange?: (open: boolean) => void;
|
|
429
|
+
className?: ClassNameProp;
|
|
430
|
+
};
|
|
169
431
|
/** @see Sidebar */
|
|
170
432
|
export type SidebarProp = {
|
|
171
433
|
/** Accessible navigation landmark name; make it unique when multiple sidebars share a document. */
|
|
@@ -179,12 +441,39 @@ export type SidebarProp = {
|
|
|
179
441
|
collapsed?: boolean;
|
|
180
442
|
children?: ChildrenProp;
|
|
181
443
|
/**
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
444
|
+
* THE framework-router contract (gh#213). Supply only the LINK ELEMENT TYPE; the Sidebar still
|
|
445
|
+
* composes the row — icon slot, label, badge, `data-active`/`aria-current`, the icon-only
|
|
446
|
+
* collapsed rail and its tooltip name — and passes it as {@link SidebarLinkProp} `children`.
|
|
447
|
+
* Used for every row that carries an `href`: top-level leaves, submenu children, collapsed-rail
|
|
448
|
+
* leaves and collapsed flyout entries. A group TRIGGER stays a `<button>` (it owns
|
|
449
|
+
* `aria-expanded` disclosure semantics per WAI-ARIA APG); its children take the link.
|
|
450
|
+
*
|
|
451
|
+
* Rows without an `href` keep the `<button>` + `onSelect(id)` shape — a router link with no
|
|
452
|
+
* destination is not a link.
|
|
453
|
+
*
|
|
454
|
+
* @example
|
|
455
|
+
* ```tsx
|
|
456
|
+
* // Inertia — its <Link href> already matches SidebarLinkProp.
|
|
457
|
+
* import { Link } from "@inertiajs/react";
|
|
458
|
+
* <Sidebar linkComponent={inertiaSidebarLink(Link)} sections={sections} activeId={activeId} />
|
|
459
|
+
*
|
|
460
|
+
* // React Router / TanStack — remap `href` to `to`.
|
|
461
|
+
* import { Link } from "react-router-dom";
|
|
462
|
+
* <Sidebar linkComponent={createSidebarLink(Link, "to")} sections={sections} activeId={activeId} />
|
|
463
|
+
* ```
|
|
186
464
|
*/
|
|
187
|
-
|
|
465
|
+
linkComponent?: SidebarLinkComponentProp;
|
|
466
|
+
/**
|
|
467
|
+
* @deprecated Use {@link SidebarProp.linkComponent} (or `SidebarItem asChild`) instead — there the
|
|
468
|
+
* LIBRARY composes the row and you supply only the element, so icons/labels/badges cannot be lost.
|
|
469
|
+
*
|
|
470
|
+
* Legacy escape hatch: return a SINGLE interactive element and the Sidebar merges the row styling
|
|
471
|
+
* + active state onto it via Slot. Because row CONTENT stayed consumer-authored, a
|
|
472
|
+
* `<Link>{item.label}</Link>` silently dropped every icon and badge (the gh#213 production
|
|
473
|
+
* regression). `rowProps` now also carries the composed `children`, so spreading it restores the
|
|
474
|
+
* canonical row.
|
|
475
|
+
*/
|
|
476
|
+
renderItem?: (item: SidebarItemData, rowProps: SidebarRenderItemProp) => ReactNode;
|
|
188
477
|
footer?: ReactNode;
|
|
189
478
|
/**
|
|
190
479
|
* Override the nav landmark's accessible name. Defaults to a localized "Main navigation".
|
|
@@ -211,3 +500,77 @@ export type TopbarProp = Omit<React.HTMLAttributes<HTMLDivElement>, "children">
|
|
|
211
500
|
/** Escape hatch — render fully custom bar content instead of the three slots. */
|
|
212
501
|
children?: ReactNode;
|
|
213
502
|
};
|
|
503
|
+
/**
|
|
504
|
+
* @see LegalDocumentShell — one entry of the table of contents + the matching document section.
|
|
505
|
+
* `id` is the REAL anchor target (`href="#{id}"`, `<section id>`), so it must be unique on the page
|
|
506
|
+
* and URL-safe: it is what a deep link, a hash jump and `aria-current` all key off.
|
|
507
|
+
*/
|
|
508
|
+
export type LegalDocumentSectionProp = {
|
|
509
|
+
/** URL-safe anchor id — the `<section id>` AND the contents `href="#…"` target. */
|
|
510
|
+
id: string;
|
|
511
|
+
/** Section heading text — rendered as an `<h2>` AND reused as the contents-list label. */
|
|
512
|
+
title: string;
|
|
513
|
+
/** Section body. Consumer-owned legal copy: paragraphs, lists, tables, nested `<h3>`s. */
|
|
514
|
+
content: ReactNode;
|
|
515
|
+
};
|
|
516
|
+
/**
|
|
517
|
+
* @see LegalDocumentShell — the long-form legal/policy document surface (terms of service, privacy
|
|
518
|
+
* policy, DPA, cookie policy, SLA, EULA) with a table of contents.
|
|
519
|
+
*
|
|
520
|
+
* It owns the parts an app must NOT re-implement: the readable measure + top-aligned document
|
|
521
|
+
* geometry, the sticky contents rail (single-column compact block below 56rem), scroll-spy
|
|
522
|
+
* active-section tracking, hash deep-linking with a token-driven scroll offset, focus handoff to
|
|
523
|
+
* the target `<section>`, and `prefers-reduced-motion`-aware smooth scrolling. All legal TEXT stays
|
|
524
|
+
* owned by the consumer — the shell only receives it through `sections` and the slots.
|
|
525
|
+
*
|
|
526
|
+
* Semantics: `<article>` labelled by the document title · a NAMED `<nav>` for the contents · REAL
|
|
527
|
+
* `<a href="#…">` anchors carrying `aria-current="location"` · one `<section>` per entry, labelled
|
|
528
|
+
* by its `<h2>`.
|
|
529
|
+
*/
|
|
530
|
+
export type LegalDocumentShellProp = {
|
|
531
|
+
/** Document title — the `<h1>` that names the `<article>` (e.g. "Terms of Service"). */
|
|
532
|
+
title: TitleProp;
|
|
533
|
+
/**
|
|
534
|
+
* Document version identifier (e.g. `"2.4"`). Rendered as a localized "Version {version}" line —
|
|
535
|
+
* pass the bare identifier, never a pre-localized sentence.
|
|
536
|
+
*/
|
|
537
|
+
version?: string;
|
|
538
|
+
/**
|
|
539
|
+
* Effective date as an **ISO 8601** calendar date (`yyyy-MM-dd`) or a full ISO instant. Formatted
|
|
540
|
+
* for display with `Intl.DateTimeFormat` in the active locale and emitted inside a
|
|
541
|
+
* `<time dateTime={effectiveDate}>`, so the machine-readable value is always the ISO input.
|
|
542
|
+
* NEVER pass a pre-formatted string.
|
|
543
|
+
*/
|
|
544
|
+
effectiveDate?: string;
|
|
545
|
+
/** Short plain-language summary rendered under the metadata, above the contents. */
|
|
546
|
+
summary?: ReactNode;
|
|
547
|
+
/**
|
|
548
|
+
* Accessible name + visible caption of the contents `<nav>` (e.g. "Contents"). Defaults to a
|
|
549
|
+
* localized "Contents"; override it when two documents render in the same view, so the two `nav`
|
|
550
|
+
* landmarks stay distinguishable (axe `landmark-unique`, WCAG 2.4.1).
|
|
551
|
+
*/
|
|
552
|
+
contentsLabel?: string;
|
|
553
|
+
/** The document's sections, in reading order. Drives BOTH the contents list and the body. */
|
|
554
|
+
sections: LegalDocumentSectionProp[];
|
|
555
|
+
/**
|
|
556
|
+
* Controlled active section id (the entry marked `aria-current="location"`). Pair it with
|
|
557
|
+
* `onActiveSectionChange`; omit both for the uncontrolled form.
|
|
558
|
+
*/
|
|
559
|
+
activeSection?: string;
|
|
560
|
+
/** Uncontrolled initial active section id. Defaults to the first section. */
|
|
561
|
+
defaultActiveSection?: string;
|
|
562
|
+
/**
|
|
563
|
+
* Fires whenever the active section changes — on a contents-anchor activation, on an initial
|
|
564
|
+
* hash deep link, and continuously from the scroll spy as the reader moves through the document.
|
|
565
|
+
*/
|
|
566
|
+
onActiveSectionChange?: (sectionId: string) => void;
|
|
567
|
+
/**
|
|
568
|
+
* Slot above the contents list in the rail — a document switcher across the legal set
|
|
569
|
+
* (Terms · Privacy · Cookies). Rendered as a plain wrapper, so the consumer owns its semantics.
|
|
570
|
+
*/
|
|
571
|
+
documentNavigation?: ReactNode;
|
|
572
|
+
/** Slot below the last section — the accept/download/print/contact actions. */
|
|
573
|
+
footerAction?: ReactNode;
|
|
574
|
+
id?: IdProp;
|
|
575
|
+
className?: ClassNameProp;
|
|
576
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/** Navigation component prop types — @see docs/COMPONENTS.md#navigation */
|
|
2
2
|
import type * as React from "react";
|
|
3
|
-
import type { ChildrenProp, ClassNameProp, DisabledProp, HasActiveFiltersProp, LabelProp, OnClearFiltersProp, StickyProp } from "../vocabulary/index.js";
|
|
3
|
+
import type { ChildrenProp, ClassNameProp, DisabledProp, HasActiveFiltersProp, IdProp, LabelProp, OnClearFiltersProp, StickyProp } from "../vocabulary/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* How a {@link ToolbarProp} strip resolves more filters than fit one row (#216).
|
|
6
|
+
* `wrap` (default) stacks on narrow viewports then wraps onto extra rows; `scroll` keeps ONE
|
|
7
|
+
* bounded row that scrolls inline, so a wide filter set never pushes the list below the fold.
|
|
8
|
+
*/
|
|
9
|
+
export type FilterBarOverflowProp = "wrap" | "scroll";
|
|
4
10
|
/** @see Toolbar */
|
|
5
11
|
export type ToolbarProp = {
|
|
6
12
|
onClear?: OnClearFiltersProp;
|
|
@@ -12,12 +18,24 @@ export type ToolbarProp = {
|
|
|
12
18
|
* `--filter-bar-sticky-background` theme knobs.
|
|
13
19
|
*/
|
|
14
20
|
sticky?: StickyProp;
|
|
21
|
+
/**
|
|
22
|
+
* Responsive overflow strategy (#216). Default `wrap`. Use `scroll` for list pages with many
|
|
23
|
+
* filters (long JA/EN/VI labels) where a wrapped 3-row strip would push the table off screen.
|
|
24
|
+
* Tune the scrollbar gutter with the `--filter-bar-scroll-padding-y` theme knob.
|
|
25
|
+
*/
|
|
26
|
+
overflow?: FilterBarOverflowProp;
|
|
15
27
|
className?: ClassNameProp;
|
|
16
28
|
children: ChildrenProp;
|
|
17
29
|
};
|
|
18
30
|
/** @see ToolbarGroup */
|
|
19
31
|
export type ToolbarGroupProp = {
|
|
20
32
|
label: LabelProp;
|
|
33
|
+
/**
|
|
34
|
+
* `id` of the single control this group labels (#216). When set, the visible group label is
|
|
35
|
+
* rendered as that control's real `<label htmlFor>`, so the filter is named by the text the
|
|
36
|
+
* user sees (WCAG 2.5.3 / 1.3.1) — otherwise the control needs its own `aria-label`.
|
|
37
|
+
*/
|
|
38
|
+
controlId?: IdProp;
|
|
21
39
|
className?: ClassNameProp;
|
|
22
40
|
children: ChildrenProp;
|
|
23
41
|
};
|