@godxjp/ui 23.0.0 → 23.2.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/app/date-format-labels.d.ts +14 -2
- package/dist/app/date-format-labels.js +1 -1
- package/dist/app/date-formats.d.ts +14 -2
- package/dist/app/date-formats.js +9 -2
- package/dist/components/data-display/card.d.ts +45 -2
- package/dist/components/data-display/card.js +4 -2
- package/dist/components/data-display/data-table.d.ts +8 -1
- package/dist/components/data-display/data-table.js +9 -2
- package/dist/components/data-display/feature-list.d.ts +26 -0
- package/dist/components/data-display/feature-list.js +29 -0
- package/dist/components/data-display/index.d.ts +6 -0
- package/dist/components/data-display/index.js +6 -0
- package/dist/components/data-display/swatch.d.ts +24 -0
- package/dist/components/data-display/swatch.js +19 -0
- package/dist/components/data-display/thumbnail.d.ts +37 -0
- package/dist/components/data-display/thumbnail.js +20 -0
- package/dist/components/data-entry/checkbox.js +1 -1
- package/dist/components/data-entry/form-field.js +2 -2
- package/dist/components/data-entry/input.js +1 -1
- package/dist/components/data-entry/number-input.js +27 -6
- package/dist/components/data-entry/radio.js +1 -1
- package/dist/components/data-entry/switch.js +1 -1
- package/dist/components/feedback/dialog.js +2 -2
- package/dist/components/feedback/index.d.ts +2 -2
- package/dist/components/feedback/index.js +19 -1
- package/dist/components/feedback/sheet.js +2 -22
- package/dist/components/feedback/skeleton.d.ts +33 -3
- package/dist/components/feedback/skeleton.js +154 -3
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +17 -5
- package/dist/components/layout/sidebar.js +9 -2
- package/dist/components/navigation/filter-bar.js +2 -1
- package/dist/components/navigation/tabs-scroll.d.ts +27 -0
- package/dist/components/navigation/tabs-scroll.js +36 -1
- package/dist/components/navigation/tabs.d.ts +2 -2
- package/dist/components/navigation/tabs.js +60 -16
- package/dist/i18n/messages/en.json +10 -1
- package/dist/i18n/messages/ja.json +10 -1
- package/dist/i18n/messages/vi.json +10 -1
- package/dist/lib/breakpoint-token.d.ts +8 -0
- package/dist/lib/breakpoint-token.js +29 -0
- package/dist/props/components/data-display.prop.d.ts +101 -1
- package/dist/props/components/feedback.prop.d.ts +85 -1
- package/dist/props/components/layout.prop.d.ts +72 -1
- package/dist/props/components/navigation.prop.d.ts +80 -2
- package/dist/props/registry.d.ts +124 -1
- package/dist/props/registry.js +140 -0
- package/dist/props/vocabulary/data.prop.d.ts +5 -0
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/styles/alert-layout.css +139 -0
- package/dist/styles/card-layout.css +48 -0
- package/dist/styles/control.css +41 -5
- package/dist/styles/data-display-layout.css +88 -0
- package/dist/styles/focus-ring.css +28 -0
- package/dist/styles/form-layout.css +4 -0
- package/dist/styles/layout.css +2 -1
- package/dist/styles/navigation-layout.css +89 -5
- package/dist/styles/shell-layout.css +22 -0
- package/dist/styles/table-layout.css +5 -2
- package/dist/tokens/components/card.css +2 -0
- package/dist/tokens/components/control.css +8 -3
- package/dist/tokens/components/data-display.css +23 -0
- package/dist/tokens/components/feedback.css +18 -0
- package/dist/tokens/components/navigation.css +4 -0
- package/dist/tokens/foundation.css +18 -16
- package/docs/CONSUMER-RULES.md +8 -3
- package/docs/CUSTOMER-THEMING.md +18 -8
- package/docs/DATETIME.md +11 -2
- package/docs/DESIGN-AUTHORITY.md +2 -1
- package/docs/FRAME-COVERAGE-REPORT.md +29 -3
- package/docs/SPACING.md +35 -5
- package/docs/TOKENS.md +1 -1
- package/docs/assets/shot-landscape.svg +12 -0
- package/docs/assets/shot-portrait.svg +10 -0
- package/docs/data-display/card/index.tsx +40 -0
- package/docs/data-display/data-table/index.tsx +17 -2
- package/docs/data-display/feature-list.tsx +159 -0
- package/docs/data-display/swatch.tsx +107 -0
- package/docs/data-display/table.tsx +1 -1
- package/docs/data-display/thumbnail.tsx +128 -0
- package/docs/data-entry/segmented-in-filter-row.tsx +77 -0
- package/docs/feedback/skeleton.tsx +57 -0
- package/docs/layout/flex.tsx +29 -0
- package/docs/layout/sidebar.tsx +66 -10
- package/docs/navigation/dropdown-menu.tsx +4 -4
- package/docs/navigation/tabs.tsx +131 -0
- package/docs/roadmap/ai-chat-components.md +1 -2
- package/docs/roadmap/tree-components.md +0 -1
- package/package.json +12 -21
- package/scripts/_agent-setup.mjs +18 -0
- package/scripts/consumer-rule.md +16 -0
- package/scripts/guinea-pig-skill.md +12 -6
- package/scripts/ui-audit.mjs +184 -7
|
@@ -238,6 +238,24 @@
|
|
|
238
238
|
--phi-0: var(--phi-unit);
|
|
239
239
|
--phi-p1: calc(var(--phi-unit) * var(--ratio-phi));
|
|
240
240
|
--phi-p2: calc(var(--phi-p1) * var(--ratio-phi));
|
|
241
|
+
|
|
242
|
+
--duration-fast: 150ms;
|
|
243
|
+
--duration-base: 250ms;
|
|
244
|
+
--duration-slow: 500ms;
|
|
245
|
+
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
|
246
|
+
--ease-emphasized: cubic-bezier(0.32, 0.72, 0, 1);
|
|
247
|
+
--ease-decelerate: cubic-bezier(0, 0, 0, 1);
|
|
248
|
+
--ease-accelerate: cubic-bezier(0.3, 0, 1, 1);
|
|
249
|
+
--reveal-distance: 10px;
|
|
250
|
+
|
|
251
|
+
--reveal-stagger-step: 60ms;
|
|
252
|
+
|
|
253
|
+
--duration-loop: 1400ms;
|
|
254
|
+
|
|
255
|
+
--activity-interval: var(--duration-loop);
|
|
256
|
+
|
|
257
|
+
--activity-stagger-step: 160ms;
|
|
258
|
+
|
|
241
259
|
}
|
|
242
260
|
|
|
243
261
|
.ui-scale-fixed {
|
|
@@ -289,22 +307,6 @@
|
|
|
289
307
|
--space-chrome-gap: var(--space-2);
|
|
290
308
|
--field-label-gap: var(--space-2);
|
|
291
309
|
|
|
292
|
-
--duration-fast: 150ms;
|
|
293
|
-
--duration-base: 250ms;
|
|
294
|
-
--duration-slow: 500ms;
|
|
295
|
-
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
|
296
|
-
--ease-emphasized: cubic-bezier(0.32, 0.72, 0, 1);
|
|
297
|
-
--ease-decelerate: cubic-bezier(0, 0, 0, 1);
|
|
298
|
-
--ease-accelerate: cubic-bezier(0.3, 0, 1, 1);
|
|
299
|
-
--reveal-distance: 10px;
|
|
300
|
-
|
|
301
|
-
--reveal-stagger-step: 60ms;
|
|
302
|
-
|
|
303
|
-
--duration-loop: 1400ms;
|
|
304
|
-
|
|
305
|
-
--activity-interval: var(--duration-loop);
|
|
306
|
-
|
|
307
|
-
--activity-stagger-step: 160ms;
|
|
308
310
|
}
|
|
309
311
|
|
|
310
312
|
.dark,
|
package/docs/CONSUMER-RULES.md
CHANGED
|
@@ -5,13 +5,18 @@ Read this once; the audit enforces it. Everything else in `docs/` is for contrib
|
|
|
5
5
|
1. Load styles with `@import "@godxjp/ui/styles"` (fonts bundled) or `@import "@godxjp/ui/styles/core"` (no fonts). Never cherry-pick `*-layout.css`.
|
|
6
6
|
2. Every page is `<PageContainer title subtitle extra footer>`; its sections are spaced by the page. Group items inside a section with `<Flex direction="col" gap>` or `<ResponsiveGrid>`.
|
|
7
7
|
3. No Tailwind layout on your own elements: no `flex`, `grid`, `gap-*`, `p-*`, `m-*`, `space-*`. Rows are `<Flex>` (default row), stacks are `<Flex direction="col">`, grids are `<ResponsiveGrid>`.
|
|
8
|
-
4. No hand-rolled surfaces: no `rounded-* border bg-*` divs. A box is `Card`, a pill is `Badge`, a person is `Avatar`, a row is `ListRow`, a label/value pair is `Descriptions`, an empty area is `EmptyState`.
|
|
8
|
+
4. No hand-rolled surfaces: no `rounded-* border bg-*` divs. A box is `Card`, a pill is `Badge`, a person is `Avatar`, a row is `ListRow`, a label/value pair is `Descriptions`, an empty area is `EmptyState`, a read-only sample of a colour the USER chose is `Swatch`.
|
|
9
9
|
5. Real controls only: `Button`, `Input`, `Select`, `Textarea`, `Checkbox`… never raw `<button>`/`<input>`; a labelled control lives in `<FormField label>`. A Select outside a form takes `width="auto"`. **A disabled control's reason is visible text, never a tooltip** — see below.
|
|
10
10
|
6. Text is `<Text>` / `<Heading>` with `tone`, `size`, `weight`, `truncate`, `mono` — not `className="text-muted-foreground font-semibold"`.
|
|
11
11
|
7. Colours are semantic tokens (`tone="destructive"`, `bg-primary`), never palette names, hex, or `bg-black` / `text-white`.
|
|
12
12
|
8. Sizes come from props (`size`, `width`, `columns`), never `w-[240px]` / `max-h-[420px]`.
|
|
13
13
|
9. Logical directions (`ms-`, `me-`, `start-`, `end-`) when a utility is unavoidable; never `ml-` / `left-`.
|
|
14
|
-
10.
|
|
14
|
+
10. A `Card` whose whole body is a table gets `<CardContent flush>` — the table must touch the
|
|
15
|
+
card's inner edge. A default `CardContent` pads 16px while the table draws its own border, so
|
|
16
|
+
the table reads as a second box inside the card, and a wide one runs past the card entirely.
|
|
17
|
+
(`flush` alone is enough: it drops the border, the radius and the inline padding. `tight` is a
|
|
18
|
+
different knob — it governs the header band, not the body's edges.)
|
|
19
|
+
11. Run `node node_modules/@godxjp/ui/scripts/ui-audit.mjs --changed` before every review; a browser sweep with `visual-audit.mjs` is a separate, heavier run — do it when the work is a visual review, not on every change; `visual-audit.mjs <url>` on the running app. Zero errors is the bar.
|
|
15
20
|
|
|
16
21
|
**Opting a deliberate exception out.** Name the rule; the block form also has to say why.
|
|
17
22
|
|
|
@@ -45,6 +50,6 @@ information belongs on the screen:
|
|
|
45
50
|
- `ServiceLauncherCard` already has this shape as a prop — `disabledReason`, rendered above the
|
|
46
51
|
action — and it is the pattern to copy anywhere else.
|
|
47
52
|
|
|
48
|
-
If the control is disabled
|
|
53
|
+
If the control is disabled _pending something the user can fix_, prefer leaving it enabled and
|
|
49
54
|
explaining on submit: an inert control with a paragraph beside it is often a validation message
|
|
50
55
|
wearing a disguise.
|
package/docs/CUSTOMER-THEMING.md
CHANGED
|
@@ -89,7 +89,7 @@ Import the styles, then set anchor tokens in your app's `theme.css` (loaded afte
|
|
|
89
89
|
|
|
90
90
|
/* ── Shadow tint — ONE knob ─────────────────────────────────────── */ --shadow-color: 12 26 49; /* RGB channels (default 0 0 0). Tints the WHOLE shadow ramp. */
|
|
91
91
|
|
|
92
|
-
/* ── Brand depth — all opt-in, all quiet by default ─────────────── */ --shadow-glow: 0 8px 20px hsl(var(--primary) / 0.32); /* glow halo on the primary CTA */ --card-shadow: 0 1px 2px rgb(12 26 49 / 0.06), 0 10px 28px -14px rgb(12 26 49 / 0.2); /* lift every Card */ --focus-ring-color: var(--ring); /* hue of every focus ring */ --focus-ring-
|
|
92
|
+
/* ── Brand depth — all opt-in, all quiet by default ─────────────── */ --shadow-glow: 0 8px 20px hsl(var(--primary) / 0.32); /* glow halo on the primary CTA */ --card-shadow: 0 1px 2px rgb(12 26 49 / 0.06), 0 10px 28px -14px rgb(12 26 49 / 0.2); /* lift every Card */ --focus-ring-color: var(--ring); /* hue of every focus ring */ --focus-ring-weight: var(--stroke-md); /* thickness of every focus ring — 2px; nothing paints until <html data-focus-outline="on"> */ --focus-ring-opacity: 1; /* alpha of every focus ring */ --focus-ring-offset: 0px; /* gap, outline-form rings only (star, dot, anchor) */ --gradient-hero: linear-gradient( 180deg, hsl(var(--accent)), transparent ); /* PageContainer header banner */ --gradient-glow: radial-gradient( 60% 70% at 90% -8%, hsl(var(--primary) / 0.1), transparent 70% ); /* AppShell ambient wash */ --overlay-background: rgb(12 26 49 / 0.55); /* modal scrim (Dialog / Sheet / Drawer) */ } ```
|
|
93
93
|
|
|
94
94
|
### The anchor tokens (single knobs that propagate)
|
|
95
95
|
|
|
@@ -101,23 +101,33 @@ Import the styles, then set anchor tokens in your app's `theme.css` (loaded afte
|
|
|
101
101
|
| `--shadow-color` | `0 0 0` | every shadow step `--shadow-{xs…2xl}` (`rgb(color / α)`) |
|
|
102
102
|
| `--shadow-glow` | invisible | brand glow halo on the primary CTA (set the full shadow value) |
|
|
103
103
|
| `--card-shadow` | `none` | resting elevation of every Card |
|
|
104
|
-
| `--focus-ring-color` / `--focus-ring-
|
|
104
|
+
| `--focus-ring-color` / `--focus-ring-weight` | `var(--ring)` / `1px` | hue & thickness of every keyboard-focus ring — but nothing paints until the switch below is on |
|
|
105
105
|
| `--focus-ring-opacity` / `--focus-ring-offset` | `1` / `0px` | alpha of every ring · gap for outline-form rings (star, carousel dot, heading anchor) |
|
|
106
106
|
| `--gradient-{hero,glow,brand}` | `none` | hero header banner / AppShell ambient wash / spare (set the full gradient) |
|
|
107
107
|
| `--overlay-background` | `rgb(0 0 0 / .5)` | the scrim of every overlay (Dialog / AlertDialog / Sheet / Drawer) |
|
|
108
108
|
|
|
109
|
-
### Focus ring —
|
|
109
|
+
### Focus ring — THE SWITCH FIRST, then three levels of override
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
**The indicator ships OFF.** `--focus-outline` is `0`, and every painted focus length multiplies by it, so by default nothing paints a focus mark. That is a product decision with a stated cost — it forfeits WCAG 2.2 SC 2.4.7 (AA) and a JIS X 8341-3 AA claim — recorded in `docs/DESIGN-AUTHORITY.md`. Turning it on is ONE attribute on the root element, no CSS:
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
```html
|
|
114
|
+
<html data-focus-outline="on"></html>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
(`AppProvider` has the equivalent.) Every `:focus-visible` selector is present either way; only the paint is switched.
|
|
118
|
+
|
|
119
|
+
Every ring is then drawn by a single rule (`src/styles/focus-ring.css`) reading the tokens above. Nothing else paints one; a test fails the build if a stylesheet tries.
|
|
120
|
+
|
|
121
|
+
**Thickness is `--focus-ring-weight`, never `--focus-ring-width`.** The width is DERIVED — `calc(var(--focus-ring-weight) * var(--focus-outline))` — so assigning it directly paints a ring even while the indicator is switched off, and that is exactly what the build-failing test forbids a stylesheet to do.
|
|
114
122
|
|
|
115
123
|
```css
|
|
116
124
|
:root {
|
|
117
125
|
--focus-ring-color: 24 99% 46%; /* every ring, brand orange */
|
|
118
|
-
--focus-ring-
|
|
126
|
+
--focus-ring-weight: var(--stroke-md); /* every ring, 2px */
|
|
119
127
|
}
|
|
120
|
-
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**A slim ring that still satisfies the criteria.** Switched on, the shipped weight is one hairline (1px) in the focus hue, measured in Chromium at **5.05:1** light and **7.07:1** dark on every surface a control sits on — so SC 1.4.11 (3:1, non-text contrast) is met on colour, independent of thickness. SC 2.4.13 Focus Appearance (AAA) additionally wants a perimeter of at least 2 CSS px: set `--focus-ring-weight: var(--stroke-md)` (measured: a 2px ring, same hue, same ratio). `var(--stroke-lg)` is the heavy 3px mark.
|
|
121
131
|
|
|
122
132
|
**Per component.** A component that genuinely needs a different ring publishes its own knob and the rule picks it up locally — Toggle and TimeInput ship a heavier, softer ring because they are filled surfaces where a hard 2px reads as a second border:
|
|
123
133
|
|
|
@@ -136,7 +146,7 @@ That means retuning is a one-liner and it reaches everything:
|
|
|
136
146
|
<div style={{ "--focus-ring-color": "0 84% 60%" } as React.CSSProperties}>…</div>
|
|
137
147
|
```
|
|
138
148
|
|
|
139
|
-
**Turning it off** — `--focus-
|
|
149
|
+
**Turning it back off** — drop the `data-focus-outline` attribute (or set `--focus-outline: 0`), which is the shipped state. Do NOT reach for `--focus-ring-width`: it is derived from the weight and the switch, and pinning it to any value is the same mistake in the other direction. Note the cost either way — with no visible focus indicator the package does not meet WCAG 2.2 SC 2.4.7.
|
|
140
150
|
|
|
141
151
|
**Adding your own component to the system**: put `ui-focus-ring` (or `ui-focus-ring-outline` when the mark needs a gap) on the focusable element.
|
|
142
152
|
|
package/docs/DATETIME.md
CHANGED
|
@@ -23,10 +23,18 @@ Omit `locale`, `timezone`, `timeFormat`, `dateFormat` → synced from AppProvide
|
|
|
23
23
|
|
|
24
24
|
| value | Pattern | Default locale |
|
|
25
25
|
| ----- | ------------ | -------------- |
|
|
26
|
-
| `iso` | `yyyy-MM-dd` |
|
|
26
|
+
| `iso` | `yyyy-MM-dd` | — |
|
|
27
|
+
| `ymd` | `yyyy/MM/dd` | ja |
|
|
27
28
|
| `dmy` | `dd/MM/yyyy` | vi |
|
|
28
29
|
| `mdy` | `MM/dd/yyyy` | en |
|
|
29
30
|
|
|
31
|
+
`ymd` and `iso` are both year-first and are NOT interchangeable: a Japanese business document
|
|
32
|
+
(請求書, 申請書) is written `2026/05/01`, never `2026-05-01`. `ja` defaulted to `iso` until a
|
|
33
|
+
Japanese-first consumer shipped its own date formatter as an explicit stopgap purely to get the
|
|
34
|
+
slashes — rule 1 above broken by this package's own default. Only the DEFAULT moved: a stored
|
|
35
|
+
preference still wins, `defaultDateFormat` still pins any value, and `iso` is one option away in
|
|
36
|
+
`<DateFormatPicker />`.
|
|
37
|
+
|
|
30
38
|
Sent to backend as `x-date-format`. Pick with `<DateFormatPicker />`.
|
|
31
39
|
|
|
32
40
|
## kind presets
|
|
@@ -43,9 +51,10 @@ Sent to backend as `x-date-format`. Pick with `<DateFormatPicker />`.
|
|
|
43
51
|
|
|
44
52
|
## ISO 8601 patterns
|
|
45
53
|
|
|
46
|
-
Date order follows `dateFormat` from AppProvider (`iso` | `dmy` | `mdy`):
|
|
54
|
+
Date order follows `dateFormat` from AppProvider (`iso` | `ymd` | `dmy` | `mdy`):
|
|
47
55
|
|
|
48
56
|
- `iso`: `yyyy-MM-dd` + `yyyy-MM-dd HH:mm`
|
|
57
|
+
- `ymd`: `yyyy/MM/dd` + `yyyy/MM/dd HH:mm`
|
|
49
58
|
- `dmy`: `dd/MM/yyyy` + `dd/MM/yyyy HH:mm`
|
|
50
59
|
- `mdy`: `MM/dd/yyyy` + `MM/dd/yyyy HH:mm`
|
|
51
60
|
|
package/docs/DESIGN-AUTHORITY.md
CHANGED
|
@@ -253,7 +253,8 @@ a weaker one.** An algorithm guarantees a value is _consistent_; this repo had t
|
|
|
253
253
|
times (below) precisely because consistent is not the same as _accessible_. A threshold guarantees
|
|
254
254
|
the property actually being sold.
|
|
255
255
|
|
|
256
|
-
**To change a derived value:** change it, run
|
|
256
|
+
**To change a derived value:** change it, run the test file that owns the threshold (never the full
|
|
257
|
+
suite — that is CI's job on the PR), and if a threshold breaks the value is
|
|
257
258
|
wrong. Do not relax the threshold.
|
|
258
259
|
|
|
259
260
|
**The four overrides that existed even while a generator did** — the clearest evidence the
|
|
@@ -3,16 +3,27 @@
|
|
|
3
3
|
> Generated by `scripts/frame-coverage.mjs` (issue #163). Do not edit by hand — run `pnpm check:frame-coverage`.
|
|
4
4
|
> Standard: [FRAME-COVERAGE-STANDARD.md](./FRAME-COVERAGE-STANDARD.md). A missing dimension is **UNTESTED**, never a pass.
|
|
5
5
|
|
|
6
|
-
- Public components: **
|
|
7
|
-
- With ≥1 frame: **
|
|
6
|
+
- Public components: **150**
|
|
7
|
+
- With ≥1 frame: **134** · zero-frame: **16**
|
|
8
8
|
- Fully covered (every contract axis declared): **0**
|
|
9
9
|
|
|
10
10
|
## UNTESTED — no `/frame/**` route
|
|
11
11
|
|
|
12
12
|
- [ ] `inertiaUpload`
|
|
13
|
+
- [ ] `FormFieldControl`
|
|
14
|
+
- [ ] `FormFieldArray`
|
|
15
|
+
- [ ] `useZodForm`
|
|
13
16
|
- [ ] `CardBar`
|
|
14
17
|
- [ ] `VisuallyHidden`
|
|
15
18
|
- [ ] `RangeTimeline`
|
|
19
|
+
- [ ] `ServiceCatalogCta`
|
|
20
|
+
- [ ] `OverlayPortalProvider`
|
|
21
|
+
- [ ] `SkeletonArticle`
|
|
22
|
+
- [ ] `SkeletonAvatar`
|
|
23
|
+
- [ ] `SkeletonButton`
|
|
24
|
+
- [ ] `SkeletonInput`
|
|
25
|
+
- [ ] `SkeletonNode`
|
|
26
|
+
- [ ] `SkeletonImage`
|
|
16
27
|
- [ ] `ChatBubbleList`
|
|
17
28
|
|
|
18
29
|
## Per-component contract axes
|
|
@@ -22,6 +33,10 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
|
|
|
22
33
|
| Component | Frame | visua | state | owner | conte | respo | inter | acces | prefe | async |
|
|
23
34
|
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
24
35
|
| inertiaUpload | **✗** | · | · | · | · | · | · | · | · | · |
|
|
36
|
+
| FormRoot | ✓ | · | · | · | · | · | · | · | · | · |
|
|
37
|
+
| FormFieldControl | **✗** | · | · | · | · | · | · | · | · | · |
|
|
38
|
+
| FormFieldArray | **✗** | · | · | · | · | · | · | · | · | · |
|
|
39
|
+
| useZodForm | **✗** | · | · | · | · | · | · | · | · | · |
|
|
25
40
|
| CardBar | **✗** | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
26
41
|
| TimeRangePicker | ✓ | · | · | · | · | · | · | · | · | · |
|
|
27
42
|
| VisuallyHidden | **✗** | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
@@ -53,8 +68,12 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
|
|
|
53
68
|
| CardContent | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
54
69
|
| StatCard | ✓ | N/A | N/A | · | · | · | · | · | · | · |
|
|
55
70
|
| ServiceLauncherCard | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
71
|
+
| ServiceCatalogCta | **✗** | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
56
72
|
| Badge | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
|
|
57
73
|
| Legend | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
74
|
+
| Swatch | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
75
|
+
| FeatureList | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
76
|
+
| Thumbnail | ✓ | · | N/A | N/A | · | · | · | · | · | · |
|
|
58
77
|
| ListRow | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
|
|
59
78
|
| CredentialReveal | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
|
|
60
79
|
| QrCode | ✓ | ✓ | N/A | · | · | · | · | · | · | · |
|
|
@@ -95,6 +114,7 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
|
|
|
95
114
|
| Steps | ✓ | ✓ | N/A | · | · | · | · | · | · | · |
|
|
96
115
|
| Toolbar | ✓ | N/A | · | N/A | · | · | · | · | · | · |
|
|
97
116
|
| AppProvider | ✓ | · | · | · | · | · | · | · | · | · |
|
|
117
|
+
| OverlayPortalProvider | **✗** | · | · | · | · | · | · | · | · | · |
|
|
98
118
|
| formatDate | ✓ | · | · | · | · | · | · | · | · | · |
|
|
99
119
|
| TimePicker | ✓ | · | · | · | · | · | · | · | · | · |
|
|
100
120
|
| Cascader | ✓ | ✓ | · | · | · | · | · | · | · | · |
|
|
@@ -116,7 +136,13 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
|
|
|
116
136
|
| PrefetchLink | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
117
137
|
| Avatar | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
|
|
118
138
|
| Separator | ✓ | · | N/A | N/A | · | · | · | · | · | · |
|
|
119
|
-
| Skeleton | ✓ | N/A |
|
|
139
|
+
| Skeleton | ✓ | N/A | · | N/A | · | · | · | · | · | · |
|
|
140
|
+
| SkeletonArticle | **✗** | N/A | · | N/A | · | · | · | · | · | · |
|
|
141
|
+
| SkeletonAvatar | **✗** | ✓ | N/A | N/A | · | · | · | · | · | · |
|
|
142
|
+
| SkeletonButton | **✗** | ✓ | N/A | N/A | · | · | · | · | · | · |
|
|
143
|
+
| SkeletonInput | **✗** | ✓ | N/A | N/A | · | · | · | · | · | · |
|
|
144
|
+
| SkeletonNode | **✗** | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
145
|
+
| SkeletonImage | **✗** | N/A | N/A | N/A | · | · | · | · | · | · |
|
|
120
146
|
| Toggle | ✓ | ✓ | · | N/A | · | · | · | · | · | · |
|
|
121
147
|
| ToggleGroup | ✓ | ✓ | · | · | · | · | · | · | · | · |
|
|
122
148
|
| AspectRatio | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
|
package/docs/SPACING.md
CHANGED
|
@@ -42,11 +42,11 @@ Implementation: `src/tokens/base.css` (values) · layout owners: `src/styles/*-l
|
|
|
42
42
|
| `--card-space-body-y` | `--space-section-active` | Header↔body gap |
|
|
43
43
|
| `--card-space-header-y` / `--card-space-footer-y` | `--space-stack-sm` | Banded header + separated footer band |
|
|
44
44
|
|
|
45
|
-
| Component
|
|
46
|
-
|
|
|
47
|
-
| `StatCard`
|
|
48
|
-
| `CardContent solo`
|
|
49
|
-
| `CardContent flush
|
|
45
|
+
| Component | Use |
|
|
46
|
+
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
47
|
+
| `StatCard` | KPI / stat tile (`solo` path) |
|
|
48
|
+
| `CardContent solo` | Body-only card (same padding as `StatCard`) |
|
|
49
|
+
| `CardContent flush` | Edge-to-edge table/tabs in card — REQUIRED when the table IS the body (rule 10). `flush` alone drops the border, radius and inline padding; add `tight` only to change the HEADER band. |
|
|
50
50
|
|
|
51
51
|
See preview **Data Display → Card** for live examples.
|
|
52
52
|
|
|
@@ -64,6 +64,36 @@ Pick by AXIS, and note that the three do **not** share one value: each reads a d
|
|
|
64
64
|
|
|
65
65
|
Because `ui-card-inset-x` reads `--card-space-inset`, it follows the card it sits in: a `Card density="tight"` or `"cozy"` moves those cells with the shell. The other two read fixed steps (band and body) and do not.
|
|
66
66
|
|
|
67
|
+
## Control interiors are NOT on this scale
|
|
68
|
+
|
|
69
|
+
Everything above is the space **between** things — page sections, siblings in a stack, a card's
|
|
70
|
+
shell against its content. A control's **inside** is a different measurement and it is derived from
|
|
71
|
+
the control band (`--control-height`, `--control-padding-x`), never from `--space-*`. The two do not
|
|
72
|
+
meet, and reading a step off the table above as a minimum for a control's interior gives the wrong
|
|
73
|
+
answer.
|
|
74
|
+
|
|
75
|
+
The case that keeps coming up is `Segmented`'s track (gh#503). Its padding is **2px**, and the
|
|
76
|
+
label inside it therefore sits ~5px from the track's outer edge — under `--space-2` (8px), which is
|
|
77
|
+
NOT a floor this document sets for anything.
|
|
78
|
+
|
|
79
|
+
2px is the whole geometry of the control:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
label height = --control-height − track padding × 2 → 32 − 4 = 28
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
so the track measures **exactly** `--control-height` and a `Segmented` sits level with the `Input`
|
|
86
|
+
and the `Button` beside it on the same row. Raise the padding to 8px and one of two things has to
|
|
87
|
+
give: either the label band drops to 16px — a 14px type size in a 16px box, under every hit target
|
|
88
|
+
this library holds — or the track grows to 44px (28 + 8 × 2) and stops lining up with every other
|
|
89
|
+
control. The same derivation is why a `Button`'s own label sits ~5px inside its border. A control
|
|
90
|
+
is sized by its band; the band is what a dense enterprise UI is for.
|
|
91
|
+
|
|
92
|
+
**The knob, if a service wants a roomier control.** `--segmented-track-padding` is a published
|
|
93
|
+
component token (`src/tokens/components/segmented.css`); raising it re-derives the item height from
|
|
94
|
+
the same formula, so the track stays exactly one control tall. Do not reach for a Tailwind `p-*` on
|
|
95
|
+
the control — the audit rejects it, and it would break the identity above.
|
|
96
|
+
|
|
67
97
|
## MCP
|
|
68
98
|
|
|
69
99
|
`get_pattern page-sections` (a page of Cards, spaced by the page) · `get_rule 40` (mobile-first spacing) · `list_audit_rules` (the spacing rules the CLI enforces).
|
package/docs/TOKENS.md
CHANGED
|
@@ -220,7 +220,7 @@ The census confirmed the number and rejected the diagnosis: **`width` is not one
|
|
|
220
220
|
|
|
221
221
|
**Px, never rem.** A stroke is a _device_ line: its job is to read as one crisp rule at any type size, so it must not grow when the root font-size does. Every token that moved onto this scale was already `px` for that reason; a `rem` thickness (`--slider-track-height: 0.375rem`) is a different decision and stayed where it was. **Not `--scaling`-multiplied** either — `--scaling` is a density knob, and a 1px divider at 0.92px would blur rather than tighten.
|
|
222
222
|
|
|
223
|
-
`--focus-ring-
|
|
223
|
+
The focus mark reads this scale too, through `--focus-ring-weight` — `var(--focus-outline-weight)`, which is `var(--stroke-hairline)` (the light 1px mark the ON state ships). `--focus-ring-width` is DERIVED from it (`weight × --focus-outline`, the on/off switch) and must never be set directly; a theme that wants a 2px focus perimeter (WCAG 2.2 SC 2.4.13) sets `--focus-ring-weight: var(--stroke-md)`. See docs/CUSTOMER-THEMING.md.
|
|
224
224
|
|
|
225
225
|
#### `--band-height-*` — the vertical extent of a horizontal band
|
|
226
226
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="960" height="540" viewBox="0 0 960 540" role="img">
|
|
2
|
+
<rect width="960" height="540" fill="hsl(210 20% 97%)"/>
|
|
3
|
+
<rect width="960" height="56" fill="hsl(152 34% 38%)"/>
|
|
4
|
+
<rect x="24" y="22" width="140" height="12" rx="6" fill="hsl(152 34% 80%)"/>
|
|
5
|
+
<rect y="56" width="216" height="484" fill="hsl(210 16% 92%)"/>
|
|
6
|
+
<rect x="24" y="92" width="160" height="10" rx="5" fill="hsl(210 12% 76%)"/>
|
|
7
|
+
<rect x="24" y="124" width="160" height="10" rx="5" fill="hsl(210 12% 82%)"/>
|
|
8
|
+
<rect x="24" y="156" width="160" height="10" rx="5" fill="hsl(210 12% 82%)"/>
|
|
9
|
+
<rect x="248" y="92" width="320" height="160" rx="12" fill="hsl(210 16% 88%)"/>
|
|
10
|
+
<rect x="592" y="92" width="320" height="160" rx="12" fill="hsl(210 16% 88%)"/>
|
|
11
|
+
<rect x="248" y="284" width="664" height="212" rx="12" fill="hsl(210 16% 90%)"/>
|
|
12
|
+
</svg>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="640" viewBox="0 0 360 640" role="img">
|
|
2
|
+
<rect width="360" height="640" fill="hsl(210 20% 97%)"/>
|
|
3
|
+
<rect width="360" height="72" fill="hsl(204 60% 46%)"/>
|
|
4
|
+
<rect x="20" y="30" width="120" height="12" rx="6" fill="hsl(204 60% 82%)"/>
|
|
5
|
+
<rect x="20" y="104" width="320" height="120" rx="10" fill="hsl(210 16% 88%)"/>
|
|
6
|
+
<rect x="20" y="248" width="320" height="64" rx="10" fill="hsl(210 16% 90%)"/>
|
|
7
|
+
<rect x="20" y="336" width="320" height="64" rx="10" fill="hsl(210 16% 90%)"/>
|
|
8
|
+
<rect x="20" y="424" width="320" height="64" rx="10" fill="hsl(210 16% 90%)"/>
|
|
9
|
+
<rect x="20" y="540" width="320" height="44" rx="10" fill="hsl(204 60% 46%)"/>
|
|
10
|
+
</svg>
|
|
@@ -111,6 +111,12 @@ export default function Demo() {
|
|
|
111
111
|
</CardHeader>
|
|
112
112
|
<CardContent>枠線のみ</CardContent>
|
|
113
113
|
</Card>
|
|
114
|
+
<Card variant="borderless">
|
|
115
|
+
<CardHeader>
|
|
116
|
+
<CardTitle level={2}>borderless</CardTitle>
|
|
117
|
+
</CardHeader>
|
|
118
|
+
<CardContent>塗りのみ · 枠線なし</CardContent>
|
|
119
|
+
</Card>
|
|
114
120
|
<Card variant="featured">
|
|
115
121
|
<CardHeader>
|
|
116
122
|
<CardTitle level={2}>featured</CardTitle>
|
|
@@ -120,6 +126,40 @@ export default function Demo() {
|
|
|
120
126
|
</ResponsiveGrid>
|
|
121
127
|
</Flex>
|
|
122
128
|
|
|
129
|
+
<Flex direction="col" gap="sm">
|
|
130
|
+
<Text as="div" weight="medium">
|
|
131
|
+
hoverable · actions — Ant Design の hoverable と actions
|
|
132
|
+
</Text>
|
|
133
|
+
<ResponsiveGrid columns={{ sm: 1, md: 2 }}>
|
|
134
|
+
{/*
|
|
135
|
+
* `hoverable` は見た目だけのフラグです。カード全体が押せるように見えるなら、
|
|
136
|
+
* キーボードでも届く本物のコントロールを必ず同居させます(ここでは footer の
|
|
137
|
+
* Button)。div に onClick を置くのは禁止です。
|
|
138
|
+
*/}
|
|
139
|
+
<Card hoverable>
|
|
140
|
+
<CardHeader>
|
|
141
|
+
<CardTitle level={2}>ホバーで浮き上がる</CardTitle>
|
|
142
|
+
<CardDescription>--card-hover-shadow まで一段上がります</CardDescription>
|
|
143
|
+
</CardHeader>
|
|
144
|
+
<CardFooter actions>
|
|
145
|
+
<Button variant="ghost">複製</Button>
|
|
146
|
+
<Button variant="ghost">共有</Button>
|
|
147
|
+
<Button variant="ghost">削除</Button>
|
|
148
|
+
</CardFooter>
|
|
149
|
+
</Card>
|
|
150
|
+
<Card hoverable accent="info" accentPlacement="perimeter">
|
|
151
|
+
<CardHeader>
|
|
152
|
+
<CardTitle level={2}>accent と併用</CardTitle>
|
|
153
|
+
<CardDescription>ホバー中もアテンションのリングは消えません</CardDescription>
|
|
154
|
+
</CardHeader>
|
|
155
|
+
<CardFooter actions>
|
|
156
|
+
<Button variant="ghost">承認</Button>
|
|
157
|
+
<Button variant="ghost">却下</Button>
|
|
158
|
+
</CardFooter>
|
|
159
|
+
</Card>
|
|
160
|
+
</ResponsiveGrid>
|
|
161
|
+
</Flex>
|
|
162
|
+
|
|
123
163
|
<Flex direction="col" gap="sm">
|
|
124
164
|
<Text as="div" weight="medium">
|
|
125
165
|
Accent · accentPlacement="edge" (既定 · 先頭エッジのレール)
|
|
@@ -290,13 +290,28 @@ export default function Demo() {
|
|
|
290
290
|
</AppProvider>
|
|
291
291
|
</Flex>
|
|
292
292
|
|
|
293
|
-
<Flex direction="col" gap="sm">
|
|
293
|
+
<Flex direction="col" gap="sm" id="empty-builtin">
|
|
294
294
|
<Text as="div" weight="medium">
|
|
295
295
|
空の状態(data が空のとき自動表示)
|
|
296
296
|
</Text>
|
|
297
297
|
<DataTable data={[]} columns={columns} getRowId={(row) => row.id} />
|
|
298
298
|
</Flex>
|
|
299
299
|
|
|
300
|
+
{/* The SAME cell with consumer content in it. `empty` takes a ReactNode, so a plain string
|
|
301
|
+
is a legal call — and the lifecycle cell used to be `padding: 0`, which put that string
|
|
302
|
+
flush against the table's edge. Measured here; see check:data-table-empty-inset. */}
|
|
303
|
+
<Flex direction="col" gap="sm" id="empty-plain-string">
|
|
304
|
+
<Text as="div" weight="medium">
|
|
305
|
+
空の状態(empty に文字列を渡す)
|
|
306
|
+
</Text>
|
|
307
|
+
<DataTable
|
|
308
|
+
data={[]}
|
|
309
|
+
columns={columns}
|
|
310
|
+
getRowId={(row) => row.id}
|
|
311
|
+
empty="まだ登録がありません"
|
|
312
|
+
/>
|
|
313
|
+
</Flex>
|
|
314
|
+
|
|
300
315
|
{/* — the two failure states, in the same table grid as empty/loading. */}
|
|
301
316
|
<Flex direction="col" gap="sm">
|
|
302
317
|
<Text as="div" weight="medium">
|
|
@@ -318,7 +333,7 @@ export default function Demo() {
|
|
|
318
333
|
<DataTable data={[]} columns={columns} getRowId={(row) => row.id} error />
|
|
319
334
|
</Flex>
|
|
320
335
|
|
|
321
|
-
<Flex direction="col" gap="sm">
|
|
336
|
+
<Flex direction="col" gap="sm" id="error-custom-node">
|
|
322
337
|
<Text as="div" weight="medium">
|
|
323
338
|
エラー(error にノードを渡して文言を差し替え)
|
|
324
339
|
</Text>
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Card,
|
|
3
|
+
CardContent,
|
|
4
|
+
CardDescription,
|
|
5
|
+
CardFooter,
|
|
6
|
+
CardHeader,
|
|
7
|
+
CardTitle,
|
|
8
|
+
FeatureList,
|
|
9
|
+
} from "@godxjp/ui/data-display";
|
|
10
|
+
import { Button, Text } from "@godxjp/ui/general";
|
|
11
|
+
import { Flex, PageContainer, ResponsiveGrid } from "@godxjp/ui/layout";
|
|
12
|
+
|
|
13
|
+
const STARTER = [
|
|
14
|
+
{ state: "included", label: "ユーザー 10 名まで" },
|
|
15
|
+
{ state: "included", label: "監査ログ", description: "直近 30 日分を保持します。" },
|
|
16
|
+
{
|
|
17
|
+
state: "limited",
|
|
18
|
+
label: "API 呼び出し",
|
|
19
|
+
description: "月 10,000 回を超えると 429 を返します。",
|
|
20
|
+
},
|
|
21
|
+
{ state: "excluded", label: "SAML / OIDC シングルサインオン" },
|
|
22
|
+
{ state: "excluded", label: "監査ログのエクスポート" },
|
|
23
|
+
] as const;
|
|
24
|
+
|
|
25
|
+
const ENTERPRISE = [
|
|
26
|
+
{ state: "included", label: "ユーザー数 無制限" },
|
|
27
|
+
{ state: "included", label: "監査ログ", description: "保持期間は契約単位で設定します。" },
|
|
28
|
+
{ state: "included", label: "API 呼び出し", description: "レート上限は個別に調整します。" },
|
|
29
|
+
{
|
|
30
|
+
state: "included",
|
|
31
|
+
label: "SAML / OIDC シングルサインオン",
|
|
32
|
+
description: "SAML 2.0 と OIDC の両方に対応。",
|
|
33
|
+
},
|
|
34
|
+
{ state: "included", label: "監査ログのエクスポート" },
|
|
35
|
+
] as const;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* FeatureList — 先頭の状態グリフ(含む/含まない/制限あり)を持つ「文」のリスト。
|
|
39
|
+
*
|
|
40
|
+
* ListRow は 1 行のエンティティ行(区切り線・末尾アクション)、Timeline は順序のあるイベント
|
|
41
|
+
* レール、Descriptions は用語/値のグリッド。どれも「折り返す説明文つきの状態リスト」ではない。
|
|
42
|
+
* Composed only from real @godxjp/ui components.
|
|
43
|
+
*/
|
|
44
|
+
export default function Demo() {
|
|
45
|
+
return (
|
|
46
|
+
<PageContainer
|
|
47
|
+
title="FeatureList"
|
|
48
|
+
subtitle="状態グリフつきの文のリスト · グリフは最初の行に揃う"
|
|
49
|
+
>
|
|
50
|
+
<Flex direction="col" gap="lg">
|
|
51
|
+
<Card>
|
|
52
|
+
<CardHeader>
|
|
53
|
+
<CardTitle level={2}>三つの状態</CardTitle>
|
|
54
|
+
<CardDescription>
|
|
55
|
+
included(✓)· limited(−)· excluded(✗)。色は意味を運ぶ唯一の手段ではありません ——
|
|
56
|
+
形が違い、読み上げ用の語も添えられます(WCAG 1.4.1)。excluded を赤で塗らないのは、
|
|
57
|
+
「含まれない」は失敗ではなく事実だからです。
|
|
58
|
+
</CardDescription>
|
|
59
|
+
</CardHeader>
|
|
60
|
+
<CardContent>
|
|
61
|
+
<FeatureList items={[...STARTER]} />
|
|
62
|
+
</CardContent>
|
|
63
|
+
</Card>
|
|
64
|
+
|
|
65
|
+
<Card>
|
|
66
|
+
<CardHeader>
|
|
67
|
+
<CardTitle level={2}>折り返しても、グリフは最初の行に揃う</CardTitle>
|
|
68
|
+
<CardDescription>
|
|
69
|
+
グリフの枠は 1 行分(1lh)の高さで、その中央にグリフが置かれます。だから 3 行に
|
|
70
|
+
折り返すラベルでも、揃う先は箱の上端ではなく最初の行です。呼び出し側に数値は
|
|
71
|
+
ありません。
|
|
72
|
+
</CardDescription>
|
|
73
|
+
</CardHeader>
|
|
74
|
+
<CardContent>
|
|
75
|
+
<FeatureList
|
|
76
|
+
items={[
|
|
77
|
+
{
|
|
78
|
+
state: "included",
|
|
79
|
+
label:
|
|
80
|
+
"組織をまたぐ権限の委譲(部門管理者が自部門の範囲内でだけロールを付け替えられる設定を含みます)",
|
|
81
|
+
description:
|
|
82
|
+
"委譲の範囲は組織ツリーのノード単位で決まり、親を超える付与はできません。監査ログには委譲元と委譲先の両方が記録されます。",
|
|
83
|
+
},
|
|
84
|
+
{ state: "limited", label: "短いラベル" },
|
|
85
|
+
]}
|
|
86
|
+
/>
|
|
87
|
+
</CardContent>
|
|
88
|
+
</Card>
|
|
89
|
+
|
|
90
|
+
<ResponsiveGrid columns={{ base: 1, md: 2 }}>
|
|
91
|
+
<Card>
|
|
92
|
+
<CardHeader>
|
|
93
|
+
<CardTitle level={2}>Starter</CardTitle>
|
|
94
|
+
<CardDescription>小さなチームのための最小構成。</CardDescription>
|
|
95
|
+
</CardHeader>
|
|
96
|
+
<CardContent>
|
|
97
|
+
<FeatureList items={[...STARTER]} />
|
|
98
|
+
</CardContent>
|
|
99
|
+
<CardFooter>
|
|
100
|
+
<Button variant="outline">Starter を選ぶ</Button>
|
|
101
|
+
</CardFooter>
|
|
102
|
+
</Card>
|
|
103
|
+
|
|
104
|
+
<Card>
|
|
105
|
+
<CardHeader>
|
|
106
|
+
<CardTitle level={2}>Enterprise</CardTitle>
|
|
107
|
+
<CardDescription>監査と SSO を必要とする組織向け。</CardDescription>
|
|
108
|
+
</CardHeader>
|
|
109
|
+
<CardContent>
|
|
110
|
+
<FeatureList items={[...ENTERPRISE]} />
|
|
111
|
+
</CardContent>
|
|
112
|
+
<CardFooter>
|
|
113
|
+
<Button>Enterprise を選ぶ</Button>
|
|
114
|
+
</CardFooter>
|
|
115
|
+
</Card>
|
|
116
|
+
</ResponsiveGrid>
|
|
117
|
+
|
|
118
|
+
<Card>
|
|
119
|
+
<CardHeader>
|
|
120
|
+
<CardTitle level={2}>数量はラベルに組み立てる</CardTitle>
|
|
121
|
+
<CardDescription>
|
|
122
|
+
「· 10,000 req/mo」のような数量に専用の prop はありません。Text を label に入れる
|
|
123
|
+
書き方がすでに合法で audit も通るため、prop を足すと docs/WHAT-BELONGS-HERE.md の問い
|
|
124
|
+
1(consumer に手がないか)に落ちます。
|
|
125
|
+
</CardDescription>
|
|
126
|
+
</CardHeader>
|
|
127
|
+
<CardContent>
|
|
128
|
+
<FeatureList
|
|
129
|
+
items={[
|
|
130
|
+
{
|
|
131
|
+
state: "limited",
|
|
132
|
+
label: (
|
|
133
|
+
<>
|
|
134
|
+
API 呼び出し{" "}
|
|
135
|
+
<Text tone="muted" tabular>
|
|
136
|
+
10,000 req/mo
|
|
137
|
+
</Text>
|
|
138
|
+
</>
|
|
139
|
+
),
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
state: "included",
|
|
143
|
+
label: (
|
|
144
|
+
<>
|
|
145
|
+
ストレージ{" "}
|
|
146
|
+
<Text tone="muted" tabular>
|
|
147
|
+
250 GB
|
|
148
|
+
</Text>
|
|
149
|
+
</>
|
|
150
|
+
),
|
|
151
|
+
},
|
|
152
|
+
]}
|
|
153
|
+
/>
|
|
154
|
+
</CardContent>
|
|
155
|
+
</Card>
|
|
156
|
+
</Flex>
|
|
157
|
+
</PageContainer>
|
|
158
|
+
);
|
|
159
|
+
}
|