@godxjp/ui 24.0.0 → 25.0.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/dist/components/data-display/badge.js +3 -0
- package/dist/components/data-entry/select.js +7 -0
- package/dist/components/general/logo.d.ts +16 -0
- package/dist/components/general/logo.js +10 -2
- package/dist/components/layout/auth-identity.d.ts +1 -1
- package/dist/components/layout/auth-identity.js +5 -2
- package/dist/components/navigation/dropdown-menu.js +19 -2
- package/dist/components/navigation/tabs.js +24 -6
- package/dist/contracts/measurement.json +1 -1
- package/dist/email/tokens.generated.d.ts +1 -1
- package/dist/email/tokens.generated.js +1 -1
- package/dist/props/components/layout.prop.d.ts +32 -1
- package/dist/props/registry.d.ts +4 -0
- package/dist/props/registry.js +5 -0
- package/dist/props/vocabulary/interaction.prop.d.ts +10 -1
- package/dist/styles/control.css +5 -1
- package/dist/styles/data-display-layout.css +16 -5
- package/dist/styles/data-entry-layout.css +5 -0
- package/dist/styles/layout.css +5 -0
- package/dist/styles/logo-layout.css +30 -3
- package/dist/styles/motion.css +4 -0
- package/dist/styles/shell-layout.css +22 -6
- package/dist/styles/text-layout.css +5 -0
- package/dist/tokens/components/logo.css +8 -0
- package/dist/tokens/components/shell.css +7 -3
- package/dist/tokens/derived.css +8 -8
- package/dist/tokens/foundation.css +2 -2
- package/docs/DESIGN-AUTHORITY.md +36 -22
- package/docs/DEVELOPMENT.md +20 -0
- package/docs/FRAME-A11Y-CI.md +164 -0
- package/docs/foundation/colors.tsx +4 -1
- package/docs/general/logo.tsx +63 -0
- package/docs/general/typography.tsx +31 -0
- package/docs/layout/auth-identity.tsx +34 -0
- package/docs/layout/topbar.tsx +19 -8
- package/docs/showcase/acme-website.tsx +3 -1
- package/docs/showcase/case4-login.tsx +2 -2
- package/docs/showcase/case5-shift-calendar.tsx +5 -3
- package/docs/showcase/case6-agency-handy.tsx +13 -9
- package/docs/showcase/futurelastic-web.tsx +11 -3
- package/docs/showcase/table-bulk-actions.tsx +13 -2
- package/docs/showcase/table-density.tsx +3 -1
- package/docs/showcase/table-expandable-rows.tsx +25 -15
- package/docs/showcase/table-grouped-subtotals.tsx +5 -1
- package/package.json +4 -2
|
@@ -101,6 +101,8 @@
|
|
|
101
101
|
--topbar-center-compact-display: none;
|
|
102
102
|
|
|
103
103
|
--topbar-item-padding-inline: var(--space-3);
|
|
104
|
+
|
|
105
|
+
--topbar-item-padding-inline-compact: var(--space-2);
|
|
104
106
|
--topbar-item-gap: var(--space-2);
|
|
105
107
|
--topbar-item-min-width: var(--control-height);
|
|
106
108
|
|
|
@@ -209,12 +211,14 @@
|
|
|
209
211
|
--app-launcher-launchpad-title-letter-spacing: 0.08em;
|
|
210
212
|
--app-launcher-launchpad-close-space-padding: var(--space-2);
|
|
211
213
|
|
|
212
|
-
--sidebar-item-active-color: initial;
|
|
213
|
-
--sidebar-item-active-tint: initial;
|
|
214
|
-
|
|
215
214
|
--sidebar-item-active-background: initial;
|
|
215
|
+
|
|
216
216
|
--sidebar-item-active-foreground: initial;
|
|
217
217
|
|
|
218
|
+
--sidebar-item-active-tint: initial;
|
|
219
|
+
|
|
220
|
+
--sidebar-item-active-background-alpha: 12%;
|
|
221
|
+
|
|
218
222
|
--auth-shell-control-height: var(--control-height-comfortable);
|
|
219
223
|
--auth-shell-heading-size: var(--font-size-2xl);
|
|
220
224
|
--auth-shell-card-max-width: 24rem;
|
package/dist/tokens/derived.css
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
:root {
|
|
4
4
|
|
|
5
|
-
--primary-hover:
|
|
5
|
+
--primary-hover: 268.7 100% 41.6%;
|
|
6
6
|
|
|
7
|
-
--primary-active:
|
|
7
|
+
--primary-active: 268.7 100% 34.5%;
|
|
8
8
|
|
|
9
|
-
--primary-border:
|
|
9
|
+
--primary-border: 268.7 68% 66%;
|
|
10
10
|
--destructive-hover: 359 50.6% 53.1%;
|
|
11
11
|
--destructive-active: 355 70.6% 33.3%;
|
|
12
12
|
|
|
13
|
-
--control-outline:
|
|
13
|
+
--control-outline: 268.7 100% 44.7%;
|
|
14
14
|
--control-outline-alpha: 0.11;
|
|
15
15
|
|
|
16
16
|
--control-outline-error: 4.3 87.6% 34.7%;
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
.dark,
|
|
23
23
|
:root[data-theme="dark"] {
|
|
24
24
|
|
|
25
|
-
--primary-hover:
|
|
25
|
+
--primary-hover: 268.7 100% 92.7%;
|
|
26
26
|
|
|
27
|
-
--primary-active:
|
|
27
|
+
--primary-active: 268.7 100% 81.1%;
|
|
28
28
|
|
|
29
|
-
--primary-border:
|
|
29
|
+
--primary-border: 268.7 46.7% 23.5%;
|
|
30
30
|
--destructive-hover: 358.8 42.3% 53.1%;
|
|
31
31
|
--destructive-active: 357.3 50.6% 34.1%;
|
|
32
32
|
|
|
33
|
-
--control-outline:
|
|
33
|
+
--control-outline: 268.7 99% 61.8%;
|
|
34
34
|
--control-outline-alpha: 0.29;
|
|
35
35
|
|
|
36
36
|
--control-outline-error: 351.5 98.3% 53.5%;
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
--input: 30 7% 53%;
|
|
27
27
|
|
|
28
28
|
--success: 146 40% 58%;
|
|
29
|
-
--success-foreground:
|
|
29
|
+
--success-foreground: 48 8% 13%;
|
|
30
30
|
--warning: 44 100% 49%;
|
|
31
31
|
--warning-foreground: 48 8% 13%;
|
|
32
32
|
--info: 221 40% 50%;
|
|
33
33
|
--info-foreground: 60 33% 99%;
|
|
34
34
|
--attention: 25 99% 46%;
|
|
35
|
-
--attention-foreground:
|
|
35
|
+
--attention-foreground: 48 8% 13%;
|
|
36
36
|
|
|
37
37
|
--brand: 268.7 100% 50%;
|
|
38
38
|
--brand-foreground: 60 33% 99%;
|
package/docs/DESIGN-AUTHORITY.md
CHANGED
|
@@ -18,8 +18,8 @@ It changes no code by itself. It is the tie-breaker a reviewer points at.
|
|
|
18
18
|
| Behaviour primitives | **Radix** | already the implementation — 193 references |
|
|
19
19
|
| Component composition shape | **shadcn** | already the structural convention — 23 references |
|
|
20
20
|
| Component taxonomy / grouping | **Ant Design** groups | already the catalog shape: `data-entry`, `data-display`, `layout`, `feedback`, `navigation`, `general` — a naming precedent, nothing is installed |
|
|
21
|
-
| Colour foundation | **SmartHR
|
|
22
|
-
| **Derived colour — the interaction states hanging off each seed** | **Measured contrast (WCAG 2.2 / JIS X 8341-3)** | Authored in `src/tokens/derived.css`; no algorithm derives them. Four contrast suites read that file and hold every value to a threshold — see below |
|
|
21
|
+
| Colour foundation | **SmartHR**, brand roles aside | the NEUTRAL spine is SmartHR's — `--foreground` = TEXT_BLACK, `--border` = BORDER. `--primary` was SmartHR MAIN `#0071bd` until identity v2.3 took the brand roles back: it is GoDX violet `#7A00FF` today |
|
|
22
|
+
| **Derived colour — the interaction states hanging off each seed** | **Measured contrast (WCAG 2.2 / JIS X 8341-3)** | Authored in `src/tokens/derived.css`; no algorithm derives them. Four contrast suites read that file and hold every value to a threshold, and a fifth holds it to the seed's HUE (gh#648) — see below |
|
|
23
23
|
| **Japanese UI convention — density, JP typography, form patterns** | **SmartHR** | **NEW — this decision.** Extends SmartHR from "where the colours came from" to the authority for how a JP business screen behaves |
|
|
24
24
|
| **Japanese accessibility / public-sector convention** | **デジタル庁 Design System** (Digital Agency) | **NEW — this decision.** The reference when a JP customer asks which standard a screen meets (JIS X 8341-3) |
|
|
25
25
|
| **Spacing, density, type scale, information architecture** | **IBM Carbon** | **NEW — this decision** |
|
|
@@ -385,17 +385,25 @@ the property actually being sold.
|
|
|
385
385
|
suite — that is CI's job on the PR), and if a threshold breaks the value is
|
|
386
386
|
wrong. Do not relax the threshold.
|
|
387
387
|
|
|
388
|
-
**The
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
|
395
|
-
|
|
|
396
|
-
| light `--primary-
|
|
397
|
-
|
|
|
398
|
-
| dark `--primary-
|
|
388
|
+
**The primary interaction ramp, and the one override left in it.** The light states are TAKEN from
|
|
389
|
+
the identity v2.3 kit rather than computed — the kit publishes its own violet ramp — and each is
|
|
390
|
+
snapped to the seed's hue (1.008:1 / 1.010:1 from the kit value, i.e. the same colour). Dark takes
|
|
391
|
+
the kit's `action.primary.hover` and then reflects the pressed step, because the dark seed sits at
|
|
392
|
+
86.9% L and the conventional step runs out of LIGHTNESS rather than out of contrast:
|
|
393
|
+
|
|
394
|
+
| token | conventional step | shipped |
|
|
395
|
+
| ------------------------ | ------------------------ | ---------------------------------- |
|
|
396
|
+
| light `--primary-hover` | kit #6400D4 | #6500d4 · 8.23:1 |
|
|
397
|
+
| light `--primary-active` | kit #5200B0 | #5400b0 · 10.31:1 |
|
|
398
|
+
| dark `--primary-hover` | kit #E8DAFF | #ecdaff · 13.51:1 |
|
|
399
|
+
| dark `--primary-active` | #fbf7ff · 1.056:1 from white | #cd9fff · 8.41:1 (sign flipped) |
|
|
400
|
+
|
|
401
|
+
**The ratio is blind to hue, and that cost a release (gh#648).** Identity v2.3 moved the seed 63
|
|
402
|
+
degrees and this tier stayed on the blue it was derived from: 24.0.0 and 24.1.0 shipped a primary
|
|
403
|
+
button that was violet at rest and navy on hover, with all four contrast suites green throughout,
|
|
404
|
+
because #005596 clears 7.53:1 on the primary label whatever the seed underneath it is. A threshold
|
|
405
|
+
is still the right authority — it just answers one axis of two.
|
|
406
|
+
`src/tokens/__tests__/derived-hue-lock.test.ts` answers the other, and asserts nothing else.
|
|
399
407
|
|
|
400
408
|
**What was deliberately never derived, and why — each a measurement, not a preference:**
|
|
401
409
|
|
|
@@ -482,11 +490,16 @@ the **field** indicator on every control — one hairline (1px) in the focus hue
|
|
|
482
490
|
`--control-outline` halo — rather than the heavy 3px outline form. Measured, in Chromium, on
|
|
483
491
|
`ql.test` after the transition settles:
|
|
484
492
|
|
|
485
|
-
| control | switch off | switch on
|
|
486
|
-
| -------------------------- | ---------------------------------------------------- |
|
|
487
|
-
| Input / Select trigger | border `1px rgb(144,135,127)`, resting shadow intact | border `1px
|
|
488
|
-
| Button (primary) | outline `0px`, resting shadow intact | `outline: 1px solid
|
|
489
|
-
| Sidebar nav row / list row | outline `0px` | `outline: 1px solid
|
|
493
|
+
| control | switch off | switch on |
|
|
494
|
+
| -------------------------- | ---------------------------------------------------- | -------------------------------------------------------------- |
|
|
495
|
+
| Input / Select trigger | border `1px rgb(144,135,127)`, resting shadow intact | border `1px` of `--ring` + `--control-outline` halo `0 0 0 2px` |
|
|
496
|
+
| Button (primary) | outline `0px`, resting shadow intact | `outline: 1px solid` `--ring` @ `0px` + same halo |
|
|
497
|
+
| Sidebar nav row / list row | outline `0px` | `outline: 1px solid` `--ring` @ **`-1px`** (inset into the row) |
|
|
498
|
+
|
|
499
|
+
The GEOMETRY above is the Chromium measurement; the COLOUR is named by token rather than pinned as
|
|
500
|
+
a hex, because it follows the seed and the hexes this table used to carry were the pre-v2.3 blue —
|
|
501
|
+
the same staleness gh#648 found one tier down. Today `--ring` resolves to rgb(122,0,255) light /
|
|
502
|
+
rgb(220,188,255) dark and the halo to `rgba(109,0,228,0.11)` / `rgba(153,61,254,0.29)`.
|
|
490
503
|
|
|
491
504
|
The field pair is the recoloured boundary plus the halo, exactly as the convention specifies for
|
|
492
505
|
this seed. The nav row insets its mark into its own shape rather than wrapping an already-shaded surface,
|
|
@@ -497,10 +510,11 @@ after: the field form only recolours a border and an `outline` is painted outsid
|
|
|
497
510
|
Input, Save and Delete all stay at 32.00px.
|
|
498
511
|
|
|
499
512
|
**Two criteria, and only one is met by thickness alone.** SC 1.4.11 (AA, non-text contrast) is about
|
|
500
|
-
COLOUR — the 1px mark measures 5.
|
|
501
|
-
the light weight costs nothing there. `--primary-border`
|
|
502
|
-
|
|
503
|
-
|
|
513
|
+
COLOUR — the 1px mark measures at worst 5.30:1 light and 6.87:1 dark across every surface a control
|
|
514
|
+
sits on (an accent panel in both themes), so the light weight costs nothing there. `--primary-border`
|
|
515
|
+
(#a66de3) reaches 3.49:1 on the page and **2.92:1 light / 1.03:1 dark on that same accent panel**, so
|
|
516
|
+
it still could not satisfy the criterion everywhere at any thickness, which is why the on-state takes
|
|
517
|
+
the focus hue instead — the single place it departs from the outline form. SC 2.4.13 Focus Appearance
|
|
504
518
|
(AAA) additionally wants a 2px perimeter; the on-state does not target it, and
|
|
505
519
|
`--focus-outline-weight: var(--stroke-lg)` restores the 3px weight if a customer needs the area
|
|
506
520
|
clause.
|
package/docs/DEVELOPMENT.md
CHANGED
|
@@ -122,10 +122,30 @@ pnpm test # FULL suite — CI only, never from an agent loop
|
|
|
122
122
|
pnpm preview:build # integration test: examples + docs must build — at most once, pre-PR
|
|
123
123
|
pnpm audit # godxjp-ui-audit — 0 errors for touched files
|
|
124
124
|
pnpm check:mcp-sync # MCP registry ↔ library export drift guard
|
|
125
|
+
pnpm check:frame-axe # WCAG 2.2 AA over every frame — see FRAME-A11Y-CI.md
|
|
125
126
|
```
|
|
126
127
|
|
|
127
128
|
`pnpm verify` and `pnpm verify:release` run these together (verify:release also builds) — **both include the full suite, so both belong to CI.** Locally, run them at most once immediately before opening a PR, never inside an edit loop and never while other agents are working on the same machine. It needs `pnpm exec playwright install chromium` once locally; see [FRAME-A11Y-CI.md](./FRAME-A11Y-CI.md) for how to run/scope it, read the evidence, and regenerate its baseline after an accessibility fix.
|
|
128
129
|
|
|
130
|
+
### Reproducing one screen at one width — the frame routes
|
|
131
|
+
|
|
132
|
+
Three gates and every bug report start here, so the addressing is written down rather than guessed
|
|
133
|
+
(godx-jp/id#639 burned three attempts on `?frame=…`, which is not a thing):
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
pnpm preview # :6008
|
|
137
|
+
http://localhost:6008/isolate/<id> # the demo ALONE, at the real viewport — measure here
|
|
138
|
+
http://localhost:6008/frame/<id> # the same demo inside the device-preset chrome
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`<id>` is the demo's path under `docs/`, minus `.tsx`, with `/` turned into `-`:
|
|
142
|
+
`docs/layout/topbar.tsx` → `layout-topbar`, `docs/data-entry/date-picker.tsx` → `data-entry-date-picker`.
|
|
143
|
+
A file may override it with a `slug` in its frontmatter. Both routes accept
|
|
144
|
+
`?dir=rtl&density=compact&theme=dark&locale=ja`; `/frame/**` additionally takes `?preset=`/`?w=`/`?h=`/`?zoom=`.
|
|
145
|
+
|
|
146
|
+
For an axe measurement at a given width, drive `/isolate/<id>` with Playwright at that viewport —
|
|
147
|
+
that is what `scripts/topbar-collision-visual.mjs` and the other `test:visual:*` gates do.
|
|
148
|
+
|
|
129
149
|
All gates are **self-contained** — no internal/external tooling package required. The eslint, prettier, and vitest setup live in the package (`eslint.config.js`, `prettier.config.mjs`, `vitest.config.ts`, `src/test/`), so a fresh checkout can lint/type-check/test without anything beyond the declared devDependencies.
|
|
130
150
|
|
|
131
151
|
The app side additionally runs **`npm run ui:audit`** (the design-system linter) and must report 0 errors for touched files.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Per-frame accessibility CI — `check:frame-axe`
|
|
2
|
+
|
|
3
|
+
One ruler, run in the repository that owns the CSS.
|
|
4
|
+
|
|
5
|
+
## Why it exists (gh#643)
|
|
6
|
+
|
|
7
|
+
`scripts/visual-audit.mjs` carries **eight** rules. A consumer's nightly runs `@axe-core/playwright`
|
|
8
|
+
with **68**. Six of our eight are design-language opinions with no axe equivalent —
|
|
9
|
+
`oversaturated-accent`, `sibling-card-gap`, `row-content-starved`, `emoji-rendered`,
|
|
10
|
+
`alert-controls-misplaced`, `css-layers-missing` — and a design system **should** own those. The
|
|
11
|
+
other sixty (names, roles, `aria-*`, contrast, focus order, target size) were checked **nowhere in
|
|
12
|
+
this repository**, and only in a consumer that cannot fix the CSS, because the CSS is here.
|
|
13
|
+
|
|
14
|
+
gh#639 is what that costs. A topbar shipped; every gate here said green; `target-size` failed in
|
|
15
|
+
`godx-jp/id`'s nightly at 320px. And our own `target-size-min` could not have caught it at any
|
|
16
|
+
threshold — it measures a **painted box**, and that failure was an **obscured** target (axe:
|
|
17
|
+
`partiallyObscured`, 8×28). Two rulers, and the disagreement only ever surfaces downstream.
|
|
18
|
+
|
|
19
|
+
## What it does
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm check:frame-axe # every frame, 3 viewports
|
|
23
|
+
pnpm check:frame-axe -- --update # rewrite the baseline
|
|
24
|
+
pnpm check:frame-axe -- --scope=showcase # the 30 whole-page frames only, 30s
|
|
25
|
+
pnpm check:frame-axe -- /isolate/layout-topbar # one route, while fixing
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
| | |
|
|
29
|
+
| --------- | --------------------------------------------------------------------------------- |
|
|
30
|
+
| tool | `@axe-core/playwright` |
|
|
31
|
+
| tags | `wcag2a` · `wcag2aa` · `wcag21aa` · `wcag22aa` — **the consumer's set, verbatim** |
|
|
32
|
+
| routes | every `/isolate/<id>` in `window.__STORY_MANIFEST__` + every `/showcase/<id>` |
|
|
33
|
+
| viewports | 1440×900 · 375×667 · **320×568** |
|
|
34
|
+
|
|
35
|
+
320 is not decoration: it is WCAG 2.2 SC 1.4.10's reflow width, it is the width the consumer's
|
|
36
|
+
nightly runs, and it is the width gh#639 failed at while 390 passed.
|
|
37
|
+
|
|
38
|
+
Showcases are included on purpose. They are the only frames here shaped like a real screen — a whole
|
|
39
|
+
page, a landmark tree, a focus order — which is precisely the class the component frames cannot
|
|
40
|
+
reach and the consumer has been carrying alone.
|
|
41
|
+
|
|
42
|
+
## What it found on its first run — and what came of it
|
|
43
|
+
|
|
44
|
+
54 rows, **159 violation nodes**, on code that passed every other gate in this repository. Fixing
|
|
45
|
+
them took it to **12 rows / 19 nodes**, and then to **0**:
|
|
46
|
+
|
|
47
|
+
| rule | first run | now | what it was |
|
|
48
|
+
| ----------------------- | --------: | --: | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
49
|
+
| `color-contrast` | 62 | 0 | text under 4.5:1 (SC 1.4.3) |
|
|
50
|
+
| `target-size` | 28 | 0 | under 24×24 (SC 2.5.8) — `Carousel` dots, `SearchInput`'s clear button, `Attachments`' file input |
|
|
51
|
+
| `aria-prohibited-attr` | 21 | 0 | `Badge`'s `aria-label` on a `generic` div — the name was dropped by every screen reader |
|
|
52
|
+
| `button-name` | 18 | 0 | **`Select`'s trigger is `role="combobox"`, which cannot be named by its contents** — every unlabelled Select shipped a nameless combobox |
|
|
53
|
+
| `aria-valid-attr-value` | 18 | 0 | `aria-controls` pointing at ids that do not exist |
|
|
54
|
+
| `aria-conditional-attr` | 12 | 0 | `aria-expanded` on a `<tr>`, which only a `treegrid` row may carry |
|
|
55
|
+
|
|
56
|
+
Four of those were LIBRARY defects, not demo slips — `Badge`, `Select`, `Carousel`, `SearchInput` —
|
|
57
|
+
and the fifth produced a new vocabulary member: `tone="inherit"` on `Text` / `Heading` / `Title` /
|
|
58
|
+
`Activity` / `Separator`, because every other tone is an absolute token and there was no way to put
|
|
59
|
+
text on a coloured surface without fighting it.
|
|
60
|
+
|
|
61
|
+
The `target-size` rows are the sharpest point about two rulers. Our own `target-size-min` was
|
|
62
|
+
running on those same frames and reporting them clean, because it measures a painted box. And the
|
|
63
|
+
fix axe wants is not the fix the standard wants: a centred `::after` genuinely makes the target
|
|
64
|
+
24×24 — `docs/MEASUREMENT-CONTRACT.md` records that under `expanders` — but axe reads
|
|
65
|
+
`getBoundingClientRect()`, which cannot see a pseudo-element. Both fixes were tried; the boxes had
|
|
66
|
+
to grow.
|
|
67
|
+
|
|
68
|
+
## The last twelve rows, and what each one turned out to be
|
|
69
|
+
|
|
70
|
+
The table above is what the sweep found; this is what the remaining 12 rows / 19 nodes turned out
|
|
71
|
+
to be once each was measured rather than reasoned about. The rows are kept, with the verdict this
|
|
72
|
+
file used to carry quoted back, because four of the five were wrong: two had no diagnosis at all
|
|
73
|
+
and two had one the measurement contradicted — and in both of those the guess pointed AWAY from
|
|
74
|
+
this package.
|
|
75
|
+
|
|
76
|
+
| rows | what | the measurement, and where it was fixed |
|
|
77
|
+
| ---: | ------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
78
|
+
| 3 | `foundation-colors` · `--success-foreground` on `--success`, `--attention-foreground` on `--attention` | Called "a PALETTE decision, an owner-level call". It was not the palette: the FILL was fine and the INK was wrong. Two of the light theme's eight fills carried a near-white ink their own lightness cannot support (2.19:1 / 3.32:1) while the sibling `--warning` had always used the near-black one on the equally pale 山吹, and the DARK theme already flipped both. `src/tokens/foundation.css`: ink only — success 2.19 → **7.08**, attention 3.32 → **4.68**. Guarded by `__tests__/status-fill-contrast.test.ts`. |
|
|
79
|
+
| 3 | `case6-agency-handy` · a SELECTED `ToggleGroupItem` paints `--foreground` over `--primary` | "Cause not yet found." Found, with `CSS.getMatchedStylesForNode`: the demo wrote `text-[var(--font-size-xs)]`, and Tailwind v4 reads a bare `var()` in `text-*` as a COLOUR — it compiled to `color: var(--font-size-xs)` in the UTILITIES layer, an invalid colour that clobbered the component's own `color: hsl(var(--primary-foreground))` in `components` and left the trigger inheriting the page ink. The component rule was right all along. Demo fix (`text-[length:var(…)]`, 10 sites in `docs/`), plus the count pill: the hand-rolled `Text` at `opacity-70` measured 2.15:1 and `ToggleGroupItem`'s own `count` prop inverts to 6.32:1. |
|
|
80
|
+
| 3 | `table-view-tabs` · a `Tab`'s `aria-controls` points at a `tabpanel` that is never rendered | A LIBRARY defect, and the composition is published: `Tabs` / `TabsList` / `TabsTrigger` are three separate exports, nothing in their types asks for a fourth, and the attribute could not be overridden (`withDomProps` puts RAC's props after the caller's). `TabsContent` now registers its value and a trigger claims a panel only when one is declared. No new public prop. `__tests__/tabs-panel-reference-643.test.tsx`. |
|
|
81
|
+
| 2 | `futurelastic-web` @320/@375 · white ghost buttons read as 1.01:1 | "Probably a false positive." It was not. The tenant's `.fl-navbar-inner` was a fixed-height flex row with no wrap, so at 320 its content ran to **x=569.6 inside a 320px nav** — the links painted outside the navbar's own box, over the page behind it. A WCAG 2.2 SC 1.4.10 reflow failure reported by the contrast rule, because that is what an overflowing element looks like from the outside. Demo CSS + `Flex wrap`. |
|
|
82
|
+
| 1 | `table-bulk-actions` @375 · `target-size` | "Not yet diagnosed." The left cluster carried `min-w-0 flex-1` — "squeeze me to nothing" — over children that refuse to shrink, so its box shrank to 113.6px while its content ran to x=462 and painted 一括承認 (264.6→360.2) under 解除 (272.3→341.0), leaving 19.2×30.2 unobscured against SC 2.5.8's 24×24. Demo: `wrap`, and no `min-w-0`. |
|
|
83
|
+
|
|
84
|
+
Two of the five were library defects and three were genuine demo slips — a different split from the
|
|
85
|
+
first sweep, where four of five were the library's. Which is the point of writing the number down
|
|
86
|
+
next to each one: "it is the demo" and "it is the palette" are both cheap to say and neither
|
|
87
|
+
survived a measurement here.
|
|
88
|
+
|
|
89
|
+
## The baseline is a debt ledger, not an allowlist
|
|
90
|
+
|
|
91
|
+
The package did not start compliant, and a gate that fails the whole build on its first day gets
|
|
92
|
+
deleted rather than obeyed. `frame-axe-baseline.json` records what was already failing when the gate
|
|
93
|
+
landed, keyed one row per `(route, viewport, rule)`:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
"/isolate/layout-topbar @320 target-size": { "count": 2, "help": "…" }
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The gate fails on a key that is **not** in the baseline, and on a baselined key whose `count`
|
|
100
|
+
**grows**. A key that stops firing is reported so it can be dropped.
|
|
101
|
+
|
|
102
|
+
- **Delete rows as you fix them.** `--update` rewrites the file; the diff is the review.
|
|
103
|
+
- **Never add a row by hand to turn a red build green.** That is the one move this file exists to
|
|
104
|
+
make visible.
|
|
105
|
+
|
|
106
|
+
## What this gate does NOT do — stated, not hidden
|
|
107
|
+
|
|
108
|
+
The gate deleted in #492 did three things this one does not, and each is a real gap:
|
|
109
|
+
|
|
110
|
+
1. **No overlay scope.** It scans the frame as rendered. A menu, dialog, listbox or popover that is
|
|
111
|
+
closed at rest is never measured, so `aria-hidden-focus` and friends stay outside its field of
|
|
112
|
+
view. The old gate opened one overlay per frame from a `data-axe-open` attribute; that attribute
|
|
113
|
+
was removed from the demos along with the gate and would have to come back.
|
|
114
|
+
2. **No chrome/component split.** The old gate held the preview toolbar to zero violations and
|
|
115
|
+
allowlisted the component scope separately. `/isolate/**` renders the demo alone, so there is
|
|
116
|
+
little chrome to separate — but `/showcase/**` is scanned whole.
|
|
117
|
+
3. **No per-rule severity.** Every WCAG-tagged rule is treated alike.
|
|
118
|
+
|
|
119
|
+
## Determinism
|
|
120
|
+
|
|
121
|
+
Two consecutive sweeps of identical code first disagreed on five `color-contrast` rows: a fade-in
|
|
122
|
+
caught mid-flight renders text at partial opacity and axe scores whatever it finds. A gate that
|
|
123
|
+
disagrees with itself gets ignored, so each page is pinned before the scan —
|
|
124
|
+
`reducedMotion: "reduce"`, an injected stylesheet zeroing every animation and transition duration,
|
|
125
|
+
and `document.fonts.ready` (web fonts change glyph geometry, which changes which boxes overlap,
|
|
126
|
+
which changes what `color-contrast` resolves a background to). Two sweeps after that: identical.
|
|
127
|
+
|
|
128
|
+
## Cost
|
|
129
|
+
|
|
130
|
+
| | |
|
|
131
|
+
| ---------------------------------- | ----------------------------------------------------------------------------------- |
|
|
132
|
+
| full sweep | **3m20s** locally · **12m01s** on the self-hosted runner — 215 routes × 3 viewports |
|
|
133
|
+
| sequential | ~55 min — the three viewport passes run concurrently, which is the whole difference |
|
|
134
|
+
| showcase only (`--scope=showcase`) | 30s |
|
|
135
|
+
|
|
136
|
+
`--shard=i/n` is in the script for the day the sweep outgrows the lane. Using it adds check-run
|
|
137
|
+
names, which costs nothing here because none of them is in `REQUIRED_CI_CHECK_RUNS`.
|
|
138
|
+
|
|
139
|
+
## Where it runs
|
|
140
|
+
|
|
141
|
+
Two lanes, split on a **measurement taken on the runner, not on a laptop**:
|
|
142
|
+
|
|
143
|
+
| lane | what | when | measured |
|
|
144
|
+
| ----------------------------------------------------------------- | ----------------------------------------- | -------------------------------------------------------------- | -------------------------------------- |
|
|
145
|
+
| `ci-browser.yml` · `Per-frame axe (showcases, WCAG 2.2 AA)` | `--scope=showcase` — 30 whole-page frames | every push to `main` | 30s locally |
|
|
146
|
+
| `ci-browser-full.yml` · `Per-frame axe (all frames, WCAG 2.2 AA)` | the full 215-route sweep | nightly, `workflow_dispatch`, or a `run-browser` label on a PR | **12m01s on the pool** (3m20s locally) |
|
|
147
|
+
|
|
148
|
+
The full sweep went into the merge lane first, on the local 3m20s. On the pool's runner the same
|
|
149
|
+
job took **12m01s** — three times the local wall clock and more than twice CONTRACT.md L4's
|
|
150
|
+
five-minute budget for that whole lane. So the merge lane keeps the showcases, which are the only
|
|
151
|
+
frames here shaped like the screens a consumer ships, and the wide matrix moved to the lane this
|
|
152
|
+
repository already reserves for wide matrices.
|
|
153
|
+
|
|
154
|
+
**Not** the PR lane: that file's own header lists axe among what it deliberately excludes, at a
|
|
155
|
+
measured 653–745s, and that decision is not reopened here.
|
|
156
|
+
|
|
157
|
+
The job is not in `REQUIRED_CI_CHECK_RUNS` (#492 removed it from the release proof map and this does
|
|
158
|
+
not put it back). It still protects a release through `assertCiProvenance`'s collateral rule — **any**
|
|
159
|
+
red check run on the SHA being published refuses the publish.
|
|
160
|
+
|
|
161
|
+
## Related
|
|
162
|
+
|
|
163
|
+
- [FRAME-COVERAGE-STANDARD.md](./FRAME-COVERAGE-STANDARD.md) — which frames must exist at all.
|
|
164
|
+
- [DEVELOPMENT.md](./DEVELOPMENT.md) §5 — the `/isolate/<id>` · `/frame/<id>` addressing.
|
|
@@ -69,7 +69,10 @@ function SwatchTile({ swatch, text }: { swatch: Swatch; text?: boolean }) {
|
|
|
69
69
|
{/* ui-audit-disable-next-line no-hand-rolled-surface no-utility-layout no-utility-spacing — a swatch showing the token itself; the fill IS the subject */}
|
|
70
70
|
<div className={`border-border flex h-14 items-end rounded-md border p-2 ${swatch.cls}`}>
|
|
71
71
|
{text ? (
|
|
72
|
-
|
|
72
|
+
/* `tone="inherit"` — the specimen's whole job is to show the token's PAIRED foreground,
|
|
73
|
+
and every other tone is an absolute colour. Without it `Text` repainted itself in
|
|
74
|
+
`--foreground` over `--primary` and measured 2.45:1 on this very page (gh#643). */
|
|
75
|
+
<Text size="xs" mono tone="inherit" className="leading-none">
|
|
73
76
|
Aa 亜
|
|
74
77
|
</Text>
|
|
75
78
|
) : null}
|
package/docs/general/logo.tsx
CHANGED
|
@@ -125,6 +125,69 @@ export default function Demo() {
|
|
|
125
125
|
</Flex>
|
|
126
126
|
</CardContent>
|
|
127
127
|
</Card>
|
|
128
|
+
|
|
129
|
+
<Card>
|
|
130
|
+
<CardHeader>
|
|
131
|
+
<CardTitle level={2}>Product suffix — 「GoDX | ID」</CardTitle>
|
|
132
|
+
<CardDescription>
|
|
133
|
+
productSuffix は製品名を lockup の内側に置きます。マスターは
|
|
134
|
+
mark="godx-lockup" の 1 つだけで、区切り線・その前後の間隔・size
|
|
135
|
+
スケール・light/dark
|
|
136
|
+
の切替はすべてパッケージのトークンが所有します(--logo-divider-color / -width /
|
|
137
|
+
-height / -alpha、--logo-product-suffix-gap / -color /
|
|
138
|
+
-font-weight)。製品名は「描いた図形」ではなく wordmark と同じ組版
|
|
139
|
+
(--logo-wordmark-font-size-* /
|
|
140
|
+
-font-family)です。別座標系のマスターを増やさず、製品が増えても
|
|
141
|
+
リリースが要らず、ローカライズできるためです。 区切り線の色はロゴタイプの ink
|
|
142
|
+
(--logo-godx-ink-color)の 0.25 alpha で、light では #c1c2cb(1.74:1、 公式キットの
|
|
143
|
+
#c5c8d6 = 1.64:1 とほぼ同じ)、dark では #515150(2.30:1)。 キットの固定値と違い dark
|
|
144
|
+
の対応があります。
|
|
145
|
+
</CardDescription>
|
|
146
|
+
</CardHeader>
|
|
147
|
+
<CardContent>
|
|
148
|
+
<Flex direction="col" gap="md">
|
|
149
|
+
{/* size は suffix にも効く — マークもロゴタイプも製品名も同じティアで動きます。 */}
|
|
150
|
+
<Flex direction="row" align="center" wrap gap="lg">
|
|
151
|
+
<Logo mark="godx-lockup" productSuffix="ID" size="xs" />
|
|
152
|
+
<Logo mark="godx-lockup" productSuffix="ID" size="sm" />
|
|
153
|
+
<Logo mark="godx-lockup" productSuffix="ID" />
|
|
154
|
+
<Logo mark="godx-lockup" productSuffix="ID" size="lg" />
|
|
155
|
+
</Flex>
|
|
156
|
+
{/* 将来の製品名も同じ API。追加のアセットもリリースも要りません。 */}
|
|
157
|
+
<Flex direction="row" align="center" wrap gap="lg">
|
|
158
|
+
<Logo mark="godx-lockup" productSuffix="Console" />
|
|
159
|
+
<Logo mark="godx-lockup" productSuffix="Admin" />
|
|
160
|
+
<Logo mark="godx-lockup" productSuffix="管理コンソール" />
|
|
161
|
+
</Flex>
|
|
162
|
+
{/* 描かれた "GoDX" は sr-only テキストで補われ、名前は "GoDX ID" になります。
|
|
163
|
+
* role="img" を使わないのは、asChild でリンクにしたとき link ロールを
|
|
164
|
+
* 上書きしてしまうためです。 */}
|
|
165
|
+
<Flex direction="col" gap="sm">
|
|
166
|
+
<Logo mark="godx-lockup" productSuffix="ID" size="lg" />
|
|
167
|
+
<Text size="2xs" mono tone="muted">
|
|
168
|
+
{`mark="godx-lockup" productSuffix="ID" → accessible name "GoDX ID"`}
|
|
169
|
+
</Text>
|
|
170
|
+
</Flex>
|
|
171
|
+
{/* 組版の wordmark と併用すると、suffix はその後ろに入ります。 */}
|
|
172
|
+
<Flex direction="col" gap="sm">
|
|
173
|
+
<Logo glyph="c" wordmark="CoreBooks" productSuffix="Admin" />
|
|
174
|
+
<Text size="2xs" mono tone="muted">
|
|
175
|
+
{`glyph + wordmark + productSuffix → name "CoreBooks Admin"`}
|
|
176
|
+
</Text>
|
|
177
|
+
</Flex>
|
|
178
|
+
{/* suffix がノードでも名前は壊れません。label は従来どおり上書きできます。 */}
|
|
179
|
+
<Logo
|
|
180
|
+
mark="godx-lockup"
|
|
181
|
+
productSuffix={<Text size="xs">ID</Text>}
|
|
182
|
+
label="GoDX ID ホーム"
|
|
183
|
+
/>
|
|
184
|
+
{/* リンク化も同じ。lockup そのものが <a> になります。 */}
|
|
185
|
+
<Logo asChild mark="godx-lockup" productSuffix="ID">
|
|
186
|
+
<a href="#logo-product-suffix" />
|
|
187
|
+
</Logo>
|
|
188
|
+
</Flex>
|
|
189
|
+
</CardContent>
|
|
190
|
+
</Card>
|
|
128
191
|
</Flex>
|
|
129
192
|
</PageContainer>
|
|
130
193
|
);
|
|
@@ -94,6 +94,37 @@ export default function Demo() {
|
|
|
94
94
|
</CardContent>
|
|
95
95
|
</Card>
|
|
96
96
|
|
|
97
|
+
<Card>
|
|
98
|
+
<CardHeader>
|
|
99
|
+
<CardTitle level={2}>tone="inherit" · 面が決める</CardTitle>
|
|
100
|
+
<CardDescription>
|
|
101
|
+
他の tone は絶対的なトークンを塗るため、色つきの面に置いた途端にページの文字色へ戻って
|
|
102
|
+
しまいます。inherit はその面が持つ対になる前景色をそのまま使う唯一のメンバーです。
|
|
103
|
+
これを入れる前、--primary の上の Text は --foreground を塗って 2.45:1
|
|
104
|
+
でした(gh#643)。
|
|
105
|
+
</CardDescription>
|
|
106
|
+
</CardHeader>
|
|
107
|
+
<CardContent>
|
|
108
|
+
<Flex direction="col" gap="md">
|
|
109
|
+
{/* ui-audit-disable-next-line no-hand-rolled-surface no-utility-layout no-utility-spacing — the COLOURED SURFACE is the subject here, exactly as in docs/foundation/colors.tsx */}
|
|
110
|
+
<div className="bg-primary text-primary-foreground rounded-md p-4">
|
|
111
|
+
<Flex direction="col" gap="xs">
|
|
112
|
+
<Heading level={3} tone="inherit">
|
|
113
|
+
請求サマリー
|
|
114
|
+
</Heading>
|
|
115
|
+
<Text tone="inherit">今月の請求は締め処理まで完了しています。</Text>
|
|
116
|
+
<Text size="2xs" mono tone="inherit">
|
|
117
|
+
{`tone="inherit"`}
|
|
118
|
+
</Text>
|
|
119
|
+
</Flex>
|
|
120
|
+
</div>
|
|
121
|
+
<Text size="xs" tone="muted">
|
|
122
|
+
同じ二行を tone="default" で置くと、面ではなくページの文字色を塗ります。
|
|
123
|
+
</Text>
|
|
124
|
+
</Flex>
|
|
125
|
+
</CardContent>
|
|
126
|
+
</Card>
|
|
127
|
+
|
|
97
128
|
<Card>
|
|
98
129
|
<CardHeader>
|
|
99
130
|
<CardTitle level={2}>Text sizes</CardTitle>
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
|
|
2
|
+
import { Logo } from "@godxjp/ui/general";
|
|
2
3
|
import { AuthAccountSummary, AuthIdentity, AuthStack, PageContainer } from "@godxjp/ui/layout";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* AuthIdentity — canonical identity title with optional relying-party request context. The
|
|
6
7
|
* requester line is consumer data and may be omitted for first-party authentication.
|
|
8
|
+
*
|
|
9
|
+
* `brand` is the product's own artwork, in the MARK's place: the h1 stays painted and keeps naming
|
|
10
|
+
* the block, and the artwork is decorative whatever fills it — so a lockup that spells "GoDX | ID"
|
|
11
|
+
* is not announced on top of the heading. When the lockup already carries the product name, make
|
|
12
|
+
* `title` the SCREEN'S purpose ("サインイン") rather than repeating the brand.
|
|
7
13
|
*/
|
|
8
14
|
export default function Demo() {
|
|
9
15
|
return (
|
|
@@ -31,6 +37,34 @@ export default function Demo() {
|
|
|
31
37
|
</AuthStack>
|
|
32
38
|
</CardContent>
|
|
33
39
|
</Card>
|
|
40
|
+
|
|
41
|
+
<Card>
|
|
42
|
+
<CardHeader>
|
|
43
|
+
<CardTitle level={2}>brand · 製品ロックアップ</CardTitle>
|
|
44
|
+
<CardDescription>
|
|
45
|
+
brandを渡すとパッケージのマークが製品のロックアップに置き換わります。h1はtitleを読み上げ名
|
|
46
|
+
として保持し、ロックアップは装飾扱いになるため製品名は一度だけ読まれます。ロックアップが製品名
|
|
47
|
+
を含む場合、titleには画面の目的を入れてください。
|
|
48
|
+
</CardDescription>
|
|
49
|
+
</CardHeader>
|
|
50
|
+
<CardContent>
|
|
51
|
+
<AuthStack>
|
|
52
|
+
<AuthIdentity
|
|
53
|
+
title="サインイン"
|
|
54
|
+
brand={<Logo mark="godx-lockup" productSuffix="ID" />}
|
|
55
|
+
/>
|
|
56
|
+
<AuthIdentity
|
|
57
|
+
title="サインイン"
|
|
58
|
+
brand={<Logo mark="godx-lockup" productSuffix="ID" size="lg" />}
|
|
59
|
+
requester="勤怠管理が認証を要求しています"
|
|
60
|
+
/>
|
|
61
|
+
<AuthIdentity
|
|
62
|
+
title="サインイン"
|
|
63
|
+
brand={<Logo glyph="a" wordmark="Acme" productSuffix="ID" />}
|
|
64
|
+
/>
|
|
65
|
+
</AuthStack>
|
|
66
|
+
</CardContent>
|
|
67
|
+
</Card>
|
|
34
68
|
</PageContainer>
|
|
35
69
|
);
|
|
36
70
|
}
|
package/docs/layout/topbar.tsx
CHANGED
|
@@ -94,10 +94,18 @@ export default function Demo() {
|
|
|
94
94
|
>
|
|
95
95
|
{collapsed ? <PanelLeftOpen /> : <PanelLeftClose />}
|
|
96
96
|
</Button>
|
|
97
|
-
{/* Decorative mark — hidden below sm so the budget goes to the two real controls.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
{/* Decorative mark — hidden below sm so the budget goes to the two real controls. That was
|
|
98
|
+
only ever a COMMENT: nothing here hid anything, and at 320px the 32px mark was part of
|
|
99
|
+
why the switcher beside it was crushed to 0 visible px (gh#639). `hideBelow` is the
|
|
100
|
+
contract that makes the sentence true — a slot cannot shrink a control, so a bar that
|
|
101
|
+
does not fit has to drop one. */}
|
|
102
|
+
<Flex as="span" hideBelow="sm" gap="none">
|
|
103
|
+
<Avatar className="rounded-md">
|
|
104
|
+
<AvatarFallback className="bg-primary text-primary-foreground font-bold">
|
|
105
|
+
C
|
|
106
|
+
</AvatarFallback>
|
|
107
|
+
</Avatar>
|
|
108
|
+
</Flex>
|
|
101
109
|
<DropdownMenu>
|
|
102
110
|
<DropdownMenuTrigger asChild>
|
|
103
111
|
{/* Button ships `shrink-0`, and only the LAST child of the start slot gets the built-in
|
|
@@ -150,10 +158,13 @@ export default function Demo() {
|
|
|
150
158
|
// end · notifications + user menu, both consumer-composed.
|
|
151
159
|
const end = (
|
|
152
160
|
<>
|
|
153
|
-
{
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
161
|
+
{/* The environment marker is the end cluster's most optional item — 92px of a 320px bar, and
|
|
162
|
+
the single biggest reason the start cluster had nothing left. It goes first. */}
|
|
163
|
+
<Flex as="span" hideBelow="sm" gap="none">
|
|
164
|
+
<Badge tone="warning" className="text-xs">
|
|
165
|
+
ステージング
|
|
166
|
+
</Badge>
|
|
167
|
+
</Flex>
|
|
157
168
|
<TopbarItem
|
|
158
169
|
aria-label="通知"
|
|
159
170
|
badge={unread ? 12 : undefined}
|
|
@@ -80,7 +80,9 @@ const THEME = `
|
|
|
80
80
|
[data-tenant="acme-web"] .tx-h2 { font-family: var(--font-family-display); font-weight: 800; font-size: 2.25rem;
|
|
81
81
|
line-height: 1.15; letter-spacing: -0.02em; margin: 0.75rem 0 0.625rem; color: hsl(var(--foreground)); }
|
|
82
82
|
[data-tenant="acme-web"] .tx-lead { font-size: 1.1875rem; line-height: 1.6; color: hsl(var(--muted-foreground)); max-width: 480px; }
|
|
83
|
-
|
|
83
|
+
/* --text-brand, not --primary (gh#643): --primary is a FILL role, and as ink it measured
|
|
84
|
+
2.01:1 here. The AA-safe text tier already exists and .tx-eyebrow above already reads it. */
|
|
85
|
+
[data-tenant="acme-web"] .tx-gold { color: hsl(var(--text-brand)); }
|
|
84
86
|
[data-tenant="acme-web"] .tx-stat { font-family: var(--font-family-display); font-weight: 800; font-size: 1.75rem; color: hsl(var(--primary)); }
|
|
85
87
|
[data-tenant="acme-web"] .tx-hero-grid { display: grid; gap: 3rem; align-items: center; padding-block: 6rem; }
|
|
86
88
|
@media (min-width: 1024px) { [data-tenant="acme-web"] .tx-hero-grid { grid-template-columns: 1.1fr 0.9fr; } }
|
|
@@ -283,11 +283,11 @@ export default function LoginShowcase() {
|
|
|
283
283
|
|
|
284
284
|
<Text as="p" size="2xs" tone="muted" align="center" className="leading-relaxed">
|
|
285
285
|
ログインすると{" "}
|
|
286
|
-
<Button variant="link" size="sm" className="text-[var(--font-size-2xs)]">
|
|
286
|
+
<Button variant="link" size="sm" className="text-[length:var(--font-size-2xs)]">
|
|
287
287
|
利用規約
|
|
288
288
|
</Button>{" "}
|
|
289
289
|
·{" "}
|
|
290
|
-
<Button variant="link" size="sm" className="text-[var(--font-size-2xs)]">
|
|
290
|
+
<Button variant="link" size="sm" className="text-[length:var(--font-size-2xs)]">
|
|
291
291
|
プライバシーポリシー
|
|
292
292
|
</Button>{" "}
|
|
293
293
|
に同意したものとみなされます。
|