@godxjp/ui 18.5.0 → 18.6.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/charts/compact-bar-trend.d.ts +2 -1
- package/dist/components/charts/index.d.ts +4 -1
- package/dist/components/data-display/data-table.d.ts +25 -4
- package/dist/components/data-display/data-table.js +13 -2
- package/dist/components/data-display/empty-state.js +1 -1
- package/dist/components/data-display/index.d.ts +1 -1
- package/dist/components/data-display/list-row.d.ts +19 -0
- package/dist/components/data-display/list-row.js +2 -0
- package/dist/components/data-display/qr-code.d.ts +1 -1
- package/dist/components/data-display/table.d.ts +47 -2
- package/dist/components/data-display/table.js +29 -4
- package/dist/components/data-entry/command.d.ts +10 -10
- package/dist/components/data-entry/index.d.ts +1 -0
- package/dist/components/data-entry/input-otp.d.ts +1 -0
- package/dist/components/feedback/dialog.d.ts +14 -1
- package/dist/components/feedback/dialog.js +4 -0
- package/dist/components/feedback/index.d.ts +1 -1
- package/dist/components/feedback/index.js +2 -0
- package/dist/components/general/logo.d.ts +7 -1
- package/dist/components/general/logo.js +1 -1
- package/dist/components/layout/app-shell.d.ts +1 -1
- package/dist/components/layout/app-shell.js +55 -46
- package/dist/components/layout/auth-account-summary.d.ts +5 -0
- package/dist/components/layout/auth-account-summary.js +31 -0
- package/dist/components/layout/auth-shell.d.ts +3 -2
- package/dist/components/layout/centered-shell.d.ts +1 -1
- package/dist/components/layout/centered-shell.js +28 -19
- package/dist/components/layout/error-surface.d.ts +35 -0
- package/dist/components/layout/error-surface.js +155 -0
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +4 -0
- package/dist/components/layout/index.d.ts +5 -0
- package/dist/components/layout/index.js +4 -0
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +4 -0
- package/dist/components/navigation/steps.js +38 -19
- package/dist/components/navigation/tabs.js +12 -3
- package/dist/components/ui/avatar.d.ts +2 -1
- package/dist/components/ui/avatar.js +2 -1
- package/dist/components/ui/input-otp.d.ts +4 -1
- package/dist/components/ui/input-otp.js +2 -1
- package/dist/components/ui/toggle-group.d.ts +7 -4
- package/dist/components/ui/toggle-group.js +32 -21
- package/dist/email/brand-mark.d.ts +21 -5
- package/dist/email/brand-mark.js +5 -0
- package/dist/email/color.d.ts +2 -1
- package/dist/email/geometry.d.ts +9 -1
- package/dist/email/geometry.js +1 -0
- package/dist/email/index.d.ts +6 -1
- package/dist/email/index.js +6 -0
- package/dist/email/inline-style.d.ts +7 -5
- package/dist/email/inline-style.js +5 -0
- package/dist/email/tokens.generated.d.ts +40 -20
- package/dist/email/tokens.generated.js +40 -20
- package/dist/email/urgency.d.ts +22 -0
- package/dist/email/urgency.js +14 -0
- package/dist/i18n/messages/en.json +15 -1
- package/dist/i18n/messages/ja.json +15 -1
- package/dist/i18n/messages/vi.json +15 -1
- package/dist/props/components/data-display.prop.d.ts +63 -1
- package/dist/props/components/data-entry.prop.d.ts +6 -0
- package/dist/props/components/index.d.ts +1 -1
- package/dist/props/components/layout.prop.d.ts +191 -4
- package/dist/props/components/navigation.prop.d.ts +5 -1
- package/dist/props/registry.d.ts +145 -4
- package/dist/props/registry.js +189 -5
- package/dist/props/vocabulary/data.prop.d.ts +27 -0
- package/dist/props/vocabulary/index.d.ts +3 -3
- package/dist/props/vocabulary/interaction.prop.d.ts +9 -0
- package/dist/props/vocabulary/layout.prop.d.ts +38 -7
- package/dist/styles/control.css +28 -0
- package/dist/styles/data-display-layout.css +26 -0
- package/dist/styles/layout.css +99 -0
- package/dist/styles/logo-layout.css +42 -9
- package/dist/styles/navigation-layout.css +109 -0
- package/dist/styles/shell-layout.css +302 -0
- package/dist/styles/table-layout.css +164 -1
- package/dist/theme/dxs.canonical.css +5 -4
- package/dist/tokens/axes.css +4 -3
- package/dist/tokens/base.css +1 -0
- package/dist/tokens/components/data-display.css +13 -0
- package/dist/tokens/components/email.css +43 -16
- package/dist/tokens/components/error-surface.css +36 -0
- package/dist/tokens/components/list-row.css +20 -0
- package/dist/tokens/components/logo.css +52 -10
- package/dist/tokens/components/navigation.css +15 -0
- package/dist/tokens/components/shell.css +72 -0
- package/dist/tokens/components/table.css +45 -0
- package/dist/tokens/foundation.css +26 -0
- package/dist/tokens/semantic/layout.css +25 -0
- package/package.json +8 -2
|
@@ -10,8 +10,10 @@
|
|
|
10
10
|
* string. Where a value mirrors a web token the comment names it, so a retune stays traceable.
|
|
11
11
|
*
|
|
12
12
|
* Colours are deliberately NOT redeclared here — they derive from the semantic roles
|
|
13
|
-
* (--card/--background/--foreground/--muted/--border/--primary/--ring/--
|
|
13
|
+
* (--card/--background/--foreground/--muted/--border/--primary/--ring/--brand) and are converted
|
|
14
14
|
* HSL→hex at module load, so a re-themed role re-tints the email with zero copy-paste.
|
|
15
|
+
* The identity mark reads --brand, NOT --success: --success is the wakatake status green, and the
|
|
16
|
+
* two are deliberately distinct roles (gh#250).
|
|
15
17
|
*/
|
|
16
18
|
:root {
|
|
17
19
|
/* ── Shell — the 480px transactional-email geometry ─────────────────────────────────────── */
|
|
@@ -24,31 +26,53 @@
|
|
|
24
26
|
--email-stack-gap: 24px; /* block rhythm — mirrors --space-stack-lg (1.5rem) */
|
|
25
27
|
--email-stack-gap-sm: 12px; /* tight rhythm — mirrors --space-3 (0.75rem) */
|
|
26
28
|
|
|
27
|
-
/* ── Brand
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
/* ── Brand-mark lockup — the canonical GoDX capsule + wordmark (see EMAIL_BRAND_MARK) ────── */
|
|
30
|
+
/* The mark ARTWORK is the same 32×32 capsule + glyph `<Logo mark="godx" />` paints; only the
|
|
31
|
+
* RENDERED BOX differs. The canonical SCR-302 header sets it at 22px next to a 13px/700 "GoDX"
|
|
32
|
+
* wordmark, which is smaller than the web --logo-godx-size (2rem) — an email header carries the
|
|
33
|
+
* identity, not the navigation, so the lockup sits quieter (gh#250). */
|
|
34
|
+
--email-mark-width: 22px; /* canonical SCR-302 header lockup mark box */
|
|
35
|
+
--email-mark-height: 22px;
|
|
36
|
+
--email-mark-gap: 8px; /* mark ↔ wordmark — mirrors --logo-wordmark-gap (--space-2) */
|
|
37
|
+
--email-wordmark-font-size: 13px; /* canonical wordmark size (≈ --font-size-xs 12.5px) */
|
|
38
|
+
--email-wordmark-font-weight: 700; /* mirrors --logo-wordmark-font-weight */
|
|
30
39
|
|
|
31
40
|
/* ── Typography — literal px so no client has to resolve the rem scale ──────────────────── */
|
|
41
|
+
/* The DXS canonical face is M PLUS 2 (see src/styles/fonts.css). Email clients honour NO
|
|
42
|
+
* @font-face, so the stack ships the face NAME first and degrades through the platform JP faces
|
|
43
|
+
* to a generic — a client with M PLUS 2 installed (or a webmail that already loaded it) renders
|
|
44
|
+
* the canonical face, everything else lands on Hiragino (macOS/iOS) → Yu Gothic (Windows) →
|
|
45
|
+
* Noto Sans JP → Meiryo → the system UI face → Arial → sans-serif. Family names are SINGLE-quoted
|
|
46
|
+
* on export (the generator normalises) because an inline `style="…"` attribute is double-quoted;
|
|
47
|
+
* only ASCII aliases are listed, since a non-ASCII family name does not survive every transfer
|
|
48
|
+
* encoding. */
|
|
32
49
|
--email-font-family-sans:
|
|
33
|
-
|
|
50
|
+
"M PLUS 2", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic Medium", YuGothic,
|
|
51
|
+
"Noto Sans JP", Meiryo, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, Arial,
|
|
52
|
+
sans-serif;
|
|
53
|
+
/* Tabular/reference strings — invoice ids, masked card numbers, ISO dates, amounts — are set in
|
|
54
|
+
* the mono face in the canonical card. Mirrors --font-family-mono. */
|
|
55
|
+
--email-font-family-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
34
56
|
--email-body-font-size: 14px; /* mirrors --font-size-base (0.875rem) */
|
|
35
|
-
|
|
57
|
+
/* 1.9, NOT the web --line-height-body (1.7) — the canonical email card runs its JP body copy
|
|
58
|
+
* looser than a screen, because a mail client gives the reader no density control. */
|
|
59
|
+
--email-body-line-height: 1.9;
|
|
36
60
|
--email-body-font-weight: 400; /* mirrors --font-weight-normal */
|
|
37
|
-
--email-heading-font-size:
|
|
38
|
-
--email-heading-line-height: 1.
|
|
39
|
-
--email-heading-font-weight:
|
|
61
|
+
--email-heading-font-size: 17px; /* canonical card title (≈ --heading-h2, base × φ^¼² ≈ 17.6px) */
|
|
62
|
+
--email-heading-line-height: 1.7; /* the title shares the card's body leading, not a tight ramp */
|
|
63
|
+
--email-heading-font-weight: 500; /* mirrors --font-weight-medium — an email title is calm, not bold */
|
|
40
64
|
|
|
41
65
|
/* ── Primary CTA — the one action button ────────────────────────────────────────────────── */
|
|
42
|
-
--email-cta-height:
|
|
43
|
-
--email-cta-line-height:
|
|
44
|
-
--email-cta-padding-x:
|
|
66
|
+
--email-cta-height: 36px; /* mirrors --control-height-lg (2.25rem) — the canonical CTA box */
|
|
67
|
+
--email-cta-line-height: 36px; /* equal to the height: bulletproof vertical centring in Outlook */
|
|
68
|
+
--email-cta-padding-x: 16px; /* mirrors --space-4 */
|
|
45
69
|
--email-cta-radius: 6px; /* mirrors the --radius base (0.375rem) */
|
|
46
70
|
--email-cta-font-size: 14px; /* mirrors --font-size-base */
|
|
47
|
-
--email-cta-font-weight:
|
|
71
|
+
--email-cta-font-weight: 500; /* mirrors --font-weight-medium */
|
|
48
72
|
|
|
49
73
|
/* ── Legal footer ───────────────────────────────────────────────────────────────────────── */
|
|
50
|
-
--email-footer-font-size:
|
|
51
|
-
--email-footer-line-height: 1.
|
|
74
|
+
--email-footer-font-size: 11px; /* mirrors --font-size-2xs (base ÷ φ^¼² ≈ 11.1px) */
|
|
75
|
+
--email-footer-line-height: 1.8; /* the legal band runs looser than the web --line-height-normal */
|
|
52
76
|
--email-footer-link-gap: 12px; /* horizontal separation between footer links (--space-3) */
|
|
53
77
|
--email-footer-padding-top: 20px; /* space above the legal band */
|
|
54
78
|
--email-footer-border-width: 1px; /* the hairline above the legal band */
|
|
@@ -61,6 +85,9 @@
|
|
|
61
85
|
--email-mobile-width: 100%; /* the card goes fluid below the breakpoint */
|
|
62
86
|
--email-mobile-padding: 20px; /* reduced card inset — mirrors --space-5 */
|
|
63
87
|
--email-mobile-page-padding: 12px; /* reduced viewport gutter — mirrors --space-3 */
|
|
64
|
-
|
|
88
|
+
/* One step below the 17px desktop title. The canonical 390px reference raster is unusable (it is
|
|
89
|
+
* 435px wide and already clips the card — dxs-platform/platform#496), so this is the library's
|
|
90
|
+
* documented contract rather than a measured canonical value. */
|
|
91
|
+
--email-mobile-heading-font-size: 16px;
|
|
65
92
|
--email-mobile-cta-width: 100%; /* the CTA goes full-bleed so the tap target spans the card */
|
|
66
93
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/* ErrorSurface — the 403 / 404 / 500 / 503 exception surface (gh#221, gh#251).
|
|
2
|
+
*
|
|
3
|
+
* Package-owned geometry: a service retunes the surface here (or in its own theme.css) instead of
|
|
4
|
+
* forking `.ui-error-surface` or adding a `className` to the component. Chrome defaults are QUIET
|
|
5
|
+
* (cardinal rule #44): the metadata block ships with no divider — a service opts IN.
|
|
6
|
+
*/
|
|
7
|
+
:root {
|
|
8
|
+
/* Measure of the surface block. Caps the status code + body + metadata column so a long ja/vi
|
|
9
|
+
* headline wraps at a readable width in BOTH shells, including the application shell where
|
|
10
|
+
* PageContainer is much wider than the copy wants to be. */
|
|
11
|
+
--error-surface-max-width: 32rem;
|
|
12
|
+
|
|
13
|
+
/* Rhythm between the status code, the EmptyState body, the metadata list and the progress meter. */
|
|
14
|
+
--error-surface-gap: var(--space-3);
|
|
15
|
+
|
|
16
|
+
/* Block padding of the surface inside the shell it is placed in. Desktop (1440/1024) default; the
|
|
17
|
+
* 390 step steps it down so a phone loses no vertical space (see styles/shell-layout.css). */
|
|
18
|
+
--error-surface-padding-block: var(--space-10);
|
|
19
|
+
--error-surface-padding-block-compact: var(--space-6);
|
|
20
|
+
|
|
21
|
+
/* Brand slot (a Logo) above the status code, system mode only. */
|
|
22
|
+
--error-surface-brand-gap: var(--space-2);
|
|
23
|
+
|
|
24
|
+
/* Metadata description list: row rhythm and the label↔value gap inside one row. */
|
|
25
|
+
--error-surface-meta-gap: var(--space-1);
|
|
26
|
+
--error-surface-meta-row-gap: var(--space-2);
|
|
27
|
+
|
|
28
|
+
/* Chrome, default quiet (#44). A service opts in with
|
|
29
|
+
* `--error-surface-meta-border: 1px solid hsl(var(--border));`. */
|
|
30
|
+
--error-surface-meta-border: none;
|
|
31
|
+
--error-surface-meta-padding-block: 0;
|
|
32
|
+
|
|
33
|
+
/* Width of the maintenance progress meter — narrower than the measure, so it reads as metadata
|
|
34
|
+
* rather than as the primary content of the page. */
|
|
35
|
+
--error-surface-progress-max-width: 18rem;
|
|
36
|
+
}
|
|
@@ -15,6 +15,26 @@
|
|
|
15
15
|
--list-row-body-min-width: 12rem;
|
|
16
16
|
/* Gap BETWEEN trailing actions — they also wrap among themselves at narrow widths (#224). */
|
|
17
17
|
--list-row-trailing-gap: var(--space-2);
|
|
18
|
+
/* ── Compact inline-actions geometry (`density="compact"`, #246) ──────────────────────────
|
|
19
|
+
* The canonical invitation / history row: a 36px leading avatar, a shrinkable title +
|
|
20
|
+
* description body and one or two small trailing Buttons, all on ONE line inside the canonical
|
|
21
|
+
* 358px card (326px content after the row's own inline inset) at a 390px viewport. These knobs
|
|
22
|
+
* only LOWER the geometry — the #224 wrap contract (row + trailing cluster wrap, body clamped
|
|
23
|
+
* with min(…, 100%)) is untouched, so a cluster that genuinely cannot fit still wraps instead of
|
|
24
|
+
* widening the page root.
|
|
25
|
+
* Declared `initial` so the spacing defaults re-resolve at the CALL SITE — --space-2 is
|
|
26
|
+
* density-scaled and re-declared inside a `.ui-density-*` subtree, so a :root binding would
|
|
27
|
+
* freeze compact rows at the :root density (docs/TOKENS.md — the :root freeze rule).
|
|
28
|
+
* Defaults = var(--space-2) block padding · var(--list-row-padding-x) inline padding ·
|
|
29
|
+
* var(--space-2) gap. */
|
|
30
|
+
--list-row-compact-padding-y: initial;
|
|
31
|
+
/* Inline inset defaults to the default row axis so compact and default rows in the same Card keep
|
|
32
|
+
* one optical axis; a service retunes it to its own grid (#45). */
|
|
33
|
+
--list-row-compact-padding-x: initial;
|
|
34
|
+
--list-row-compact-gap: initial;
|
|
35
|
+
/* Compact body threshold — small enough that avatar + body + two compact Buttons fit the
|
|
36
|
+
* canonical column (36 + 8 + 96 + 8 + 146 = 294 ≤ 326), and still a readable measure. */
|
|
37
|
+
--list-row-compact-body-min-width: 6rem;
|
|
18
38
|
/* Read (default) row surface — `initial`, documented default = transparent, i.e. the Card
|
|
19
39
|
* surface shows through untouched (#44 — chrome defaults to the quietest state). */
|
|
20
40
|
--list-row-read-background: initial;
|
|
@@ -12,28 +12,70 @@
|
|
|
12
12
|
--logo-font-size-sm: var(--font-size-xs);
|
|
13
13
|
--logo-font-size-md: var(--font-size-sm);
|
|
14
14
|
--logo-font-size-lg: var(--font-size-base);
|
|
15
|
-
/* Semantic identity fill
|
|
16
|
-
*
|
|
15
|
+
/* Semantic identity fill reads the --brand IDENTITY role: independent of --primary (a re-themed
|
|
16
|
+
* action colour never recolours the mark) AND of --success (the 若竹 STATUS green stays on
|
|
17
|
+
* badges/progress/"saved" text — the mark used to borrow it and rendered ΔE76 ≈ 17.5 off the
|
|
18
|
+
* canonical emerald, gh#250). Services retune the role once for every Logo.
|
|
17
19
|
* ROLE-MIRROR KNOBS — declared `initial` here with the role default at the CALL SITE
|
|
18
|
-
* (logo-layout.css), so a scoped `.dark` / `[data-tenant]` override of --
|
|
20
|
+
* (logo-layout.css), so a scoped `.dark` / `[data-tenant]` override of --brand actually
|
|
19
21
|
* reaches the mark instead of freezing at the :root value (docs/TOKENS.md ·
|
|
20
22
|
* "Role-mirror knobs MUST be `initial`"). Documented defaults:
|
|
21
|
-
* --logo-success-background = hsl(var(--
|
|
22
|
-
* --logo-success-foreground = hsl(var(--
|
|
23
|
-
* --logo-godx-color = hsl(var(--
|
|
23
|
+
* --logo-success-background = hsl(var(--brand))
|
|
24
|
+
* --logo-success-foreground = hsl(var(--logo-identity-foreground))
|
|
25
|
+
* --logo-godx-color = hsl(var(--brand)) */
|
|
24
26
|
--logo-success-background: initial;
|
|
25
27
|
--logo-success-foreground: initial;
|
|
26
|
-
--logo-godx-size: 2rem;
|
|
27
28
|
--logo-godx-color: initial;
|
|
28
29
|
|
|
30
|
+
/* Identity-fill INK — the ink `mark="glyph"` sets its (caller-supplied) TEXT in when it sits on
|
|
31
|
+
* the --brand identity fill. This is deliberately NOT --brand-foreground.
|
|
32
|
+
*
|
|
33
|
+
* --brand-foreground is the identity artwork's KNOCKOUT colour, not an ink: it tracks
|
|
34
|
+
* --background in both themes (light 60 33% 99% = --background; dark 48 9% 9% = --background)
|
|
35
|
+
* because `<Logo mark="godx">` punches its inner bar as an evenodd HOLE and the email mark has to
|
|
36
|
+
* paint that hole as a solid fill to match. Negative space only has to clear WCAG 2.2 SC 1.4.11
|
|
37
|
+
* (3:1, non-text) — and at 3.67:1 on the emerald it does.
|
|
38
|
+
*
|
|
39
|
+
* The boxed glyph is a different thing: it renders real TEXT, so SC 1.4.3 applies at 4.5:1 (14px
|
|
40
|
+
* bold is NOT "large text" — that needs 18.66px bold / 24px), and the knockout white measured
|
|
41
|
+
* 3.67:1 → a genuine AA failure. This ink is 48 9% 9% (#191815), the same near-black spine the
|
|
42
|
+
* DARK theme already inked the glyph with, so it is theme-INVARIANT: dark renders byte-identically
|
|
43
|
+
* (6.89:1, unchanged) and light rises 3.67 → 4.74:1. A service that re-themes --brand to a dark
|
|
44
|
+
* fill overrides --logo-success-foreground (the public knob) to re-invert the ink.
|
|
45
|
+
*
|
|
46
|
+
* NOT a role-mirror knob: its default is a real value, not a role token, so there is no role to
|
|
47
|
+
* freeze at :root and the `initial` + call-site rule (docs/TOKENS.md) does not apply to it. */
|
|
48
|
+
--logo-identity-foreground: 48 9% 9%;
|
|
49
|
+
|
|
50
|
+
/* ── Identity-mark box (`<Logo mark="godx" />`) ──────────────────────────────────────────────
|
|
51
|
+
* The `size` prop drives the identity mark exactly like it drives the boxed glyph — a public
|
|
52
|
+
* prop that renders identically at every tier is a silent no-op, and the godx LOCKUP already
|
|
53
|
+
* scaled its wordmark per tier, so a fixed mark broke the mark↔wordmark proportion at
|
|
54
|
+
* `size="lg"` (gh#163 follow-up). The godx artwork is a horizontal capsule inside a square
|
|
55
|
+
* viewBox, so it carries less optical weight than the fully-filled glyph box: each tier sits
|
|
56
|
+
* +0.25rem above its --logo-size-* sibling. `md` is 2rem — the historical fixed value — so
|
|
57
|
+
* every existing default-size identity surface renders byte-identically.
|
|
58
|
+
*
|
|
59
|
+
* --logo-godx-size is the PIN: declared `initial` (guaranteed-invalid) here with the per-tier
|
|
60
|
+
* default at the CALL SITE (logo-layout.css), so it is inert by default and a service that
|
|
61
|
+
* sets it once freezes the mark at that box on EVERY tier — the same call-site pattern the
|
|
62
|
+
* role-mirror colour knobs use (docs/TOKENS.md). Retune a single tier via --logo-godx-size-*.
|
|
63
|
+
* Documented default: --logo-godx-size = unset (tiers apply). */
|
|
64
|
+
--logo-godx-size-xs: 1.5rem;
|
|
65
|
+
--logo-godx-size-sm: 1.75rem;
|
|
66
|
+
--logo-godx-size-md: 2rem;
|
|
67
|
+
--logo-godx-size-lg: 2.5rem;
|
|
68
|
+
--logo-godx-size: initial;
|
|
69
|
+
|
|
29
70
|
/* ── Wordmark / lockup (`<Logo wordmark="GoDX" />`) ─────────────────────────────────────────
|
|
30
71
|
* The readable product name set beside the mark. The package ships NO wordmark artwork: the
|
|
31
72
|
* wordmark is typeset in the design-system display face, so a service retunes face, weight,
|
|
32
73
|
* tracking, size and the mark↔wordmark gap here instead of writing page CSS. The colour is a
|
|
33
|
-
* role-mirror knob whose default is the IDENTITY role (never --primary
|
|
34
|
-
* lockup is
|
|
74
|
+
* role-mirror knob whose default is the IDENTITY role --brand (never --primary, never the
|
|
75
|
+
* --success status green): the GoDX/`success` lockup is canonical emerald out of the box, and
|
|
76
|
+
* every other lockup reads --foreground.
|
|
35
77
|
* Documented defaults: --logo-wordmark-font-family = var(--font-family-display);
|
|
36
|
-
* --logo-wordmark-color = hsl(var(--foreground)), or hsl(var(--
|
|
78
|
+
* --logo-wordmark-color = hsl(var(--foreground)), or hsl(var(--brand)) on the
|
|
37
79
|
* godx / tone="success" lockup. */
|
|
38
80
|
--logo-wordmark-gap: var(--space-2);
|
|
39
81
|
--logo-wordmark-font-size-xs: var(--font-size-xs);
|
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
--filter-label-font-size: var(--font-size-xs);
|
|
11
11
|
--filter-picker-width-sm: 11rem;
|
|
12
12
|
--filter-picker-width-md: 14rem;
|
|
13
|
+
--steps-inline-gap: var(--space-2);
|
|
14
|
+
--steps-inline-item-gap: var(--space-1);
|
|
15
|
+
--steps-inline-font-size: var(--font-size-xs);
|
|
16
|
+
--steps-inline-separator-size: var(--control-icon-size-sm);
|
|
13
17
|
|
|
14
18
|
/* AppSettingPicker `compact` (gh#217) — the small, content-hugging labelled trigger used in an
|
|
15
19
|
* auth/legal footer, where the square icon-only default reads as a stray button and the full
|
|
@@ -24,6 +28,17 @@
|
|
|
24
28
|
--tabs-list-max-inline-size: 100%;
|
|
25
29
|
--tabs-list-overflow: auto;
|
|
26
30
|
|
|
31
|
+
/* Tabs `line` active indicator (gh#248) — the ONLY selected-state decoration the line variant
|
|
32
|
+
* paints. The surrounding active ring belongs to the default/card lists, so `:focus-visible`
|
|
33
|
+
* keeps its own distinct keyboard ring here (WCAG 2.4.7). `--tabs-indicator-background` is a
|
|
34
|
+
* role-mirror knob: `initial` so hsl(var(--primary)) re-resolves at the CALL SITE under a scoped
|
|
35
|
+
* [data-tenant]/.dark theme (a :root binding to a role var would freeze at :root).
|
|
36
|
+
* Default = hsl(var(--primary)) · 2px thick · flush with the trigger edge (offset 0 = quietest,
|
|
37
|
+
* rule #44); a service raises the offset to park the bar on a thicker strip hairline. */
|
|
38
|
+
--tabs-indicator-background: initial;
|
|
39
|
+
--tabs-indicator-size: 2px;
|
|
40
|
+
--tabs-indicator-offset: 0px;
|
|
41
|
+
|
|
27
42
|
/* Menu item hover/highlight tint — `initial` so the --accent default re-resolves at the call site
|
|
28
43
|
* under a scoped theme (a :root binding to a role var freezes at :root).
|
|
29
44
|
* Defaults = hsl(var(--accent)) fill · hsl(var(--accent-foreground)) text. */
|
|
@@ -54,6 +54,15 @@
|
|
|
54
54
|
--sidebar-brand-mark-size: 1.375rem;
|
|
55
55
|
--sidebar-nav-item-height: 2rem;
|
|
56
56
|
--sidebar-nav-item-font-size: 0.8125rem;
|
|
57
|
+
/* Line box of the nav LABEL, not the row (gh#254): `.sb-label` clips, so its line box is its clip
|
|
58
|
+
* box, and the row's `line-height: 1` shears descenders and Vietnamese tone marks. Keep >= 1.2. */
|
|
59
|
+
--sidebar-nav-item-line-height: 1.5;
|
|
60
|
+
/* Same gh#254 trap, two more clipping boxes. `.ui-auth-account-email` and the truncating last
|
|
61
|
+
* child of `.ui-topbar-start` both clip (`overflow: hidden`/`clip` + `text-overflow: ellipsis`),
|
|
62
|
+
* so their line box IS their clip box — inheriting a tight value shears descenders and Vietnamese
|
|
63
|
+
* tone marks exactly as the sidebar label did. Keep >= 1.2. */
|
|
64
|
+
--auth-account-summary-email-line-height: 1.5;
|
|
65
|
+
--topbar-start-truncate-line-height: 1.5;
|
|
57
66
|
--sidebar-nav-icon-size: 1rem;
|
|
58
67
|
--sidebar-nav-item-gap: 0.625rem;
|
|
59
68
|
--sidebar-nav-item-padding-x: 0.625rem;
|
|
@@ -72,6 +81,11 @@
|
|
|
72
81
|
--topbar-height: auto;
|
|
73
82
|
--topbar-inset: 0px;
|
|
74
83
|
--topbar-gap: var(--space-2);
|
|
84
|
+
/* At compact desktop/tablet widths the docked sidebar leaves too little inline room for three
|
|
85
|
+
* intrinsically-sized clusters. The package hides the optional center slot before it can cover
|
|
86
|
+
* the breadcrumb/title or end utilities. Consumers may opt back into another display strategy
|
|
87
|
+
* (for example `flex`) once their center content has its own compact presentation. */
|
|
88
|
+
--topbar-center-compact-display: none;
|
|
75
89
|
--org-switcher-trigger-height: 2.75rem;
|
|
76
90
|
--org-switcher-trigger-padding-x: var(--space-2);
|
|
77
91
|
--org-switcher-avatar-size: 1.75rem;
|
|
@@ -144,6 +158,24 @@
|
|
|
144
158
|
* (quiet, rule #44) so an existing single-card consumer is untouched; presets opt in. */
|
|
145
159
|
--auth-shell-card-stack-gap: 0px;
|
|
146
160
|
|
|
161
|
+
/* Login preset (gh#237) — canonical SCR-001 anchors at 1440x900, 1024x900 and 390x844.
|
|
162
|
+
* The 112px identity slot is deliberately taller than a two-line real requester. Identity
|
|
163
|
+
* content aligns to the slot end, so missing/one-line/two-line requester data changes only the
|
|
164
|
+
* empty space above it, never the card or footer position. The flow starts at y=231 desktop and
|
|
165
|
+
* y=221 mobile: 231/221 + 112 + 20 gap = card y=363/353. Literal artboard lengths belong here,
|
|
166
|
+
* not in a consumer selector, and do not drift with --scaling. */
|
|
167
|
+
--auth-shell-login-card-max-width: 22.5rem;
|
|
168
|
+
--auth-shell-login-flow-offset-block: 14.4375rem;
|
|
169
|
+
--auth-shell-login-flow-offset-block-mobile: 13.8125rem;
|
|
170
|
+
--auth-shell-login-main-padding-inline: 1rem;
|
|
171
|
+
--auth-shell-login-main-padding-inline-mobile: 0.9375rem;
|
|
172
|
+
--auth-shell-login-main-padding-block-end: 1rem;
|
|
173
|
+
--auth-shell-login-identity-slot-block-size: 7rem;
|
|
174
|
+
--auth-shell-login-card-stack-gap: 1.25rem;
|
|
175
|
+
--auth-shell-login-card-padding-block-compact: calc(
|
|
176
|
+
var(--auth-shell-compact-card-inset) + var(--control-border-width) + var(--control-border-width)
|
|
177
|
+
);
|
|
178
|
+
|
|
147
179
|
/* Device-authorization preset — 380px card measure, 15px block · 5px inline mobile gutter
|
|
148
180
|
* (at a 390px viewport the card is x=5px, width=380px). */
|
|
149
181
|
--auth-shell-device-card-max-width: 23.75rem;
|
|
@@ -178,6 +210,13 @@
|
|
|
178
210
|
--auth-requester-gap: 0.375rem;
|
|
179
211
|
--auth-requester-icon-size: 1rem;
|
|
180
212
|
--auth-requester-glyph-size: 0.625rem;
|
|
213
|
+
--auth-account-summary-min-height: var(--control-height-comfortable);
|
|
214
|
+
--auth-account-summary-gap: var(--space-2);
|
|
215
|
+
--auth-account-summary-padding: var(--space-1) var(--space-2);
|
|
216
|
+
--auth-account-summary-identity-min-width: 12rem;
|
|
217
|
+
--auth-account-summary-avatar-size: var(--control-height-sm);
|
|
218
|
+
--auth-account-summary-avatar-glyph-size: var(--control-icon-size-sm);
|
|
219
|
+
--auth-account-summary-email-font-size: var(--font-size-sm);
|
|
181
220
|
--auth-footer-content-gap: 0.375rem;
|
|
182
221
|
--auth-footer-text-font-size: 0.6875rem;
|
|
183
222
|
--auth-stack-gap: var(--space-3);
|
|
@@ -203,3 +242,36 @@
|
|
|
203
242
|
--centered-shell-width-md: 46rem;
|
|
204
243
|
--centered-shell-width-lg: 64rem;
|
|
205
244
|
}
|
|
245
|
+
|
|
246
|
+
/* CenteredShell · public-landing preset (gh#252) — the token-owned geometry of a PUBLIC marketing
|
|
247
|
+
* / product landing page: one content measure shared by header, main column and footer, the
|
|
248
|
+
* section rhythm between page sections, the flat (chrome-quiet) card presentation and the hero
|
|
249
|
+
* heading tier. Every value is a service-themeable knob (rule #45): a landing composition is a
|
|
250
|
+
* COMPOSITION of real primitives (docs/COMPOSITION-VS-COMPONENT.md — Hero/Navbar/Footer FAIL the
|
|
251
|
+
* Framework-Component Test), so the consumer must never own geometry or a media query. These
|
|
252
|
+
* knobs are read ONLY under `.ui-centered-shell[data-preset="public-landing"]`, so the default
|
|
253
|
+
* shell — which emits no `data-preset` at all — is byte-identical to before. */
|
|
254
|
+
:root {
|
|
255
|
+
--centered-shell-landing-max-width: 67.5rem; /* 1080px — header/main/footer share ONE measure */
|
|
256
|
+
--centered-shell-landing-inset-inline: var(--space-6); /* 24px page gutter ≥ 40rem */
|
|
257
|
+
--centered-shell-landing-inset-inline-compact: var(--space-4); /* 16px page gutter < 40rem */
|
|
258
|
+
--centered-shell-landing-main-padding-block: var(--space-10); /* 40px */
|
|
259
|
+
--centered-shell-landing-main-padding-block-compact: var(--space-6); /* 24px */
|
|
260
|
+
--centered-shell-landing-section-gap: var(--space-10); /* rhythm BETWEEN page sections */
|
|
261
|
+
--centered-shell-landing-section-gap-compact: var(--space-6);
|
|
262
|
+
--centered-shell-landing-footer-padding-block: var(--space-8);
|
|
263
|
+
/* Chrome is a token, default quiet (rule #44): a landing surface is FLAT — no card elevation —
|
|
264
|
+
* so a service opts back IN with `--centered-shell-landing-card-shadow: var(--card-shadow)`. */
|
|
265
|
+
--centered-shell-landing-card-shadow: none;
|
|
266
|
+
/* Hero heading tier. The preset re-points `--heading-h1` (same mechanism as
|
|
267
|
+
* `.ui-auth-shell` → `--auth-shell-heading-size`), so a hero title is a real `Heading level={1}`
|
|
268
|
+
* and never a consumer font-size. */
|
|
269
|
+
--centered-shell-landing-heading-size: var(--font-size-display);
|
|
270
|
+
--centered-shell-landing-heading-size-compact: var(--font-size-3xl);
|
|
271
|
+
/* Role-mirror knob — MUST stay `initial`, with the role default at the CALL SITE
|
|
272
|
+
* (`var(--centered-shell-landing-background, var(--background))`), so a scoped
|
|
273
|
+
* `[data-tenant]` / `.dark` override of `--background` still reaches it (docs/TOKENS.md ·
|
|
274
|
+
* "Role-mirror knobs MUST be `initial`"). Documented default = hsl(var(--background)) — a public
|
|
275
|
+
* page is the plain page canvas, not the app's `--muted` chrome. */
|
|
276
|
+
--centered-shell-landing-background: initial;
|
|
277
|
+
}
|
|
@@ -7,6 +7,29 @@
|
|
|
7
7
|
--table-row-height: calc(var(--table-row-height-default) * var(--scaling));
|
|
8
8
|
--table-cell-padding-y: var(--space-2);
|
|
9
9
|
--table-cell-space-x: var(--control-padding-x);
|
|
10
|
+
/* Pagination footer inset (gh#236). The footer ships as a SELF-CONTAINED slot and is commonly
|
|
11
|
+
* placed in a flush container (`<Card><CardContent flush><DataTable/>`), where no ancestor
|
|
12
|
+
* supplies padding — so it owns its own on BOTH axes instead of declaring block-start only.
|
|
13
|
+
* Block default = the previous single `padding-top` value, now on both block edges (breathing
|
|
14
|
+
* room above the footer and before the container's closing border). Inline default = the cell
|
|
15
|
+
* inline padding, so the "rows per page" label sits on the same optical axis as the first
|
|
16
|
+
* column's text. A service retunes either axis to its own grid (#45).
|
|
17
|
+
* Both are declared `initial` so the defaults re-resolve at the CALL SITE: --space-stack-sm and
|
|
18
|
+
* --table-cell-space-x are density-scaled and re-declared inside a `.ui-density-*` subtree, and a
|
|
19
|
+
* :root binding would freeze the footer at the :root density (docs/TOKENS.md — the :root freeze
|
|
20
|
+
* rule). Defaults = var(--space-stack-sm) block · var(--table-cell-space-x) inline. */
|
|
21
|
+
--table-pagination-padding-y: initial;
|
|
22
|
+
--table-pagination-padding-x: initial;
|
|
23
|
+
/* DataTable surface — narrow-viewport legibility FLOOR (gh#253). Below the `sm` viewport step a
|
|
24
|
+
* multi-column admin grid whose columns are `white-space: nowrap` would otherwise be crushed, so
|
|
25
|
+
* the bordered surface keeps a minimum inline size and `.ui-data-table-scroll` scrolls instead.
|
|
26
|
+
* This shipped as a hard-coded `min-w-[640px]` utility on the surface element, which left a
|
|
27
|
+
* service that wants a narrower (or no) floor with no route but forking the component (#45).
|
|
28
|
+
* Default = the previous literal, in px so the floor releases at EXACTLY the same width as the
|
|
29
|
+
* px-based `sm` media query that clears it (a rem value would drift under a non-16px root and
|
|
30
|
+
* re-introduce the scroll between the two thresholds). Set `0` to opt out entirely — which is
|
|
31
|
+
* what `preset="action-collection"` does, because there the priority measures own the width. */
|
|
32
|
+
--table-surface-min-inline-size: 640px;
|
|
10
33
|
--table-head-font-size: var(--font-size-xs);
|
|
11
34
|
/* Header band — its OWN bg + fg knobs (decoupled from --secondary). Declared `initial` so the
|
|
12
35
|
* default re-resolves to the LIVE --muted / --muted-foreground roles at the call site: a :root
|
|
@@ -24,3 +47,25 @@
|
|
|
24
47
|
--table-row-hover-background: initial;
|
|
25
48
|
--table-row-selected-background: initial;
|
|
26
49
|
}
|
|
50
|
+
|
|
51
|
+
/* Table · action-collection preset (gh#253) — the canonical dense approval / action queue.
|
|
52
|
+
* Column PRIORITY measures replace the desktop intrinsic widths (a nowrap free-text column is
|
|
53
|
+
* what makes a five-column queue wider than its card and forces a horizontal scroll). Nothing
|
|
54
|
+
* here is read unless `preset="action-collection"` is set, so every existing table is untouched.
|
|
55
|
+
* Percentages so the ratio holds at any card width; the action affordance is an absolute measure
|
|
56
|
+
* because it must never be squeezed below its touch target. */
|
|
57
|
+
:root {
|
|
58
|
+
--table-action-collection-primary-width: 18%; /* requester / subject */
|
|
59
|
+
--table-action-collection-secondary-width: 22%; /* target / resource */
|
|
60
|
+
--table-action-collection-meta-width: 12%; /* timestamps, ids — lowest priority */
|
|
61
|
+
--table-action-collection-actions-width: 3.5rem; /* row-action affordance, never clipped */
|
|
62
|
+
/* Compact tier, applied below the collapse step (the 390px acceptance frame). */
|
|
63
|
+
--table-action-collection-primary-width-compact: 24%;
|
|
64
|
+
--table-action-collection-secondary-width-compact: 22%;
|
|
65
|
+
--table-action-collection-meta-width-compact: 20%;
|
|
66
|
+
--table-action-collection-actions-width-compact: 2.75rem;
|
|
67
|
+
--table-action-collection-font-size-compact: var(--font-size-xs);
|
|
68
|
+
--table-action-collection-cell-space-x-compact: var(--space-2);
|
|
69
|
+
--table-action-collection-cell-padding-y-compact: var(--space-2);
|
|
70
|
+
--table-action-collection-row-height-compact: var(--table-row-height-compact);
|
|
71
|
+
}
|
|
@@ -31,6 +31,25 @@
|
|
|
31
31
|
--attention: 25 99% 46%; /* 朱 #eb6101 */
|
|
32
32
|
--attention-foreground: 60 33% 99%;
|
|
33
33
|
|
|
34
|
+
/* IDENTITY role — the canonical GoDX emerald. This is the PRODUCT MARK colour (Logo `mark="godx"`
|
|
35
|
+
* / `tone="success"`, its wordmark, the email brand capsule), and it is deliberately THREE-WAY
|
|
36
|
+
* distinct:
|
|
37
|
+
* · from --primary — a service re-theming its action colour must never recolour the mark;
|
|
38
|
+
* · from --success — 若竹 #68be8d is the STATUS green (badges, progress, "saved" text) and
|
|
39
|
+
* stays exactly as it is. The mark previously borrowed it, which rendered
|
|
40
|
+
* the identity at #69bf8e instead of the canonical emerald — ΔE76 ≈ 17.5,
|
|
41
|
+
* a plainly wrong brand colour (gh#250/#214);
|
|
42
|
+
* · from --text-brand / --color-brand — those are the BLUE brand-numeral TEXT slot and the
|
|
43
|
+
* Tailwind `text-brand` utility it feeds; unrelated, and not renamed here.
|
|
44
|
+
* Canonical value: oklch(0.595 0.137 162.94) = #009766, "kept distinct from SmartHR primary".
|
|
45
|
+
* The triplet is carried at one decimal so hsl() lands on that exact hex (an integer 160 100% 30%
|
|
46
|
+
* would drift to #009966). Dark lifts lightness only — same hue, same full chroma — so the mark
|
|
47
|
+
* stays the same emerald while clearing AA against the dark spine.
|
|
48
|
+
* There is no Tailwind `bg-brand` utility on purpose: `--color-brand` is already taken by
|
|
49
|
+
* --text-brand, so identity surfaces read `hsl(var(--brand))` directly in component CSS. */
|
|
50
|
+
--brand: 160.5 100% 29.6%; /* 翠 GoDX emerald #009766 */
|
|
51
|
+
--brand-foreground: 60 33% 99%;
|
|
52
|
+
|
|
34
53
|
/* Extended text hierarchy (beyond --foreground / --muted-foreground) — themeable per service.
|
|
35
54
|
* Roles primitives bake in today: caption/meta, disabled, inline link, brand numerals. */
|
|
36
55
|
--text-tertiary: 44 5% 55%; /* lighter than muted-foreground — captions / meta */
|
|
@@ -380,6 +399,13 @@
|
|
|
380
399
|
--attention: 25 95% 56%;
|
|
381
400
|
--attention-foreground: 48 9% 9%;
|
|
382
401
|
|
|
402
|
+
/* IDENTITY (dark) — the SAME canonical emerald hue/chroma, lifted 29.6% → 36% lightness so the
|
|
403
|
+
* mark reads off the warm near-black spine (#00b87c: 6.9:1 on --background, 6.3:1 on --card;
|
|
404
|
+
* the unlifted #009766 sat at 4.4:1 on the card). The on-fill glyph flips dark, exactly like
|
|
405
|
+
* --success-foreground does. */
|
|
406
|
+
--brand: 160.5 100% 36%; /* #00b87c */
|
|
407
|
+
--brand-foreground: 48 9% 9%;
|
|
408
|
+
|
|
383
409
|
/* Extended text hierarchy + interaction ramp (dark) */
|
|
384
410
|
--text-tertiary: 44 6% 56%;
|
|
385
411
|
--text-disabled: 45 6% 40%;
|
|
@@ -83,6 +83,21 @@
|
|
|
83
83
|
* page moves. 11rem = 176px, i.e. the control ends flush with the compact page gutter. */
|
|
84
84
|
--page-header-extra-measure: 11rem; /* 176px */
|
|
85
85
|
|
|
86
|
+
/* Bounded page MEASURE (gh#245 / gh#247) — the shared inline cap applied to the page HEADER and
|
|
87
|
+
* BODY together, so the header `extra` action ends on the same edge as the body surface (the
|
|
88
|
+
* `variant="narrow"` complaint: it caps only `.ui-page-body`, leaving the header action out at
|
|
89
|
+
* the page edge). Selected by the semantic `measure` prop; `measure="default"` reads NEITHER
|
|
90
|
+
* token, so an existing page is untouched.
|
|
91
|
+
*
|
|
92
|
+
* These are OUTER measures: the page gutters (--space-page-active-x, 24px each side by default)
|
|
93
|
+
* live INSIDE the cap, so the VISIBLE surface is the measure minus both gutters:
|
|
94
|
+
* narrow 42rem = 672px → 624px visible surface (the historical variant="narrow" body width)
|
|
95
|
+
* medium 48rem = 768px → 720px visible surface (the canonical readable/feed measure)
|
|
96
|
+
* Below the cap nothing binds, so a 390px viewport stays fluid at the 16px compact gutter
|
|
97
|
+
* (358px surface). A service theme retunes both in ONE place; never a page-local max-width. */
|
|
98
|
+
--page-measure-narrow: 42rem; /* 672px outer → 624px surface */
|
|
99
|
+
--page-measure-medium: 48rem; /* 768px outer → 720px surface */
|
|
100
|
+
|
|
86
101
|
/* Responsive page typography is independent from density. Density changes information spacing;
|
|
87
102
|
* these tokens change only page chrome so mobile keeps readable body text and touch targets. */
|
|
88
103
|
--page-title-font-size: var(--heading-h1);
|
|
@@ -104,3 +119,13 @@
|
|
|
104
119
|
* whole system stays in sync (gh feedback: Descriptions was ~0px while FormField was 8px). */
|
|
105
120
|
--field-label-gap: var(--space-2); /* 8px */
|
|
106
121
|
}
|
|
122
|
+
|
|
123
|
+
/* Canonical admin collection composition. Services may retune these semantic knobs once. */
|
|
124
|
+
:root {
|
|
125
|
+
--admin-collection-control-height: var(--control-height-default);
|
|
126
|
+
--admin-collection-section-gap: var(--space-stack-md);
|
|
127
|
+
--admin-collection-toolbar-padding-y: 0px;
|
|
128
|
+
--admin-collection-search-measure: 20rem;
|
|
129
|
+
--admin-collection-table-row-height: var(--table-row-height-default);
|
|
130
|
+
--admin-collection-table-cell-padding-y: var(--space-1);
|
|
131
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@godxjp/ui",
|
|
3
|
-
"version": "18.
|
|
4
|
-
"godxUiMcp": "18.
|
|
3
|
+
"version": "18.6.0",
|
|
4
|
+
"godxUiMcp": "18.6.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@10.29.1",
|
|
7
7
|
"pnpm": {
|
|
@@ -66,6 +66,10 @@
|
|
|
66
66
|
"types": "./dist/components/charts/index.d.ts",
|
|
67
67
|
"import": "./dist/components/charts/index.js"
|
|
68
68
|
},
|
|
69
|
+
"./charts/compact-bar-trend": {
|
|
70
|
+
"types": "./dist/components/charts/compact-bar-trend.d.ts",
|
|
71
|
+
"import": "./dist/components/charts/compact-bar-trend.js"
|
|
72
|
+
},
|
|
69
73
|
"./ui": {
|
|
70
74
|
"types": "./dist/components/ui/index.d.ts",
|
|
71
75
|
"import": "./dist/components/ui/index.js"
|
|
@@ -291,6 +295,8 @@
|
|
|
291
295
|
"format": "prettier --check .",
|
|
292
296
|
"format:fix": "prettier --write .",
|
|
293
297
|
"test": "vitest run",
|
|
298
|
+
"test:visual:auth-login": "node scripts/auth-shell-login-visual.mjs",
|
|
299
|
+
"test:visual:topbar-collision": "node scripts/topbar-collision-visual.mjs",
|
|
294
300
|
"test:watch": "vitest",
|
|
295
301
|
"test:coverage": "vitest run --coverage",
|
|
296
302
|
"check:example-imports": "node scripts/check-example-imports.mjs",
|