@godxjp/ui 19.6.0 → 20.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/app/theme-axes.d.ts +2 -0
- package/dist/app/theme-axes.js +45 -0
- package/dist/components/charts/chart-cartesian.d.ts +2 -1
- package/dist/components/charts/chart-cartesian.js +52 -3
- package/dist/components/charts/chart-category-axis.d.ts +55 -0
- package/dist/components/charts/chart-category-axis.js +93 -0
- package/dist/components/charts/chart-frame.d.ts +10 -1
- package/dist/components/charts/chart-frame.js +19 -3
- package/dist/components/charts/compact-bar-trend.d.ts +1 -1
- package/dist/components/charts/compact-bar-trend.js +2 -0
- package/dist/components/charts/pie-chart.d.ts +1 -1
- package/dist/components/charts/pie-chart.js +12 -1
- package/dist/components/charts/recharts-peer.d.ts +49 -0
- package/dist/components/charts/recharts-peer.js +45 -0
- package/dist/components/data-display/card.d.ts +14 -3
- package/dist/components/data-display/card.js +22 -4
- package/dist/components/data-display/code-block.js +6 -2
- package/dist/components/data-display/collapsible.d.ts +23 -4
- package/dist/components/data-display/collapsible.js +119 -4
- package/dist/components/data-display/data-table.d.ts +39 -4
- package/dist/components/data-display/data-table.js +802 -270
- package/dist/components/data-display/descriptions.d.ts +27 -6
- package/dist/components/data-display/descriptions.js +58 -17
- package/dist/components/data-display/index.d.ts +5 -1
- package/dist/components/data-display/index.js +4 -0
- package/dist/components/data-display/legend.d.ts +15 -0
- package/dist/components/data-display/legend.js +11 -0
- package/dist/components/data-display/list-row.d.ts +10 -1
- package/dist/components/data-display/list-row.js +8 -2
- package/dist/components/data-display/popover.d.ts +60 -7
- package/dist/components/data-display/popover.js +268 -39
- package/dist/components/data-display/progress.d.ts +50 -2
- package/dist/components/data-display/progress.js +57 -9
- package/dist/components/data-display/range-timeline.d.ts +38 -0
- package/dist/components/data-display/range-timeline.js +161 -0
- package/dist/components/data-display/scroll-area.js +13 -2
- package/dist/components/data-display/service-launcher-card.js +10 -10
- package/dist/components/data-display/table.d.ts +11 -3
- package/dist/components/data-display/table.js +48 -18
- package/dist/components/data-display/tree-list.js +4 -9
- package/dist/components/data-entry/calendar.d.ts +2 -2
- package/dist/components/data-entry/calendar.js +79 -33
- package/dist/components/data-entry/cascader.d.ts +1 -1
- package/dist/components/data-entry/cascader.js +188 -24
- package/dist/components/data-entry/checkbox.d.ts +19 -6
- package/dist/components/data-entry/checkbox.js +55 -16
- package/dist/components/data-entry/choice-option.d.ts +1 -1
- package/dist/components/data-entry/color-picker.d.ts +1 -1
- package/dist/components/data-entry/color-picker.js +17 -5
- package/dist/components/data-entry/control-appearance.d.ts +64 -0
- package/dist/components/data-entry/control-appearance.js +39 -0
- package/dist/components/data-entry/control-surface.d.ts +61 -0
- package/dist/components/data-entry/control-surface.js +39 -0
- package/dist/components/data-entry/date-picker.d.ts +1 -1
- package/dist/components/data-entry/date-picker.js +344 -113
- package/dist/components/data-entry/date-range-picker.d.ts +2 -2
- package/dist/components/data-entry/date-range-picker.js +278 -140
- package/dist/components/data-entry/field.js +0 -1
- package/dist/components/data-entry/form-field.d.ts +1 -1
- package/dist/components/data-entry/form-field.js +39 -4
- package/dist/components/data-entry/form.d.ts +4 -0
- package/dist/components/data-entry/form.js +5 -3
- package/dist/components/data-entry/index.d.ts +7 -3
- package/dist/components/data-entry/index.js +10 -1
- package/dist/components/data-entry/input-otp.d.ts +1 -1
- package/dist/components/data-entry/input.d.ts +12 -34
- package/dist/components/data-entry/input.js +92 -24
- package/dist/components/data-entry/label.d.ts +3 -2
- package/dist/components/data-entry/label.js +23 -10
- package/dist/components/data-entry/month-picker.d.ts +2 -2
- package/dist/components/data-entry/month-picker.js +47 -10
- package/dist/components/data-entry/month-range-picker.d.ts +2 -2
- package/dist/components/data-entry/month-range-picker.js +51 -11
- package/dist/components/data-entry/number-input.d.ts +7 -0
- package/dist/components/data-entry/number-input.js +147 -98
- package/dist/components/data-entry/password-input.d.ts +1 -1
- package/dist/components/data-entry/radio.d.ts +1 -1
- package/dist/components/data-entry/radio.js +61 -13
- package/dist/components/data-entry/search-input.d.ts +1 -1
- package/dist/components/data-entry/search-input.js +16 -2
- package/dist/components/data-entry/search-select.d.ts +2 -2
- package/dist/components/data-entry/search-select.js +209 -78
- package/dist/components/data-entry/select.d.ts +22 -4
- package/dist/components/data-entry/select.js +215 -163
- package/dist/components/data-entry/slider.d.ts +9 -1
- package/dist/components/data-entry/slider.js +87 -9
- package/dist/components/data-entry/switch.d.ts +3 -0
- package/dist/components/data-entry/switch.js +29 -3
- package/dist/components/data-entry/textarea.d.ts +14 -56
- package/dist/components/data-entry/textarea.js +80 -33
- package/dist/components/data-entry/time-picker.d.ts +2 -2
- package/dist/components/data-entry/time-picker.js +333 -109
- package/dist/components/data-entry/time-range-picker.d.ts +5 -0
- package/dist/components/data-entry/time-range-picker.js +89 -0
- package/dist/components/data-entry/transfer.d.ts +1 -1
- package/dist/components/data-entry/transfer.js +99 -31
- package/dist/components/data-entry/tree-select-strategy.d.ts +1 -1
- package/dist/components/data-entry/tree-select.d.ts +1 -1
- package/dist/components/data-entry/tree-select.js +197 -92
- package/dist/components/data-entry/tree-utils.d.ts +1 -1
- package/dist/components/data-entry/tree-utils.js +7 -14
- package/dist/components/data-entry/upload-files.d.ts +2 -0
- package/dist/components/data-entry/upload-files.js +31 -0
- package/dist/components/data-entry/upload-request.d.ts +4 -0
- package/dist/components/data-entry/upload-request.js +53 -0
- package/dist/components/data-entry/upload-types.d.ts +28 -0
- package/dist/components/data-entry/upload-types.js +2 -0
- package/dist/components/data-entry/upload.d.ts +2 -2
- package/dist/components/data-entry/upload.js +482 -117
- package/dist/components/feedback/dialog.d.ts +105 -38
- package/dist/components/feedback/dialog.js +268 -193
- package/dist/components/feedback/overlay-close-focus.d.ts +31 -0
- package/dist/components/feedback/overlay-close-focus.js +31 -0
- package/dist/components/feedback/overlay-header-tone.d.ts +1 -1
- package/dist/components/feedback/sheet.d.ts +53 -11
- package/dist/components/feedback/sheet.js +150 -81
- package/dist/components/feedback/tooltip.d.ts +51 -7
- package/dist/components/feedback/tooltip.js +107 -25
- package/dist/components/general/button.d.ts +1 -1
- package/dist/components/general/button.js +7 -3
- package/dist/components/general/index.d.ts +1 -0
- package/dist/components/general/index.js +2 -0
- package/dist/components/general/logo.d.ts +17 -0
- package/dist/components/general/logo.js +22 -16
- package/dist/components/general/typography.d.ts +3 -0
- package/dist/components/general/typography.js +15 -1
- package/dist/components/general/visually-hidden.d.ts +3 -0
- package/dist/components/general/visually-hidden.js +9 -0
- package/dist/components/layout/app-launcher.d.ts +34 -0
- package/dist/components/layout/app-launcher.js +228 -0
- package/dist/components/layout/app-shell.d.ts +3 -1
- package/dist/components/layout/app-shell.js +69 -12
- package/dist/components/layout/aspect-ratio.js +0 -1
- package/dist/components/layout/auth-divider.js +0 -1
- package/dist/components/layout/breadcrumb.d.ts +14 -2
- package/dist/components/layout/breadcrumb.js +46 -4
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +41 -3
- package/dist/components/layout/index.d.ts +3 -0
- package/dist/components/layout/index.js +5 -1
- package/dist/components/layout/nav-surface.d.ts +26 -0
- package/dist/components/layout/nav-surface.js +17 -0
- package/dist/components/layout/org-switcher.d.ts +5 -1
- package/dist/components/layout/org-switcher.js +25 -4
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +5 -3
- package/dist/components/layout/responsive-grid.d.ts +16 -2
- package/dist/components/layout/responsive-grid.js +29 -2
- package/dist/components/layout/separator.js +0 -1
- package/dist/components/layout/sidebar.js +4 -1
- package/dist/components/layout/split-pane.d.ts +14 -1
- package/dist/components/layout/split-pane.js +26 -13
- package/dist/components/layout/topbar-item.d.ts +3 -0
- package/dist/components/layout/topbar-item.js +19 -5
- package/dist/components/layout/topbar.d.ts +1 -1
- package/dist/components/layout/topbar.js +27 -6
- package/dist/components/navigation/app-setting-picker.js +21 -2
- package/dist/components/navigation/app-setting-toggle.d.ts +16 -0
- package/dist/components/navigation/app-setting-toggle.js +96 -0
- package/dist/components/navigation/dropdown-menu.d.ts +227 -18
- package/dist/components/navigation/dropdown-menu.js +402 -118
- package/dist/components/navigation/index.d.ts +2 -0
- package/dist/components/navigation/index.js +2 -0
- package/dist/components/navigation/pagination-utils.d.ts +2 -1
- package/dist/components/navigation/pagination.d.ts +2 -2
- package/dist/components/navigation/pagination.js +155 -83
- package/dist/components/navigation/steps.d.ts +2 -2
- package/dist/components/navigation/steps.js +29 -4
- package/dist/components/navigation/tabs.d.ts +29 -16
- package/dist/components/navigation/tabs.js +374 -144
- package/dist/components/ui/accordion.d.ts +50 -5
- package/dist/components/ui/accordion.js +239 -33
- package/dist/components/ui/aspect-ratio.d.ts +23 -2
- package/dist/components/ui/aspect-ratio.js +15 -13
- package/dist/components/ui/avatar.d.ts +29 -4
- package/dist/components/ui/avatar.js +111 -25
- package/dist/components/ui/hover-card.d.ts +42 -4
- package/dist/components/ui/hover-card.js +183 -27
- package/dist/components/ui/input-otp.d.ts +26 -28
- package/dist/components/ui/input-otp.js +50 -7
- package/dist/components/ui/label.js +0 -1
- package/dist/components/ui/password-input.d.ts +36 -2
- package/dist/components/ui/password-input.js +27 -7
- package/dist/components/ui/rating.d.ts +25 -0
- package/dist/components/ui/rating.js +67 -27
- package/dist/components/ui/segmented.d.ts +12 -3
- package/dist/components/ui/segmented.js +17 -2
- package/dist/components/ui/separator.d.ts +12 -2
- package/dist/components/ui/separator.js +30 -9
- package/dist/components/ui/tag-input.d.ts +45 -0
- package/dist/components/ui/tag-input.js +109 -27
- package/dist/components/ui/toggle-group.d.ts +50 -5
- package/dist/components/ui/toggle-group.js +79 -20
- package/dist/components/ui/toggle.d.ts +31 -5
- package/dist/components/ui/toggle.js +42 -3
- package/dist/form/form-context.d.ts +29 -0
- package/dist/form/form-context.js +44 -4
- package/dist/form/form-field-array.d.ts +22 -0
- package/dist/form/form-field-array.js +50 -0
- package/dist/form/form-field-control.d.ts +2 -1
- package/dist/form/form-field-control.js +116 -40
- package/dist/form/form-root.d.ts +2 -1
- package/dist/form/form-root.js +142 -23
- package/dist/form/index.d.ts +3 -1
- package/dist/form/index.js +12 -1
- package/dist/i18n/messages/en.json +64 -5
- package/dist/i18n/messages/ja.json +64 -5
- package/dist/i18n/messages/vi.json +64 -5
- package/dist/inertia/index.d.ts +20 -0
- package/dist/inertia/index.js +60 -1
- package/dist/lib/control-styles.d.ts +25 -3
- package/dist/lib/control-styles.js +9 -3
- package/dist/lib/datetime/picker-format.d.ts +8 -0
- package/dist/lib/datetime/picker-format.js +54 -0
- package/dist/lib/slot.d.ts +32 -0
- package/dist/lib/slot.js +22 -0
- package/dist/lib/variants.d.ts +22 -3
- package/dist/lib/variants.js +56 -1
- package/dist/props/components/app.prop.d.ts +25 -1
- package/dist/props/components/charts.prop.d.ts +21 -0
- package/dist/props/components/data-display.prop.d.ts +72 -4
- package/dist/props/components/data-entry.prop.d.ts +718 -46
- package/dist/props/components/form.prop.d.ts +142 -4
- package/dist/props/components/general.prop.d.ts +17 -1
- package/dist/props/components/index.d.ts +3 -3
- package/dist/props/components/layout.prop.d.ts +281 -11
- package/dist/props/components/navigation.prop.d.ts +114 -4
- package/dist/props/registry.d.ts +397 -11
- package/dist/props/registry.js +526 -11
- package/dist/props/vocabulary/content.prop.d.ts +1 -1
- package/dist/props/vocabulary/data.prop.d.ts +179 -1
- package/dist/props/vocabulary/index.d.ts +5 -5
- package/dist/props/vocabulary/interaction.prop.d.ts +68 -3
- package/dist/props/vocabulary/layout.prop.d.ts +57 -1
- package/dist/props/vocabulary/navigation.prop.d.ts +40 -0
- package/dist/props/vocabulary/shared.prop.d.ts +33 -0
- package/dist/styles/badge-layout.css +2 -1
- package/dist/styles/card-layout.css +26 -4
- package/dist/styles/chart-layout.css +15 -0
- package/dist/styles/control.css +657 -15
- package/dist/styles/core.css +5 -2
- package/dist/styles/data-display-layout.css +313 -6
- package/dist/styles/data-entry-layout.css +13 -0
- package/dist/styles/focus-ring.css +4 -0
- package/dist/styles/index.css +5 -2
- package/dist/styles/layout.css +327 -4
- package/dist/styles/navigation-layout.css +227 -0
- package/dist/styles/shell-layout.css +369 -13
- package/dist/styles/table-layout.css +95 -6
- package/dist/styles/text-layout.css +10 -4
- package/dist/tokens/base.css +2 -1
- package/dist/tokens/components/badge.css +1 -0
- package/dist/tokens/components/chart.css +6 -0
- package/dist/tokens/components/control.css +79 -2
- package/dist/tokens/components/data-display.css +20 -0
- package/dist/tokens/components/descriptions.css +11 -0
- package/dist/tokens/components/flex.css +8 -0
- package/dist/tokens/components/navigation.css +55 -0
- package/dist/tokens/components/shell.css +53 -3
- package/dist/tokens/components/table.css +14 -0
- package/dist/tokens/foundation.css +2 -0
- package/dist/tokens/semantic/layout.css +9 -0
- package/docs/COMPONENTS.md +9 -3
- package/docs/CONSUMER-RULES.md +13 -0
- package/docs/DESIGN-AUTHORITY.md +145 -83
- package/docs/DEVELOPMENT.md +4 -3
- package/docs/FORMS.md +151 -6
- package/docs/FRAME-COVERAGE-REPORT.md +32 -17
- package/docs/README.md +15 -15
- package/docs/STANDARDS-vocabulary-tokens.md +1 -1
- package/docs/TESTING.md +15 -6
- package/docs/WHAT-BELONGS-HERE.md +179 -0
- package/docs/charts/cjk-category-axis.tsx +81 -0
- package/docs/data-display/card/index.tsx +22 -0
- package/docs/data-display/data-table/examples/antd-parity.tsx +257 -0
- package/docs/data-display/data-table/index.tsx +23 -0
- package/docs/data-display/descriptions.tsx +41 -0
- package/docs/data-display/legend.tsx +145 -0
- package/docs/data-display/progress.tsx +32 -0
- package/docs/data-display/scroll-area.tsx +31 -25
- package/docs/data-display/table.tsx +104 -45
- package/docs/data-display/timeline.tsx +41 -0
- package/docs/data-entry/date-picker.tsx +85 -0
- package/docs/data-entry/date-range-picker.tsx +26 -0
- package/docs/data-entry/form-dynamic-fields.tsx +199 -0
- package/docs/data-entry/form.tsx +74 -4
- package/docs/data-entry/input-otp.tsx +24 -0
- package/docs/data-entry/input.tsx +46 -1
- package/docs/data-entry/month-range-picker.tsx +1 -1
- package/docs/data-entry/segmented.tsx +1 -1
- package/docs/data-entry/select.tsx +29 -2
- package/docs/data-entry/switch.tsx +41 -0
- package/docs/data-entry/textarea.tsx +38 -0
- package/docs/data-entry/time-picker.tsx +85 -1
- package/docs/data-entry/time-range-picker.tsx +55 -0
- package/docs/data-entry/transfer.tsx +17 -0
- package/docs/data-entry/upload.tsx +56 -12
- package/docs/feedback/sheet.tsx +1 -1
- package/docs/feedback/tooltip.tsx +1 -1
- package/docs/general/activity.tsx +2 -2
- package/docs/general/button/index.tsx +14 -1
- package/docs/general/typography.tsx +14 -1
- package/docs/layout/app-launcher.tsx +151 -0
- package/docs/layout/app-shell-arrangements.tsx +225 -0
- package/docs/layout/app-shell.tsx +11 -0
- package/docs/layout/aspect-ratio.tsx +1 -1
- package/docs/layout/flex.tsx +50 -0
- package/docs/layout/responsive-grid.tsx +21 -1
- package/docs/layout/topbar.tsx +5 -9
- package/docs/navigation/app-setting-picker.tsx +37 -1
- package/docs/navigation/app-setting-toggle.tsx +111 -0
- package/docs/navigation/breadcrumb.tsx +48 -0
- package/docs/navigation/dropdown-menu.tsx +21 -0
- package/docs/navigation/pagination.tsx +52 -0
- package/docs/navigation/steps.tsx +37 -0
- package/docs/navigation/tabs.tsx +97 -1
- package/docs/query/button-refetch.tsx +1 -0
- package/package.json +28 -8
- package/scripts/_agent-setup.mjs +182 -3
- package/scripts/consumer-rule.md +98 -0
- package/scripts/guinea-pig-skill.md +322 -0
- package/scripts/init-guinea-pig.mjs +84 -0
- package/scripts/postinstall.mjs +13 -2
- package/scripts/ui-audit.mjs +351 -37
- /package/dist/tokens/{antd.generated.css → derived.css} +0 -0
package/docs/README.md
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
# @godxjp/ui Documentation
|
|
2
2
|
|
|
3
|
-
| Doc | Purpose
|
|
4
|
-
| -------------------------------------------- |
|
|
5
|
-
| [CONSUMER-RULES.md](./CONSUMER-RULES.md) | **Start here if you build an app with @godxjp/ui** — the ten rules the audit enforces (styles entry, layout owners, real primitives, tokens)
|
|
6
|
-
| [DEVELOPMENT.md](./DEVELOPMENT.md) | **Contributor guideline** — role/boundary, architecture, how to add/extend, verify
|
|
7
|
-
| [COMPONENTS.md](./COMPONENTS.md) | Component catalog by
|
|
8
|
-
| [PROPS-VOCABULARY.md](./PROPS-VOCABULARY.md) | Atomic prop types (`*Prop` suffix)
|
|
9
|
-
| [PROPS-REGISTRY.md](./PROPS-REGISTRY.md) | Machine-readable registry + forbidden aliases
|
|
10
|
-
| [DATETIME.md](./DATETIME.md) | **Mandatory** `formatDate` — all date/time display
|
|
11
|
-
| [DESIGN-AUTHORITY.md](./DESIGN-AUTHORITY.md) | **Which external standard owns which decision** — APG, Radix, shadcn, Ant Design groups, SmartHR colour, Carbon geometry. Read before inventing a spacing/density/layout answer |
|
|
12
|
-
| [SPACING.md](./SPACING.md) | Golden ratio (φ) macro spacing — PageContainer sections, Flex gap, Card rhythm
|
|
13
|
-
| [FORMS.md](./FORMS.md) | **Mandatory** react-hook-form + Zod 4
|
|
14
|
-
| [TESTING.md](./TESTING.md) | **Mandatory** Vitest per component
|
|
15
|
-
| [FRAME-A11Y-CI.md](./FRAME-A11Y-CI.md) | Per-frame axe a11y + geometry + coverage CI gates — how to run/regenerate locally
|
|
16
|
-
| [../README.md](../README.md) | Setup, workspace wiring, theme
|
|
3
|
+
| Doc | Purpose |
|
|
4
|
+
| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
5
|
+
| [CONSUMER-RULES.md](./CONSUMER-RULES.md) | **Start here if you build an app with @godxjp/ui** — the ten rules the audit enforces (styles entry, layout owners, real primitives, tokens) |
|
|
6
|
+
| [DEVELOPMENT.md](./DEVELOPMENT.md) | **Contributor guideline** — role/boundary, architecture, how to add/extend, verify |
|
|
7
|
+
| [COMPONENTS.md](./COMPONENTS.md) | Component catalog by taxonomy group |
|
|
8
|
+
| [PROPS-VOCABULARY.md](./PROPS-VOCABULARY.md) | Atomic prop types (`*Prop` suffix) |
|
|
9
|
+
| [PROPS-REGISTRY.md](./PROPS-REGISTRY.md) | Machine-readable registry + forbidden aliases |
|
|
10
|
+
| [DATETIME.md](./DATETIME.md) | **Mandatory** `formatDate` — all date/time display |
|
|
11
|
+
| [DESIGN-AUTHORITY.md](./DESIGN-AUTHORITY.md) | **Which external standard owns which decision** — APG, Radix, shadcn, Ant Design groups, SmartHR colour, Carbon geometry, measured contrast for derived colour. Read before inventing a spacing/density/layout answer |
|
|
12
|
+
| [SPACING.md](./SPACING.md) | Golden ratio (φ) macro spacing — PageContainer sections, Flex gap, Card rhythm |
|
|
13
|
+
| [FORMS.md](./FORMS.md) | **Mandatory** react-hook-form + Zod 4 |
|
|
14
|
+
| [TESTING.md](./TESTING.md) | **Mandatory** Vitest per component |
|
|
15
|
+
| [FRAME-A11Y-CI.md](./FRAME-A11Y-CI.md) | Per-frame axe a11y + geometry + coverage CI gates — how to run/regenerate locally |
|
|
16
|
+
| [../README.md](../README.md) | Setup, workspace wiring, theme |
|
|
17
17
|
|
|
18
18
|
## Preview
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
cd packages/ui
|
|
22
22
|
pnpm preview # http://localhost:6008
|
|
23
|
-
pnpm preview:build # static site → preview/dist/
|
|
23
|
+
pnpm preview:build # static site → preview/dist/ — heavy; CI's job, run at most once pre-PR
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
### Preview doc format
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Prop Vocabulary + Design Token Standards
|
|
2
2
|
|
|
3
|
-
These rules are normative for @godxjp/ui
|
|
3
|
+
These rules are normative for @godxjp/ui. They came out of the props-vocabulary / token-consistency debate, whose record lived in `debate/` until that directory was removed — this file is now the normative source, not a mirror of one.
|
|
4
4
|
|
|
5
5
|
1. Prop vocabulary: every exported `*Prop` type in `src/props/components/` MUST have exactly one `COMPONENT_PROP_REGISTRY` entry.
|
|
6
6
|
2. Prop vocabulary: every public property in an exported component prop type MUST map to one `VOCABULARY_REGISTRY` entry or to a `local: true` registry record with a non-empty `reason`.
|
package/docs/TESTING.md
CHANGED
|
@@ -5,10 +5,16 @@ Every component **must** ship with a Vitest suite before merge.
|
|
|
5
5
|
## Run
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
pnpm
|
|
11
|
-
pnpm
|
|
8
|
+
# While working — ONLY the tests for what you touched. Tests sit beside the
|
|
9
|
+
# component in `src/components/<group>/__tests__/`, so scope to that folder.
|
|
10
|
+
pnpm vitest run src/components/<group>/__tests__ --maxWorkers=2
|
|
11
|
+
pnpm vitest watch src/components/<group>/__tests__ # watch one component
|
|
12
|
+
|
|
13
|
+
# CI only — 506 files / 3700+ tests. Do NOT run these from an agent loop or with
|
|
14
|
+
# other agents on the machine: measured 70 vitest workers at load 90, an overheating
|
|
15
|
+
# laptop and a burnt monthly API budget.
|
|
16
|
+
pnpm test # single run — CI
|
|
17
|
+
pnpm test:coverage # v8 coverage report — CI
|
|
12
18
|
```
|
|
13
19
|
|
|
14
20
|
## File location
|
|
@@ -68,7 +74,7 @@ import "@testing-library/jest-dom/vitest";
|
|
|
68
74
|
| `react-hooks/set-state-in-effect` | sync setState in effects |
|
|
69
75
|
| `RenderLoopGuard` in tests | runaway re-renders during Vitest |
|
|
70
76
|
|
|
71
|
-
Run `pnpm lint` before
|
|
77
|
+
Run `pnpm lint` before your scoped test run — official React Compiler rules align with test guard.
|
|
72
78
|
|
|
73
79
|
## Forms testing
|
|
74
80
|
|
|
@@ -83,7 +89,10 @@ Never test forms with raw `useState` — mirror production `FormRoot` + `FormFie
|
|
|
83
89
|
|
|
84
90
|
## CI gate
|
|
85
91
|
|
|
86
|
-
|
|
92
|
+
The full suite must pass with zero failures before any UI PR merges — **and that run belongs
|
|
93
|
+
to CI, not to you.** Locally you run only the tests for the files you changed; CI runs
|
|
94
|
+
everything on the PR. `tal --help` states the same rule for the agent loop: *FULL SUITE KHÔNG
|
|
95
|
+
THUỘC VỀ VÒNG LẶP.*
|
|
87
96
|
|
|
88
97
|
## When tests fail
|
|
89
98
|
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Cái gì đáng đưa vào @godxjp/ui
|
|
2
|
+
|
|
3
|
+
Một design system hỏng theo hai hướng ngược nhau, và cả hai đều hỏng thật:
|
|
4
|
+
|
|
5
|
+
- **Quá hẹp** — thiếu prop, nên consumer buộc phải lách bằng class hoặc mã màu
|
|
6
|
+
gõ tay. Đây là hướng đang hỏng: một lượt kiểm trên godx-chat (08/09/2026) ra
|
|
7
|
+
**51 lỗi, 42 trong đó đến từ ĐÚNG MỘT prop còn thiếu** (đệm trên primitive bố
|
|
8
|
+
cục).
|
|
9
|
+
- **Quá rộng** — nhận mọi yêu cầu, thành một đống prop không ai nhớ, và mỗi
|
|
10
|
+
prop là một mảnh DOM nội bộ bị đóng băng thành API công khai.
|
|
11
|
+
|
|
12
|
+
Tài liệu này là bộ lọc giữa hai hướng đó. Nó cố tình viết thành câu hỏi **trả
|
|
13
|
+
lời được bằng có/không**, không phải nguyên tắc để cảm nhận.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Ba câu hỏi — phải ĐỦ CẢ BA
|
|
18
|
+
|
|
19
|
+
### 1. Có phải consumer KHÔNG CÓ nước đi hợp lệ nào không?
|
|
20
|
+
|
|
21
|
+
Không phải "bất tiện". Là **bất khả**: mọi prop và token đang có đều không nói
|
|
22
|
+
được điều cần nói, và mọi đường còn lại đều bị `ui-audit` chặn.
|
|
23
|
+
|
|
24
|
+
- ✅ Thiết kế cần 12px giữa hai phần tử trên một HÀNG. Thang bậc tên đọc trục
|
|
25
|
+
dọc nên `md` = 16px; làm tròn thì lệch bố cục; viết `gap: 12px` thì
|
|
26
|
+
`no-arbitrary-spacing` chặn. **Không có nước đi.** → gh#401, đã vá.
|
|
27
|
+
- ❌ "Viết `<Flex gap={3}>` dài hơn `gap-3`." Có nước đi, chỉ là dài hơn.
|
|
28
|
+
|
|
29
|
+
Cách kiểm: viết ra đoạn mã bạn _muốn_ viết, chạy `ui-audit` lên nó. Nếu nó
|
|
30
|
+
xanh, bạn đã có nước đi.
|
|
31
|
+
|
|
32
|
+
### 2. Nó thuộc về HÌNH DẠNG của component, hay thuộc về NỘI DUNG của một màn?
|
|
33
|
+
|
|
34
|
+
Design system sở hữu hình dạng. Màn hình sở hữu nội dung.
|
|
35
|
+
|
|
36
|
+
- ✅ `Flex` không có đệm. Mọi hàng/cột trong mọi ứng dụng đều có thể cần đệm.
|
|
37
|
+
- ✅ `TableHead` không có trục căn lề. Mọi bảng có cột số đều cần.
|
|
38
|
+
- ❌ "Bảng quản trị thành viên cần cột vai trò rộng 8rem." Đó là màn hình ấy.
|
|
39
|
+
- ❌ "Dashboard cần bốn thẻ chỉ số xếp ngang." Đó là bố cục của một trang.
|
|
40
|
+
|
|
41
|
+
Câu hỏi phụ khi phân vân: **consumer thứ hai có gặp không?** Nếu câu trả lời là
|
|
42
|
+
"chắc là không" thì gần như luôn là nội dung, không phải hình dạng.
|
|
43
|
+
|
|
44
|
+
### 3. Diễn đạt được thành một TRỤC CÓ TÊN không?
|
|
45
|
+
|
|
46
|
+
Một prop phải gọi được **ý định**, không chỉ mở một lỗ.
|
|
47
|
+
|
|
48
|
+
- ✅ `pad={{ blockStart: 3 }}` — trục logic, bậc thang, đọc ra nghĩa.
|
|
49
|
+
- ❌ `styles={{ body: {...}, header: {...} }}` — không phải một trục; nó là một
|
|
50
|
+
lỗ tự do, và nó đóng băng tên khe DOM nội bộ thành API công khai. Xem mục
|
|
51
|
+
"Không đáng" bên dưới.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Bốn dấu hiệu MẠNH — một cái là đủ để ưu tiên làm ngay
|
|
56
|
+
|
|
57
|
+
Ba câu trên quyết định _có thuộc về đây không_. Bốn dấu hiệu này quyết định
|
|
58
|
+
_làm trước hay sau_.
|
|
59
|
+
|
|
60
|
+
### a. Nó chặn một yêu cầu TIẾP CẬN
|
|
61
|
+
|
|
62
|
+
Không thương lượng, làm trước.
|
|
63
|
+
Ví dụ đã gặp: vòng tiêu điểm của Input là 1px (hạ xuống có chủ ý), không
|
|
64
|
+
đạt WCAG 2.4.11 vốn đòi vùng chỉ báo tương đương đường 2px. Và `FormRoot` không
|
|
65
|
+
có móc `onInvalid`, nên không đưa được tiêu điểm về trường lỗi đầu tiên — WCAG
|
|
66
|
+
3.3.1 / 2.4.3.
|
|
67
|
+
|
|
68
|
+
### b. Nó hỏng IM LẶNG
|
|
69
|
+
|
|
70
|
+
Không lỗi biên dịch, không test đỏ, không cảnh báo — chỉ sai.
|
|
71
|
+
Ví dụ đã gặp: `AppShell` nhận cả `logo` lẫn `topbar` nhưng `resolvedTopbar` trả
|
|
72
|
+
thẳng `topbar`, nên `logo` **không bao giờ được vẽ**. godx-chat truyền cả hai
|
|
73
|
+
suốt nhiều tháng và không ai phát hiện.
|
|
74
|
+
|
|
75
|
+
Lớp lỗi này đắt gấp nhiều lần lớp lỗi ồn ào, vì nó không có ai báo.
|
|
76
|
+
|
|
77
|
+
### c. Đếm được
|
|
78
|
+
|
|
79
|
+
Một khoảng trống đẻ ra N lỗi audit là một khoảng trống có số đo, không phải một
|
|
80
|
+
ý kiến. 42 lỗi từ một prop thiếu là một ưu tiên; một lỗi từ một prop thiếu thì
|
|
81
|
+
chưa chắc.
|
|
82
|
+
|
|
83
|
+
### d. Nó BẤT ĐỐI XỨNG với thứ đã có
|
|
84
|
+
|
|
85
|
+
Nếu trục dọc có `xl` mà trục ngang không có, khoảng trống ấy gần như luôn là
|
|
86
|
+
**quên**, không phải quyết định. Sửa cho cân là rẻ và không tranh cãi.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Cái KHÔNG đáng vào — và vì sao
|
|
91
|
+
|
|
92
|
+
**Bố cục của một màn hình cụ thể.** Nó thuộc về màn hình đó. Nếu ba màn cùng
|
|
93
|
+
cần, lúc ấy nó đã thành hình dạng và quay lại câu hỏi 2.
|
|
94
|
+
|
|
95
|
+
**Một giá trị dùng đúng một lần.** Đừng đẻ prop cho nó — dùng cửa thoát
|
|
96
|
+
(`gapRaw`, `padRaw`). Cửa thoát để lại `data-*-raw` trên DOM nên đếm được; khi
|
|
97
|
+
số đếm ấy lớn lên, ĐÓ mới là lúc nó thành một trục đáng có tên.
|
|
98
|
+
|
|
99
|
+
**Lỗ kiểu dáng tự do** (`styles={{ slot }}`, `classNames={{ slot }}`). Nó đóng
|
|
100
|
+
băng cấu trúc DOM nội bộ thành API công khai, và audit **không đếm được** nó
|
|
101
|
+
(một object style dựng ở đâu cũng được rồi spread vào). Nó cũng ngược hẳn với
|
|
102
|
+
`style: 0/289` — lập trường nhất quán hiện nay là cho prop ý định, không cho lỗ
|
|
103
|
+
kiểu dáng.
|
|
104
|
+
|
|
105
|
+
**Gu thẩm mỹ.** "Dùng nhiều khoảng trắng", "hai màu nhấn là đủ", "tránh lưới
|
|
106
|
+
bento". Không kiểm chứng được, không cổng nào canh, và khi nó tới tay agent
|
|
107
|
+
TRƯỚC luật cứng thì kết quả là mã đẹp mà sai hợp đồng.
|
|
108
|
+
|
|
109
|
+
**Thứ chỉ tiết kiệm vài dòng ở call site.** Nếu đường hiện tại đã hợp lệ và
|
|
110
|
+
đọc được, việc rút ngắn nó không phải việc của design system.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Thêm rồi thì NỢ gì
|
|
115
|
+
|
|
116
|
+
Một prop mới chưa xong khi nó biên dịch được. Ba việc bắt buộc, và cả ba đều đã
|
|
117
|
+
có cổng CI:
|
|
118
|
+
|
|
119
|
+
1. **Vào catalog.** Chạy `node scripts/gen-component-api-manifest.mjs`.
|
|
120
|
+
`check:component-api-manifest` canh việc này. **Không vào catalog thì agent
|
|
121
|
+
không biết nó tồn tại** — và đó không phải giả thuyết: `pad`/`padRaw` được
|
|
122
|
+
thêm vào gói nhưng catalog phát hành chưa có, nên một agent tra MCP đúng quy
|
|
123
|
+
trình vẫn kết luận "Flex chỉ có gap" và bỏ cuộc trước 21 lỗi mà nó có thể
|
|
124
|
+
sửa.
|
|
125
|
+
|
|
126
|
+
2. **Có bằng chứng phủ từng nhánh giá trị.** `component-case-evidence.json` +
|
|
127
|
+
`check:frame-coverage-ledger`. Bằng chứng phải trỏ vào test THẬT SỰ chạy qua
|
|
128
|
+
nhánh ấy, không phải một tệp cho có.
|
|
129
|
+
|
|
130
|
+
3. **Có ví dụ BIÊN DỊCH ĐƯỢC.** Hậu quả đo được khi không kiểm: pattern
|
|
131
|
+
`confirm-destructive` truyền cho `Dialog` một prop `mode` không tồn tại,
|
|
132
|
+
hướng dẫn DataTable dùng `variant="success"` (chính thứ luật
|
|
133
|
+
`status-tone-not-variant` cấm), và ví dụ `Input` gọi một prop
|
|
134
|
+
`onValueChange` không có thật. Agent chép chúng và viết ra mã hỏng.
|
|
135
|
+
|
|
136
|
+
Ba chỗ ấy đã sửa, và `check:doc-prop-existence` nay bắt được lớp lỗi đó.
|
|
137
|
+
Lưu ý khi viết tài liệu: cổng ấy đọc mọi đoạn JSX trong `docs/**` như mã
|
|
138
|
+
THẬT, nên **trích dẫn một API sai để làm ví dụ cũng bị bắt**. Mô tả bằng lời
|
|
139
|
+
như đoạn trên, đừng dán một thẻ JSX hoàn chỉnh vào.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Một lợi ích ẩn của việc rời Radix, đo được
|
|
144
|
+
|
|
145
|
+
`check:doc-prop-existence` canh chiều "mọi prop dùng trong ví dụ đều phải tồn
|
|
146
|
+
tại" — chính lớp lỗi khiến agent chép ví dụ rồi viết ra mã hỏng (prop `mode`
|
|
147
|
+
trên `Dialog`, prop `onValueChange` trên `Input`). Nhưng nó **bỏ qua mọi
|
|
148
|
+
component bọc primitive bên thứ ba**, vì với chúng manifest chỉ là cận dưới:
|
|
149
|
+
prop thật nằm trong types của Radix, generator không mở ra được.
|
|
150
|
+
|
|
151
|
+
Số đo (08/09/2026):
|
|
152
|
+
|
|
153
|
+
| | component KHÔNG kiểm được |
|
|
154
|
+
| --------------------------------------------- | ------------------------- |
|
|
155
|
+
| `main` | **139 / 289** |
|
|
156
|
+
| `feat/v20-react-aria` (6 primitive đã chuyển) | **126 / 289** |
|
|
157
|
+
|
|
158
|
+
Mỗi primitive rời Radix là `declaredIn` chuyển từ `node_modules` vào `src/`, và
|
|
159
|
+
component đó **bước vào vùng kiểm được**. Sáu primitive đầu đã gỡ rào cho 13
|
|
160
|
+
component.
|
|
161
|
+
|
|
162
|
+
Nên đợt đổi nền không chỉ là thay thư viện. Nó là cách duy nhất làm cho 126
|
|
163
|
+
component còn lại có thể được canh — và trong số đó có `Dialog`, `Input`,
|
|
164
|
+
`Badge`, tức đúng những component mà ví dụ sai đã lọt qua.
|
|
165
|
+
|
|
166
|
+
## Khi câu trả lời là "không thuộc về đây"
|
|
167
|
+
|
|
168
|
+
Nói ra ở chỗ gặp nó, bằng mã:
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
/*
|
|
172
|
+
* KHÔNG thuộc về design system: bề rộng này là số đo của riêng màn hình
|
|
173
|
+
* quản trị thành viên, không phải một trục của Table. Nếu màn thứ hai cần
|
|
174
|
+
* cùng thứ, lúc đó mở issue.
|
|
175
|
+
*/
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Một dòng như thế đáng giá hơn một issue mở rồi bỏ đấy — nó nói cho người sau
|
|
179
|
+
biết ai đã cân nhắc, và cân nhắc ra sao.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
|
|
2
|
+
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
3
|
+
import { BarChart } from "@godxjp/ui/charts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 横棒グラフの分類軸と、カードの見出しとの重複 — gh#409 · 1 と 2。
|
|
7
|
+
*
|
|
8
|
+
* 監理団体の実習実施者(受入企業)名は「株式会社」を含む 8〜10 文字の全角で、幅は 100〜125px に
|
|
9
|
+
* なります。分類軸の幅を固定にすると、名前の**先頭**、つまり識別に必要な部分から切り落とされます。
|
|
10
|
+
* BarChart は実際に描画される字形で各目盛りを実測し、いちばん広い目盛りに合わせて軸を確保します。
|
|
11
|
+
* 上限はトークン `--chart-category-axis-max-fraction` が持ち、これを超える名前だけが**末尾**で
|
|
12
|
+
* 省略され、全文は目盛りの `<title>` と図の代替テキストに残ります。
|
|
13
|
+
*
|
|
14
|
+
* 下段のカードは `showCaption={false}`。`CardTitle` が見出しを担うので、キャプションは
|
|
15
|
+
* `sr-only` として DOM に残り、`role="img"` の名前は失われません。
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** 実習実施者ごとの受入人数。企業名は 8〜10 文字の全角で、固定幅の軸では先頭が消えていました。 */
|
|
19
|
+
const acceptances = [
|
|
20
|
+
{ company: "株式会社山田製作所", trainees: 42 },
|
|
21
|
+
{ company: "佐藤食品株式会社", trainees: 35 },
|
|
22
|
+
{ company: "株式会社中村建設", trainees: 28 },
|
|
23
|
+
{ company: "東海精密工業株式会社", trainees: 24 },
|
|
24
|
+
{ company: "みどり農産株式会社", trainees: 18 },
|
|
25
|
+
{ company: "大和金属加工株式会社", trainees: 12 },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
export default function Demo() {
|
|
29
|
+
return (
|
|
30
|
+
<PageContainer
|
|
31
|
+
title="CJK category axis"
|
|
32
|
+
subtitle="横棒グラフの分類軸を実測で確保し、見出しの重複をなくす"
|
|
33
|
+
>
|
|
34
|
+
<Flex direction="col" gap="lg">
|
|
35
|
+
<Card>
|
|
36
|
+
<CardHeader>
|
|
37
|
+
<CardTitle level={2}>横棒 BarChart · 分類軸は目盛りの実測で決まる</CardTitle>
|
|
38
|
+
<CardDescription>
|
|
39
|
+
いちばん広い目盛りに合わせて軸幅を確保します。キャプションは既定どおり表示。
|
|
40
|
+
</CardDescription>
|
|
41
|
+
</CardHeader>
|
|
42
|
+
<CardContent>
|
|
43
|
+
<BarChart
|
|
44
|
+
id="cjk-axis-chart"
|
|
45
|
+
label="実習実施者別 受入人数"
|
|
46
|
+
data={acceptances}
|
|
47
|
+
categoryKey="company"
|
|
48
|
+
series={[{ dataKey: "trainees", label: "受入人数" }]}
|
|
49
|
+
showLegend={false}
|
|
50
|
+
size="md"
|
|
51
|
+
horizontal
|
|
52
|
+
/>
|
|
53
|
+
</CardContent>
|
|
54
|
+
</Card>
|
|
55
|
+
|
|
56
|
+
<Card>
|
|
57
|
+
<CardHeader>
|
|
58
|
+
<CardTitle level={2}>実習実施者別 受入人数</CardTitle>
|
|
59
|
+
<CardDescription>
|
|
60
|
+
`showCaption={"{false}"}` — 見出しは CardTitle が担い、キャプションは sr-only
|
|
61
|
+
として残るのでアクセシブルな名前は保たれます。
|
|
62
|
+
</CardDescription>
|
|
63
|
+
</CardHeader>
|
|
64
|
+
<CardContent>
|
|
65
|
+
<BarChart
|
|
66
|
+
id="cjk-axis-chart-no-caption"
|
|
67
|
+
label="実習実施者別 受入人数"
|
|
68
|
+
data={acceptances}
|
|
69
|
+
categoryKey="company"
|
|
70
|
+
series={[{ dataKey: "trainees", label: "受入人数" }]}
|
|
71
|
+
showLegend={false}
|
|
72
|
+
showCaption={false}
|
|
73
|
+
size="md"
|
|
74
|
+
horizontal
|
|
75
|
+
/>
|
|
76
|
+
</CardContent>
|
|
77
|
+
</Card>
|
|
78
|
+
</Flex>
|
|
79
|
+
</PageContainer>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
@@ -281,6 +281,28 @@ export default function Demo() {
|
|
|
281
281
|
</Card>
|
|
282
282
|
</ResponsiveGrid>
|
|
283
283
|
</Flex>
|
|
284
|
+
|
|
285
|
+
<Card>
|
|
286
|
+
<CardHeader>
|
|
287
|
+
<CardTitle level={2}>連続したツールバー</CardTitle>
|
|
288
|
+
</CardHeader>
|
|
289
|
+
<CardContent>
|
|
290
|
+
<Text>本文</Text>
|
|
291
|
+
</CardContent>
|
|
292
|
+
<CardBar pad={{ block: 1, inline: 3 }} surface="muted" border="block-start" gap="sm">
|
|
293
|
+
<Button variant="ghost" size="sm">
|
|
294
|
+
添付
|
|
295
|
+
</Button>
|
|
296
|
+
</CardBar>
|
|
297
|
+
<CardBar
|
|
298
|
+
pad={{ block: 2, inline: 3 }}
|
|
299
|
+
border="block-start"
|
|
300
|
+
gap="sm"
|
|
301
|
+
extra={<Button>送信</Button>}
|
|
302
|
+
>
|
|
303
|
+
<Text tone="muted">下書きを保存しました</Text>
|
|
304
|
+
</CardBar>
|
|
305
|
+
</Card>
|
|
284
306
|
</Flex>
|
|
285
307
|
</PageContainer>
|
|
286
308
|
);
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Card,
|
|
5
|
+
CardContent,
|
|
6
|
+
Badge,
|
|
7
|
+
DataTable,
|
|
8
|
+
Descriptions,
|
|
9
|
+
TableCell,
|
|
10
|
+
TableRow,
|
|
11
|
+
type ColumnDef,
|
|
12
|
+
} from "@godxjp/ui/data-display";
|
|
13
|
+
import { Text } from "@godxjp/ui/general";
|
|
14
|
+
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* DataTable / Descriptions — the Ant Design 6.6.2 parity surface on one screen: frozen columns
|
|
18
|
+
* (`fixed`), truncation (`ellipsis`), multi-column sort (`sorter.multiple`), header filters
|
|
19
|
+
* (`filters` + `onFilter`), the full `rowSelection` object, `expandable` detail rows, a `summary`
|
|
20
|
+
* totals row, a `scroll` envelope and a bordered `Descriptions` on a responsive column ladder.
|
|
21
|
+
*
|
|
22
|
+
* It is also the MEASUREMENT surface: the frozen columns and the scroll envelope are geometry, and
|
|
23
|
+
* geometry is verified against this page in a browser, not by eye.
|
|
24
|
+
*/
|
|
25
|
+
type Line = {
|
|
26
|
+
id: string;
|
|
27
|
+
code: string;
|
|
28
|
+
partner: string;
|
|
29
|
+
note: string;
|
|
30
|
+
status: "active" | "pending" | "failed";
|
|
31
|
+
region: string;
|
|
32
|
+
owner: string;
|
|
33
|
+
updated: string;
|
|
34
|
+
amount: number;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const STATUS_TONE = { active: "success", pending: "warning", failed: "destructive" } as const;
|
|
38
|
+
const STATUS_LABEL = { active: "有効", pending: "保留", failed: "失敗" } as const;
|
|
39
|
+
|
|
40
|
+
const BASE_ROWS: Line[] = [
|
|
41
|
+
{
|
|
42
|
+
id: "L-1",
|
|
43
|
+
code: "INV-0312",
|
|
44
|
+
partner: "株式会社ベトヤ",
|
|
45
|
+
note: "四月分の請求。検収は完了しているが振込確認が未了のため保留にしている。",
|
|
46
|
+
status: "active",
|
|
47
|
+
region: "関東",
|
|
48
|
+
owner: "田中",
|
|
49
|
+
updated: "2024-04-12",
|
|
50
|
+
amount: 482000,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "L-2",
|
|
54
|
+
code: "INV-0311",
|
|
55
|
+
partner: "ハノイ物流",
|
|
56
|
+
note: "越境輸送分。通関書類の差し替えを依頼済み。",
|
|
57
|
+
status: "pending",
|
|
58
|
+
region: "海外",
|
|
59
|
+
owner: "佐藤",
|
|
60
|
+
updated: "2024-04-11",
|
|
61
|
+
amount: 128400,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "L-3",
|
|
65
|
+
code: "INV-0310",
|
|
66
|
+
partner: "GMO決済",
|
|
67
|
+
note: "決済手数料。月次で自動計上される。",
|
|
68
|
+
status: "active",
|
|
69
|
+
region: "関東",
|
|
70
|
+
owner: "田中",
|
|
71
|
+
updated: "2024-04-10",
|
|
72
|
+
amount: 64800,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: "L-4",
|
|
76
|
+
code: "INV-0309",
|
|
77
|
+
partner: "東京ロジ",
|
|
78
|
+
note: "再送分。前回の請求が差し戻されたため再発行している。",
|
|
79
|
+
status: "failed",
|
|
80
|
+
region: "関東",
|
|
81
|
+
owner: "鈴木",
|
|
82
|
+
updated: "2024-04-09",
|
|
83
|
+
amount: 312000,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: "L-5",
|
|
87
|
+
code: "INV-0308",
|
|
88
|
+
partner: "大阪商事",
|
|
89
|
+
note: "年間契約の四半期按分。",
|
|
90
|
+
status: "pending",
|
|
91
|
+
region: "関西",
|
|
92
|
+
owner: "鈴木",
|
|
93
|
+
updated: "2024-04-08",
|
|
94
|
+
amount: 900500,
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Enough rows for the `scroll.y` envelope to actually bite — five rows never reach an 18rem cap,
|
|
100
|
+
* and a cap that never clips proves nothing.
|
|
101
|
+
*/
|
|
102
|
+
const ROWS: Line[] = [
|
|
103
|
+
...BASE_ROWS,
|
|
104
|
+
...BASE_ROWS.map((row, i) => ({
|
|
105
|
+
...row,
|
|
106
|
+
id: `${row.id}-b`,
|
|
107
|
+
code: `INV-02${String(10 + i).padStart(2, "0")}`,
|
|
108
|
+
updated: `2024-03-${String(10 + i).padStart(2, "0")}`,
|
|
109
|
+
})),
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
const yen = new Intl.NumberFormat("ja-JP", {
|
|
113
|
+
style: "currency",
|
|
114
|
+
currency: "JPY",
|
|
115
|
+
maximumFractionDigits: 0,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const columns: ColumnDef<Line>[] = [
|
|
119
|
+
// Frozen to the inline start — the identity column stays put while the grid scrolls.
|
|
120
|
+
{ key: "code", header: "伝票番号", fixed: "start", width: "150px", sorter: { multiple: 2 } },
|
|
121
|
+
{ key: "partner", header: "取引先", width: "220px" },
|
|
122
|
+
// One line, truncated, with the full text kept as the cell's title.
|
|
123
|
+
{ key: "note", header: "備考", ellipsis: true, width: "260px" },
|
|
124
|
+
{
|
|
125
|
+
key: "status",
|
|
126
|
+
header: "状態",
|
|
127
|
+
width: "140px",
|
|
128
|
+
filters: [
|
|
129
|
+
{ text: "有効", value: "active" },
|
|
130
|
+
{ text: "保留", value: "pending" },
|
|
131
|
+
{ text: "失敗", value: "failed" },
|
|
132
|
+
],
|
|
133
|
+
onFilter: (value, row) => row.status === value,
|
|
134
|
+
render: (row) => <Badge tone={STATUS_TONE[row.status]}>{STATUS_LABEL[row.status]}</Badge>,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
key: "region",
|
|
138
|
+
header: "地域",
|
|
139
|
+
width: "140px",
|
|
140
|
+
filters: [
|
|
141
|
+
{ text: "関東", value: "関東" },
|
|
142
|
+
{ text: "関西", value: "関西" },
|
|
143
|
+
{ text: "海外", value: "海外" },
|
|
144
|
+
],
|
|
145
|
+
filterMultiple: false,
|
|
146
|
+
onFilter: (value, row) => row.region === value,
|
|
147
|
+
},
|
|
148
|
+
{ key: "owner", header: "担当", width: "140px", sorter: { multiple: 1 } },
|
|
149
|
+
{
|
|
150
|
+
key: "updated",
|
|
151
|
+
header: "更新日",
|
|
152
|
+
width: "160px",
|
|
153
|
+
sorter: true,
|
|
154
|
+
sortDirections: ["desc", "asc"],
|
|
155
|
+
},
|
|
156
|
+
// Frozen to the inline end — the amount stays readable at any scroll position.
|
|
157
|
+
{
|
|
158
|
+
key: "amount",
|
|
159
|
+
header: "金額",
|
|
160
|
+
align: "right",
|
|
161
|
+
fixed: "end",
|
|
162
|
+
width: "160px",
|
|
163
|
+
sorter: (a, b) => a.amount - b.amount,
|
|
164
|
+
render: (row) => yen.format(row.amount),
|
|
165
|
+
},
|
|
166
|
+
];
|
|
167
|
+
|
|
168
|
+
export default function AntdParityDemo() {
|
|
169
|
+
const [selected, setSelected] = useState<string[]>([]);
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<PageContainer title="Ant Design パリティ" subtitle="DataTable / Descriptions">
|
|
173
|
+
<Flex direction="col" gap="lg">
|
|
174
|
+
<Card>
|
|
175
|
+
<CardContent flush>
|
|
176
|
+
<DataTable
|
|
177
|
+
data={ROWS}
|
|
178
|
+
columns={columns}
|
|
179
|
+
getRowId={(row) => row.id}
|
|
180
|
+
bordered
|
|
181
|
+
showSorterTooltip
|
|
182
|
+
scroll={{ x: 1400, y: "18rem" }}
|
|
183
|
+
sticky
|
|
184
|
+
rowSelection={{
|
|
185
|
+
selectedRowKeys: selected,
|
|
186
|
+
onChange: (keys) => {
|
|
187
|
+
setSelected(keys);
|
|
188
|
+
},
|
|
189
|
+
selections: true,
|
|
190
|
+
getCheckboxProps: (row) => ({ disabled: row.status === "failed" }),
|
|
191
|
+
preserveSelectedRowKeys: true,
|
|
192
|
+
}}
|
|
193
|
+
expandable={{
|
|
194
|
+
expandedRowRender: (row) => (
|
|
195
|
+
<Descriptions bordered columns={{ sm: 2, lg: 3 }} layout="horizontal">
|
|
196
|
+
<Descriptions.Item label="伝票番号" mono>
|
|
197
|
+
{row.code}
|
|
198
|
+
</Descriptions.Item>
|
|
199
|
+
<Descriptions.Item label="担当">{row.owner}</Descriptions.Item>
|
|
200
|
+
<Descriptions.Item label="地域">{row.region}</Descriptions.Item>
|
|
201
|
+
<Descriptions.Item label="備考" span="filled">
|
|
202
|
+
{row.note}
|
|
203
|
+
</Descriptions.Item>
|
|
204
|
+
</Descriptions>
|
|
205
|
+
),
|
|
206
|
+
rowExpandable: (row) => row.status !== "failed",
|
|
207
|
+
}}
|
|
208
|
+
summary={(rows) => (
|
|
209
|
+
<TableRow>
|
|
210
|
+
<TableCell />
|
|
211
|
+
<TableCell />
|
|
212
|
+
<TableCell>合計</TableCell>
|
|
213
|
+
<TableCell />
|
|
214
|
+
<TableCell />
|
|
215
|
+
<TableCell />
|
|
216
|
+
<TableCell />
|
|
217
|
+
<TableCell />
|
|
218
|
+
<TableCell>
|
|
219
|
+
{yen.format(rows.reduce((sum, row) => sum + row.amount, 0))}
|
|
220
|
+
</TableCell>
|
|
221
|
+
</TableRow>
|
|
222
|
+
)}
|
|
223
|
+
onRow={(row) => ({ "data-row-key": row.id })}
|
|
224
|
+
>
|
|
225
|
+
<DataTable.Toolbar>
|
|
226
|
+
<DataTable.Search />
|
|
227
|
+
<Flex direction="row" gap="sm" align="center">
|
|
228
|
+
<DataTable.ViewOptions />
|
|
229
|
+
<DataTable.DensityToggle />
|
|
230
|
+
</Flex>
|
|
231
|
+
</DataTable.Toolbar>
|
|
232
|
+
<DataTable.Content />
|
|
233
|
+
<DataTable.Pagination />
|
|
234
|
+
</DataTable>
|
|
235
|
+
</CardContent>
|
|
236
|
+
</Card>
|
|
237
|
+
|
|
238
|
+
<Card>
|
|
239
|
+
<CardContent>
|
|
240
|
+
<Text size="sm" tone="muted">
|
|
241
|
+
選択中: {selected.length} 件
|
|
242
|
+
</Text>
|
|
243
|
+
<Descriptions bordered columns={{ sm: 2, lg: 4 }}>
|
|
244
|
+
<Descriptions.Item label="伝票数">{ROWS.length}</Descriptions.Item>
|
|
245
|
+
<Descriptions.Item label="通貨">JPY</Descriptions.Item>
|
|
246
|
+
<Descriptions.Item label="期間">2024-04-08 ~ 2024-04-12</Descriptions.Item>
|
|
247
|
+
<Descriptions.Item label="ステータス">確定前</Descriptions.Item>
|
|
248
|
+
<Descriptions.Item label="メモ" span="filled">
|
|
249
|
+
Ant Design 6.6.2 の `bordered` と `column` レスポンシブ指定をそのまま受ける。
|
|
250
|
+
</Descriptions.Item>
|
|
251
|
+
</Descriptions>
|
|
252
|
+
</CardContent>
|
|
253
|
+
</Card>
|
|
254
|
+
</Flex>
|
|
255
|
+
</PageContainer>
|
|
256
|
+
);
|
|
257
|
+
}
|