@godxjp/ui 19.1.0 → 19.3.1
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 +25 -128
- package/dist/app/theme-axes.d.ts +4 -15
- package/dist/app/timezones.d.ts +1 -4
- package/dist/components/charts/area-chart.d.ts +2 -3
- package/dist/components/charts/bar-chart.d.ts +2 -3
- package/dist/components/charts/chart-frame.d.ts +7 -16
- package/dist/components/charts/chart-summary.d.ts +2 -2
- package/dist/components/charts/compact-bar-trend.d.ts +9 -24
- package/dist/components/charts/index.d.ts +1 -6
- package/dist/components/data-display/badge.d.ts +20 -14
- package/dist/components/data-display/badge.js +18 -4
- package/dist/components/data-display/card.d.ts +21 -41
- package/dist/components/data-display/carousel.d.ts +1 -2
- package/dist/components/data-display/code-block.d.ts +4 -0
- package/dist/components/data-display/code-block.js +24 -0
- package/dist/components/data-display/data-table.d.ts +15 -37
- package/dist/components/data-display/data-table.js +1 -3
- package/dist/components/data-display/descriptions.d.ts +2 -6
- package/dist/components/data-display/descriptions.js +0 -2
- package/dist/components/data-display/index.d.ts +4 -0
- package/dist/components/data-display/index.js +4 -0
- package/dist/components/data-display/list-row.d.ts +3 -22
- package/dist/components/data-display/permission-matrix.d.ts +7 -20
- package/dist/components/data-display/progress.d.ts +1 -1
- package/dist/components/data-display/prose.d.ts +4 -0
- package/dist/components/data-display/prose.js +20 -0
- package/dist/components/data-display/service-launcher-card.d.ts +3 -10
- package/dist/components/data-display/table.d.ts +20 -80
- package/dist/components/data-display/table.js +0 -3
- package/dist/components/data-display/timeline.d.ts +3 -5
- package/dist/components/data-entry/branch-scope-picker.d.ts +2 -19
- package/dist/components/data-entry/branch-scope-picker.js +0 -1
- package/dist/components/data-entry/calendar.d.ts +3 -2
- package/dist/components/data-entry/calendar.js +58 -3
- package/dist/components/data-entry/command-palette.d.ts +8 -22
- package/dist/components/data-entry/date-picker.d.ts +4 -5
- package/dist/components/data-entry/date-picker.js +6 -1
- package/dist/components/data-entry/date-range-picker.d.ts +1 -1
- package/dist/components/data-entry/date-range-picker.js +8 -3
- package/dist/components/data-entry/form-errors.d.ts +7 -18
- package/dist/components/data-entry/form-field.js +1 -5
- package/dist/components/data-entry/form.d.ts +1 -9
- package/dist/components/data-entry/input.d.ts +16 -14
- package/dist/components/data-entry/input.js +3 -0
- package/dist/components/data-entry/month-picker.js +2 -2
- package/dist/components/data-entry/month-range-picker.d.ts +4 -6
- package/dist/components/data-entry/month-range-picker.js +2 -2
- package/dist/components/data-entry/number-input.d.ts +1 -5
- package/dist/components/data-entry/number-input.js +1 -0
- package/dist/components/data-entry/radio.js +0 -1
- package/dist/components/data-entry/search-select.d.ts +2 -4
- package/dist/components/data-entry/select.d.ts +11 -6
- package/dist/components/data-entry/select.js +4 -2
- package/dist/components/data-entry/switch.js +0 -1
- package/dist/components/data-entry/textarea.d.ts +10 -16
- package/dist/components/data-entry/time-picker.d.ts +3 -5
- package/dist/components/data-entry/upload-types.d.ts +1 -5
- package/dist/components/data-entry/use-upload-draft.d.ts +0 -4
- package/dist/components/feedback/dialog.d.ts +6 -15
- package/dist/components/feedback/overlay-header-tone.d.ts +1 -1
- package/dist/components/feedback/sheet.d.ts +3 -10
- package/dist/components/feedback/sheet.js +1 -1
- package/dist/components/feedback/sonner.js +2 -3
- package/dist/components/general/activity.d.ts +4 -30
- package/dist/components/general/button.js +1 -10
- package/dist/components/general/logo.d.ts +6 -28
- package/dist/components/general/reveal.d.ts +3 -9
- package/dist/components/general/typography.d.ts +1 -3
- package/dist/components/layout/account-chip.d.ts +8 -0
- package/dist/components/layout/account-chip.js +45 -0
- package/dist/components/layout/auth-divider.d.ts +2 -9
- package/dist/components/layout/auth-shell.d.ts +1 -14
- package/dist/components/layout/breadcrumb.d.ts +1 -5
- package/dist/components/layout/centered-shell.d.ts +4 -18
- package/dist/components/layout/error-surface.d.ts +11 -28
- package/dist/components/layout/error-surface.js +4 -1
- package/dist/components/layout/index.d.ts +2 -0
- package/dist/components/layout/index.js +2 -0
- package/dist/components/layout/legal-document-shell.d.ts +5 -28
- package/dist/components/layout/master-detail.d.ts +2 -18
- package/dist/components/layout/page-container.js +0 -1
- package/dist/components/layout/responsive-grid.d.ts +6 -1
- package/dist/components/layout/responsive-grid.js +9 -2
- package/dist/components/layout/service-role-panel.d.ts +7 -19
- package/dist/components/layout/sidebar.d.ts +5 -27
- package/dist/components/layout/sidebar.js +0 -1
- package/dist/components/layout/split-pane.d.ts +0 -7
- package/dist/components/layout/topbar.d.ts +1 -14
- package/dist/components/navigation/app-setting-picker.js +1 -3
- package/dist/components/navigation/filter-bar.d.ts +1 -6
- package/dist/components/navigation/pagination-utils.d.ts +2 -12
- package/dist/components/navigation/tabs-scroll.d.ts +2 -36
- package/dist/components/navigation/tabs.js +4 -8
- package/dist/components/query/data-state.d.ts +2 -2
- package/dist/components/ui/credential-reveal.d.ts +1 -4
- package/dist/components/ui/hover-card.d.ts +1 -2
- package/dist/components/ui/separator.d.ts +2 -15
- package/dist/components/ui/toggle-group.d.ts +1 -5
- package/dist/components/ui/toggle.d.ts +6 -31
- package/dist/email/brand-mark.d.ts +6 -34
- package/dist/email/color.d.ts +7 -17
- package/dist/email/geometry.d.ts +4 -8
- package/dist/email/index.d.ts +4 -48
- package/dist/email/inline-style.d.ts +3 -9
- package/dist/email/urgency.d.ts +2 -7
- package/dist/form/form-context.d.ts +2 -5
- package/dist/form/form-root.d.ts +1 -2
- package/dist/i18n/messages/en.json +4 -0
- package/dist/i18n/messages/ja.json +4 -0
- package/dist/i18n/messages/vi.json +4 -0
- package/dist/inertia/index.d.ts +2 -10
- package/dist/lib/control-styles.d.ts +10 -21
- package/dist/lib/control-styles.js +4 -6
- package/dist/lib/datetime/format-date.d.ts +1 -4
- package/dist/lib/field-a11y.d.ts +11 -68
- package/dist/lib/field-a11y.js +0 -1
- package/dist/lib/format.d.ts +4 -8
- package/dist/lib/hooks.d.ts +6 -12
- package/dist/lib/permission-grid.d.ts +3 -18
- package/dist/lib/query-error.d.ts +3 -3
- package/dist/props/components/app.prop.d.ts +15 -38
- package/dist/props/components/charts.prop.d.ts +2 -3
- package/dist/props/components/data-display.prop.d.ts +55 -72
- package/dist/props/components/data-entry.prop.d.ts +35 -40
- package/dist/props/components/form.prop.d.ts +2 -6
- package/dist/props/components/general.prop.d.ts +11 -27
- package/dist/props/components/layout.prop.d.ts +89 -260
- package/dist/props/components/navigation.prop.d.ts +27 -42
- package/dist/props/registry.d.ts +36 -1
- package/dist/props/registry.js +45 -1
- package/dist/props/vocabulary/data.prop.d.ts +18 -49
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/props/vocabulary/interaction.prop.d.ts +10 -12
- package/dist/props/vocabulary/layout.prop.d.ts +8 -30
- package/dist/props/vocabulary/shared.prop.d.ts +3 -2
- package/dist/styles/alert-layout.css +1 -32
- package/dist/styles/badge-layout.css +19 -18
- package/dist/styles/base.css +14 -113
- package/dist/styles/card-layout.css +6 -128
- package/dist/styles/chart-layout.css +2 -17
- package/dist/styles/control.css +380 -458
- package/dist/styles/core.css +21 -0
- package/dist/styles/data-display-layout.css +175 -94
- package/dist/styles/data-entry-layout.css +0 -45
- package/dist/styles/density.css +1 -30
- package/dist/styles/dialog-layout.css +5 -69
- package/dist/styles/focus-ring.css +13 -87
- package/dist/styles/fonts.css +1 -31
- package/dist/styles/form-layout.css +7 -91
- package/dist/styles/index.css +2 -20
- package/dist/styles/layout.css +38 -456
- package/dist/styles/logo-layout.css +1 -35
- package/dist/styles/motion.css +3 -42
- package/dist/styles/navigation-layout.css +3 -50
- package/dist/styles/shell-layout.css +37 -403
- package/dist/styles/table-layout.css +16 -274
- package/dist/styles/text-layout.css +7 -21
- package/dist/styles/toggle.css +1 -23
- package/dist/theme/dxs.canonical.css +1 -55
- package/dist/theme/example.service.css +1 -26
- package/dist/theme/famgia.service.css +5 -15
- package/dist/tokens/axes.css +3 -40
- package/dist/tokens/base.css +1 -4
- package/dist/tokens/components/activity.css +6 -42
- package/dist/tokens/components/badge.css +12 -13
- package/dist/tokens/components/banner.css +4 -9
- package/dist/tokens/components/card.css +32 -88
- package/dist/tokens/components/chart.css +9 -26
- package/dist/tokens/components/control.css +37 -222
- package/dist/tokens/components/data-display.css +28 -79
- package/dist/tokens/components/data-entry.css +5 -19
- package/dist/tokens/components/descriptions.css +7 -27
- package/dist/tokens/components/email.css +38 -84
- package/dist/tokens/components/error-surface.css +2 -18
- package/dist/tokens/components/feedback.css +27 -124
- package/dist/tokens/components/form.css +13 -45
- package/dist/tokens/components/legal-document.css +16 -41
- package/dist/tokens/components/list-row.css +11 -36
- package/dist/tokens/components/logo.css +2 -57
- package/dist/tokens/components/navigation.css +16 -94
- package/dist/tokens/components/scroll-area.css +2 -18
- package/dist/tokens/components/separator.css +8 -30
- package/dist/tokens/components/sheet.css +3 -14
- package/dist/tokens/components/shell.css +53 -307
- package/dist/tokens/components/sidebar.css +5 -22
- package/dist/tokens/components/table.css +19 -140
- package/dist/tokens/components/toggle.css +3 -65
- package/dist/tokens/components/upload.css +7 -43
- package/dist/tokens/foundation.css +108 -383
- package/dist/tokens/semantic/layout.css +33 -207
- package/docs/CANONICAL-CONTRACTS.md +206 -0
- package/docs/COMPONENTS.md +157 -0
- package/docs/COMPOSITION-VS-COMPONENT.md +105 -0
- package/docs/CONSUMER-RULES.md +14 -0
- package/docs/CUSTOMER-THEMING.md +162 -0
- package/docs/DATETIME.md +69 -0
- package/docs/DEVELOPMENT.md +173 -0
- package/docs/FORMS.md +143 -0
- package/docs/FRAME-A11Y-CI.md +267 -0
- package/docs/FRAME-COVERAGE-LEDGER.md +123 -0
- package/docs/FRAME-COVERAGE-REPORT.md +140 -0
- package/docs/FRAME-COVERAGE-STANDARD.md +65 -0
- package/docs/FRAME-COVERAGE.md +29 -0
- package/docs/PROPS-REGISTRY.md +61 -0
- package/docs/PROPS-VOCABULARY.md +100 -0
- package/docs/README.md +60 -0
- package/docs/REGISTRY.md +70 -0
- package/docs/SPACING.md +56 -0
- package/docs/STANDARDS-vocabulary-tokens.md +48 -0
- package/docs/TESTING.md +98 -0
- package/docs/TOKENS.md +347 -0
- package/docs/asset-modules.d.ts +46 -0
- package/docs/assets/cover-terrain.svg +6 -0
- package/docs/assets/portrait-amber.svg +5 -0
- package/docs/assets/portrait-clay.svg +5 -0
- package/docs/assets/portrait-indigo.svg +5 -0
- package/docs/assets/portrait-iris.svg +5 -0
- package/docs/assets/portrait-moss.svg +5 -0
- package/docs/assets/portrait-plum.svg +5 -0
- package/docs/assets/portrait-slate.svg +5 -0
- package/docs/charts/compact-bar-trend.tsx +328 -0
- package/docs/charts/size-tiers.tsx +192 -0
- package/docs/data-display/accordion.tsx +99 -0
- package/docs/data-display/avatar.tsx +355 -0
- package/docs/data-display/badge.tsx +283 -0
- package/docs/data-display/card/examples/detail-panel.tsx +106 -0
- package/docs/data-display/card/index.md +3 -0
- package/docs/data-display/card/index.tsx +285 -0
- package/docs/data-display/carousel.tsx +160 -0
- package/docs/data-display/charts.tsx +198 -0
- package/docs/data-display/code-block.tsx +90 -0
- package/docs/data-display/collapsible.tsx +162 -0
- package/docs/data-display/credential-reveal.tsx +145 -0
- package/docs/data-display/data-table/examples/approval-queue.tsx +212 -0
- package/docs/data-display/data-table/examples/grid-features.tsx +158 -0
- package/docs/data-display/data-table/examples/list-page.tsx +175 -0
- package/docs/data-display/data-table/index.md +5 -0
- package/docs/data-display/data-table/index.tsx +295 -0
- package/docs/data-display/descriptions.tsx +143 -0
- package/docs/data-display/empty-state.tsx +164 -0
- package/docs/data-display/hover-card.tsx +181 -0
- package/docs/data-display/list-row.tsx +420 -0
- package/docs/data-display/permission-matrix.tsx +188 -0
- package/docs/data-display/popover-touch.tsx +27 -0
- package/docs/data-display/popover.tsx +246 -0
- package/docs/data-display/progress.tsx +84 -0
- package/docs/data-display/prose.tsx +105 -0
- package/docs/data-display/qr-code.tsx +68 -0
- package/docs/data-display/scroll-area.tsx +303 -0
- package/docs/data-display/service-launcher-card.tsx +145 -0
- package/docs/data-display/stat-card.tsx +99 -0
- package/docs/data-display/table.tsx +251 -0
- package/docs/data-display/timeline.tsx +112 -0
- package/docs/data-display/touch-actions.tsx +36 -0
- package/docs/data-display/tree-list.tsx +107 -0
- package/docs/data-entry/branch-scope-picker.tsx +123 -0
- package/docs/data-entry/calendar.tsx +180 -0
- package/docs/data-entry/cascader.tsx +378 -0
- package/docs/data-entry/checkbox.tsx +256 -0
- package/docs/data-entry/color-picker.tsx +117 -0
- package/docs/data-entry/command-palette.tsx +179 -0
- package/docs/data-entry/command.tsx +262 -0
- package/docs/data-entry/country-picker-recipe.tsx +175 -0
- package/docs/data-entry/date-picker.tsx +191 -0
- package/docs/data-entry/date-range-picker.tsx +149 -0
- package/docs/data-entry/form/examples/employee-settings.tsx +267 -0
- package/docs/data-entry/form/examples/invoice-form.tsx +387 -0
- package/docs/data-entry/form-field/examples/a11y-contract.tsx +240 -0
- package/docs/data-entry/form-field/examples/create-form.tsx +105 -0
- package/docs/data-entry/form-field/index.md +8 -0
- package/docs/data-entry/form-field/index.tsx +330 -0
- package/docs/data-entry/form-inertia.tsx +80 -0
- package/docs/data-entry/form-root.tsx +102 -0
- package/docs/data-entry/form.tsx +724 -0
- package/docs/data-entry/input-otp.tsx +231 -0
- package/docs/data-entry/input.tsx +114 -0
- package/docs/data-entry/label.tsx +100 -0
- package/docs/data-entry/month-picker.tsx +101 -0
- package/docs/data-entry/month-range-picker.tsx +115 -0
- package/docs/data-entry/number-input.tsx +240 -0
- package/docs/data-entry/password-input.tsx +102 -0
- package/docs/data-entry/password-strength.tsx +97 -0
- package/docs/data-entry/radio-group.tsx +95 -0
- package/docs/data-entry/rating.tsx +87 -0
- package/docs/data-entry/search-input.tsx +120 -0
- package/docs/data-entry/select-async-contracts.tsx +108 -0
- package/docs/data-entry/select-matrix.tsx +204 -0
- package/docs/data-entry/select.tsx +369 -0
- package/docs/data-entry/slider.tsx +130 -0
- package/docs/data-entry/switch.tsx +67 -0
- package/docs/data-entry/tag-input.tsx +108 -0
- package/docs/data-entry/textarea.tsx +209 -0
- package/docs/data-entry/time-picker.tsx +99 -0
- package/docs/data-entry/toggle-count.tsx +293 -0
- package/docs/data-entry/toggle-group.tsx +225 -0
- package/docs/data-entry/toggle.tsx +127 -0
- package/docs/data-entry/transfer.tsx +97 -0
- package/docs/data-entry/tree-select.tsx +204 -0
- package/docs/data-entry/upload.tsx +184 -0
- package/docs/feedback/alert-dialog.tsx +270 -0
- package/docs/feedback/alert.tsx +248 -0
- package/docs/feedback/banner.tsx +183 -0
- package/docs/feedback/danger-confirm.tsx +88 -0
- package/docs/feedback/dialog-touch.tsx +24 -0
- package/docs/feedback/dialog.tsx +193 -0
- package/docs/feedback/sheet.tsx +420 -0
- package/docs/feedback/skeleton.tsx +111 -0
- package/docs/feedback/toast.tsx +135 -0
- package/docs/feedback/tooltip.tsx +171 -0
- package/docs/feedback/two-factor-setup.tsx +68 -0
- package/docs/foundation/_email-specimen.ts +274 -0
- package/docs/foundation/colors.tsx +204 -0
- package/docs/foundation/density.tsx +232 -0
- package/docs/foundation/email-tokens.tsx +323 -0
- package/docs/foundation/radius-shadow.tsx +154 -0
- package/docs/foundation/spacing.tsx +211 -0
- package/docs/foundation/typography.tsx +147 -0
- package/docs/general/activity.tsx +224 -0
- package/docs/general/button/examples/destructive-confirm.tsx +90 -0
- package/docs/general/button/examples/form-actions.tsx +85 -0
- package/docs/general/button/examples/toolbar.tsx +160 -0
- package/docs/general/button/index.md +12 -0
- package/docs/general/button/index.tsx +211 -0
- package/docs/general/logo.tsx +131 -0
- package/docs/general/reveal.tsx +41 -0
- package/docs/general/typography.tsx +152 -0
- package/docs/layout/account-chip.tsx +72 -0
- package/docs/layout/admin-collection.tsx +122 -0
- package/docs/layout/app-shell.tsx +374 -0
- package/docs/layout/aspect-ratio.tsx +135 -0
- package/docs/layout/auth-account-summary.tsx +103 -0
- package/docs/layout/auth-divider.tsx +28 -0
- package/docs/layout/auth-footer.tsx +37 -0
- package/docs/layout/auth-identity.tsx +36 -0
- package/docs/layout/auth-recovery/examples/mfa-challenge.md +41 -0
- package/docs/layout/auth-recovery/examples/mfa-challenge.tsx +254 -0
- package/docs/layout/auth-recovery/examples/mobile-390.md +25 -0
- package/docs/layout/auth-recovery/examples/mobile-390.tsx +82 -0
- package/docs/layout/auth-recovery/examples/password-recovery.md +24 -0
- package/docs/layout/auth-recovery/examples/password-recovery.tsx +197 -0
- package/docs/layout/auth-recovery/examples/wrapping-ja-en-vi.md +27 -0
- package/docs/layout/auth-recovery/examples/wrapping-ja-en-vi.tsx +156 -0
- package/docs/layout/auth-recovery/index.md +140 -0
- package/docs/layout/auth-recovery/index.tsx +96 -0
- package/docs/layout/auth-shell-context.tsx +103 -0
- package/docs/layout/auth-shell-device.tsx +112 -0
- package/docs/layout/auth-shell-registration.tsx +335 -0
- package/docs/layout/auth-shell-variants.tsx +139 -0
- package/docs/layout/auth-shell.tsx +59 -0
- package/docs/layout/auth-stack.tsx +40 -0
- package/docs/layout/centered-shell.tsx +102 -0
- package/docs/layout/error-surface/examples/application-403.tsx +84 -0
- package/docs/layout/error-surface/examples/application-404.tsx +77 -0
- package/docs/layout/error-surface/examples/system-500.tsx +47 -0
- package/docs/layout/error-surface/examples/system-503.tsx +48 -0
- package/docs/layout/error-surface/index.md +153 -0
- package/docs/layout/error-surface/index.tsx +239 -0
- package/docs/layout/flex.tsx +266 -0
- package/docs/layout/legal-document-shell/_data.ts +110 -0
- package/docs/layout/legal-document-shell/examples/desktop-1440.md +12 -0
- package/docs/layout/legal-document-shell/examples/desktop-1440.tsx +83 -0
- package/docs/layout/legal-document-shell/examples/mobile-390.md +22 -0
- package/docs/layout/legal-document-shell/examples/mobile-390.tsx +70 -0
- package/docs/layout/legal-document-shell/examples/tablet-1024.md +3 -0
- package/docs/layout/legal-document-shell/examples/tablet-1024.tsx +84 -0
- package/docs/layout/legal-document-shell/examples/wrapping-ja-en-vi.md +18 -0
- package/docs/layout/legal-document-shell/examples/wrapping-ja-en-vi.tsx +61 -0
- package/docs/layout/legal-document-shell/index.md +51 -0
- package/docs/layout/legal-document-shell/index.tsx +101 -0
- package/docs/layout/master-detail.tsx +387 -0
- package/docs/layout/org-switcher.tsx +131 -0
- package/docs/layout/page-container.tsx +954 -0
- package/docs/layout/resizable-panel.tsx +419 -0
- package/docs/layout/responsive-grid.tsx +243 -0
- package/docs/layout/separator.tsx +327 -0
- package/docs/layout/service-role-panel.tsx +144 -0
- package/docs/layout/sidebar.tsx +609 -0
- package/docs/layout/split-pane.tsx +468 -0
- package/docs/layout/topbar.tsx +349 -0
- package/docs/navigation/app-setting-picker.tsx +142 -0
- package/docs/navigation/breadcrumb.tsx +135 -0
- package/docs/navigation/context-menu.tsx +123 -0
- package/docs/navigation/dropdown-menu.tsx +213 -0
- package/docs/navigation/filter-bar.tsx +227 -0
- package/docs/navigation/menubar.tsx +141 -0
- package/docs/navigation/navigation-menu.tsx +158 -0
- package/docs/navigation/pagination.tsx +241 -0
- package/docs/navigation/steps.tsx +265 -0
- package/docs/navigation/tabs-rtl.tsx +28 -0
- package/docs/navigation/tabs.tsx +314 -0
- package/docs/navigation/toolbar.tsx +339 -0
- package/docs/providers/app-provider.tsx +191 -0
- package/docs/providers/format-date.tsx +230 -0
- package/docs/query/button-refetch.tsx +160 -0
- package/docs/query/data-state.tsx +192 -0
- package/docs/query/infinite-query-state.tsx +93 -0
- package/docs/query/mutation-feedback.tsx +70 -0
- package/docs/query/prefetch-link.tsx +262 -0
- package/docs/query/touch-actions.tsx +68 -0
- package/docs/showcase/acme-portal.tsx +455 -0
- package/docs/showcase/acme-website.tsx +461 -0
- package/docs/showcase/case1-warehouse-dashboard.tsx +359 -0
- package/docs/showcase/case2-employee-me.tsx +444 -0
- package/docs/showcase/case3-approval-workflow.tsx +529 -0
- package/docs/showcase/case4-login.tsx +313 -0
- package/docs/showcase/case5-shift-calendar.tsx +795 -0
- package/docs/showcase/case6-agency-handy.tsx +1113 -0
- package/docs/showcase/futurelastic-web.tsx +392 -0
- package/docs/showcase/org-switcher.tsx +313 -0
- package/docs/showcase/permission-matrix.tsx +346 -0
- package/docs/showcase/public-landing.tsx +210 -0
- package/docs/showcase/settings-account-sections.tsx +559 -0
- package/docs/showcase/settings-security-mfa.tsx +145 -0
- package/docs/showcase/table-approval-queue.tsx +199 -0
- package/docs/showcase/table-bulk-actions.tsx +460 -0
- package/docs/showcase/table-compact-kintone.tsx +438 -0
- package/docs/showcase/table-conditional-format.tsx +367 -0
- package/docs/showcase/table-crud-list.tsx +544 -0
- package/docs/showcase/table-density.tsx +347 -0
- package/docs/showcase/table-expandable-rows.tsx +480 -0
- package/docs/showcase/table-filter-chips.tsx +456 -0
- package/docs/showcase/table-footer-totals.tsx +314 -0
- package/docs/showcase/table-grouped-subtotals.tsx +391 -0
- package/docs/showcase/table-master-detail.tsx +484 -0
- package/docs/showcase/table-pagination.tsx +327 -0
- package/docs/showcase/table-states.tsx +366 -0
- package/docs/showcase/table-sticky-columns.tsx +376 -0
- package/docs/showcase/table-tree-rows.tsx +444 -0
- package/docs/showcase/table-view-tabs.tsx +488 -0
- package/package.json +9 -12
- package/scripts/_agent-setup.mjs +16 -2
- package/scripts/audit-hook.mjs +3 -13
- package/scripts/init-agent-kit.mjs +1 -14
- package/scripts/postinstall.mjs +12 -12
- package/scripts/ui-audit.mjs +93 -31
- package/scripts/visual-audit-rules.mjs +51 -7
- package/scripts/visual-audit.mjs +118 -47
package/docs/REGISTRY.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Consuming @godxjp/ui through the shadcn registry
|
|
2
|
+
|
|
3
|
+
## What is published, and what is not
|
|
4
|
+
|
|
5
|
+
`@godxjp/ui` ships as an **npm package**. The components are imported, not copied:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { DataTable, Cascader } from "@godxjp/ui/data-display";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The registry does **not** publish those components, and that is deliberate. A shadcn registry is a copy-paste channel — `shadcn add` writes files into your tree and you own them from then on. Copying 165 components would fork your copy from the package: you would stop receiving token fixes, a11y fixes and the guard discipline the library is built on, while carrying ~73k lines you did not write.
|
|
12
|
+
|
|
13
|
+
What the registry publishes is the part the package cannot hand you on its own: **the design language**.
|
|
14
|
+
|
|
15
|
+
| Item | Type | What you get |
|
|
16
|
+
| ---------------- | ---------------- | ------------------------------------------------------------------------------ |
|
|
17
|
+
| `@godxjp/theme` | `registry:theme` | The full token system — foundation scales, semantic roles, per-component knobs |
|
|
18
|
+
| `@godxjp/styles` | `registry:style` | The stylesheets those tokens drive (only if you adopt godxjp markup too) |
|
|
19
|
+
|
|
20
|
+
`docs/showcase/acme-portal.tsx` is the proof this is the valuable half: an entire brand — gold and navy, Source Sans 3, a 14px radius, navy-tinted shadows — reproduced by **configuring tokens alone**, with no component edits and no new components.
|
|
21
|
+
|
|
22
|
+
## Setup
|
|
23
|
+
|
|
24
|
+
Add the namespace to your own `components.json`:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"registries": {
|
|
29
|
+
"@godxjp": "https://godx-jp.github.io/godxjp-ui/registry/{name}.json"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Then:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx shadcn add @godxjp/theme
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
and import the token entry before your own overrides:
|
|
41
|
+
|
|
42
|
+
```css
|
|
43
|
+
@import "./styles/tokens/base.css";
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Re-theming
|
|
47
|
+
|
|
48
|
+
Override roles at `:root`, or scope them per tenant:
|
|
49
|
+
|
|
50
|
+
```css
|
|
51
|
+
[data-tenant="acme"] {
|
|
52
|
+
--primary: 41 71% 53%;
|
|
53
|
+
--radius: 0.875rem;
|
|
54
|
+
--font-family-sans: "Source Sans 3", system-ui, sans-serif;
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Two rules the token system holds to, worth knowing before you override:
|
|
59
|
+
|
|
60
|
+
This is what lets a scoped `[data-tenant]` or `.dark` override actually reach a portaled overlay. See `docs/TOKENS.md`.
|
|
61
|
+
|
|
62
|
+
## Why not the components?
|
|
63
|
+
|
|
64
|
+
If you want the components, install the package — that is the supported path and the one every guard, test and token in this repo is built around:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pnpm add @godxjp/ui
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The registry exists for teams who already have their own shadcn components and want the godxjp design language on top of them.
|
package/docs/SPACING.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Spacing & golden ratio (@godxjp/ui)
|
|
2
|
+
|
|
3
|
+
Macro layout uses a **φ modular scale** (≈ 1.618). Reference: [NN/G — golden ratio in UI](https://www.nngroup.com/articles/golden-ratio-ui-design/).
|
|
4
|
+
|
|
5
|
+
Implementation: `src/tokens/base.css` (values) · layout owners: `src/styles/*-layout.css` · full map: `docs/TOKENS.md`.
|
|
6
|
+
|
|
7
|
+
## Rules for apps
|
|
8
|
+
|
|
9
|
+
1. **Never** Tailwind `gap-*`, `space-*`, `p-*`, `m-*` for layout — the audit rejects them (`no-utility-spacing`, `no-utility-layout`). Rows are `<Flex>` (default `direction="row"`), stacks are `<Flex direction="col" gap>`, grids are `<ResponsiveGrid>`.
|
|
10
|
+
2. **Page sections are spaced by `<PageContainer>` itself**: every direct child of the page body gets `--page-body-gap` (the section step, φ⁰) above it. Do not wrap the sections in a Flex just to space them; do not add margins.
|
|
11
|
+
3. Inside a section: `<Flex direction="col" gap="md">` (φ⁰) for the default rhythm, `gap="lg"` (φ¹) / `gap="xl"` (φ²) for major blocks, `xs` / `sm` (4px grid) for control rows.
|
|
12
|
+
4. Card rhythm is token-driven — do not override card padding in app CSS.
|
|
13
|
+
|
|
14
|
+
## φ scale (one knob)
|
|
15
|
+
|
|
16
|
+
| Token | Formula |
|
|
17
|
+
| ---------- | ------------------- |
|
|
18
|
+
| `--phi-n1` | unit ÷ φ |
|
|
19
|
+
| `--phi-0` | unit (`--phi-unit`) |
|
|
20
|
+
| `--phi-p1` | unit × φ |
|
|
21
|
+
| `--phi-p2` | unit × φ² |
|
|
22
|
+
|
|
23
|
+
`--phi-unit` steps up at `sm` breakpoint; density (`compact` / `comfortable`) retunes it on `PageContainer`.
|
|
24
|
+
|
|
25
|
+
## Flex gap map
|
|
26
|
+
|
|
27
|
+
| Prop | Token | Typical use |
|
|
28
|
+
| ---------- | -------- | --------------------- |
|
|
29
|
+
| `xs`, `sm` | 4px grid | Tight form rows |
|
|
30
|
+
| `md` | φ⁰ | Default sections |
|
|
31
|
+
| `lg` | φ¹ | Dashboard blocks |
|
|
32
|
+
| `xl` | φ² | Page-level separation |
|
|
33
|
+
|
|
34
|
+
## Card
|
|
35
|
+
|
|
36
|
+
**Single owner:** `src/styles/card-layout.css` - all `[data-slot="card-*"]` padding. Components emit `data-slot` + modifier flags only (`data-banded`, `data-flush`, `data-tight`, `data-solo`, `data-separated`). Never Tailwind `p-*` / `px-*` on `Card*` in apps or previews.
|
|
37
|
+
|
|
38
|
+
| Part | Ratio | Role |
|
|
39
|
+
| ------------------------------------------------- | ------------------------ | ------------------------------------------ |
|
|
40
|
+
| `--card-space-inset` | `--space-section-active` | Inline (start/end) inset |
|
|
41
|
+
| `--card-space-shell-y` | `--card-space-inset` | Block shell padding (first/last slot edge) |
|
|
42
|
+
| `--card-space-body-y` | `--space-section-active` | Header↔body gap |
|
|
43
|
+
| `--card-space-header-y` / `--card-space-footer-y` | `--space-stack-sm` | Banded header + separated footer band |
|
|
44
|
+
|
|
45
|
+
| Component | Use |
|
|
46
|
+
| ------------------------- | -------------------------------------------------- |
|
|
47
|
+
| `StatCard` | KPI / stat tile (`solo` path) |
|
|
48
|
+
| `CardContent solo` | Body-only card (same padding as `StatCard`) |
|
|
49
|
+
| `CardContent flush tight` | Edge-to-edge table/tabs in card |
|
|
50
|
+
| `ui-card-inset-x` | Align nested cells to shell (tables in flush body) |
|
|
51
|
+
|
|
52
|
+
See preview **Data Display → Card** for live examples.
|
|
53
|
+
|
|
54
|
+
## MCP
|
|
55
|
+
|
|
56
|
+
`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).
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Prop Vocabulary + Design Token Standards
|
|
2
|
+
|
|
3
|
+
These rules are normative for @godxjp/ui 8.0.0. They mirror `debate/props-vocab-token-consistency/04-Decision.md`.
|
|
4
|
+
|
|
5
|
+
1. Prop vocabulary: every exported `*Prop` type in `src/props/components/` MUST have exactly one `COMPONENT_PROP_REGISTRY` entry.
|
|
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`.
|
|
7
|
+
3. Prop vocabulary: every vocabulary name referenced by `COMPONENT_PROP_REGISTRY[*].vocabulary` MUST exist in `VOCABULARY_REGISTRY`.
|
|
8
|
+
4. Prop vocabulary: the same prop spelling, value kind, and semantic role used by two or more components MUST use one shared vocabulary entry.
|
|
9
|
+
5. Prop vocabulary: `gap` MUST use the single shared `GapProp` on every layout primitive (`Flex`); there are NO per-component gap vocabularies, and none may be added to the registry.
|
|
10
|
+
6. Prop vocabulary: primary heading text MUST use `TitleProp`; `PageTitleProp` MUST NOT be a canonical registry entry.
|
|
11
|
+
7. Prop vocabulary: abstract controlled values MUST use `value?: ValueProp<T>`, `defaultValue?: DefaultValueProp<T>`, and `onValueChange?: OnValueChangeProp<T>`; `onChange` MAY be used only for DOM event handlers or explicitly local compatibility wrappers.
|
|
12
|
+
8. Prop vocabulary: disclosure/open state MUST use `open?: OpenProp`, `defaultOpen?: DefaultOpenProp`, and `onOpenChange?: OnOpenChangeProp`.
|
|
13
|
+
9. Prop vocabulary: semantic color/status intent MUST use `tone` with `ToneProp` or a documented status-specific subtype; `variant` MUST NOT include status-only values such as `success`, `warning`, `info`, or `neutral`.
|
|
14
|
+
10. Prop vocabulary: public `size` values MUST use shared `SizeProp` names or a documented component-specific subset; aliases such as `small` MUST be renamed to the canonical shared value.
|
|
15
|
+
11. Prop vocabulary: public density MUST use `DensityProp` when the component participates in page/subtree density; component-specific density subsets MUST be documented with a registry reason.
|
|
16
|
+
12. Prop vocabulary: no new public `HandlerProp` use is allowed for named user events; command callbacks MUST have event-specific names such as `onConfirm`, `onRetry`, `onDismiss`, or `onValueChange`.
|
|
17
|
+
13. Design tokens: package tokens MUST be organized into primitive, semantic, and component tiers.
|
|
18
|
+
14. Design tokens: primitive tokens MUST define raw scales or palettes only; semantic tokens MUST alias primitives by UI role; component tokens MUST alias semantic or primitive tokens by component part/state.
|
|
19
|
+
15. Design tokens: package CSS custom properties and Tailwind `@theme` exports MUST NOT contain app, customer, or business-domain nouns.
|
|
20
|
+
16. Design tokens: `--tracking-*` and `--color-tracking-*` are forbidden in package source.
|
|
21
|
+
17. Design tokens: component-scoped tokens MUST live in the component tier and use `--{component}-{part}-{property}` or `--{component}-{property}-{state}` naming consistently.
|
|
22
|
+
18. Design tokens: Tailwind `@theme` color exports MUST reference package tokens; literal colors are allowed only when first registered as primitive or semantic tokens.
|
|
23
|
+
19. Design tokens: public raw/decorative primitive exports are allowed only under documented neutral namespaces such as `wa-*` or `chart-*`; undocumented raw ramps such as public `gray-*`/`blue-*` exports are forbidden.
|
|
24
|
+
20. Design tokens: dark mode MUST override semantic tokens by role; component-token dark overrides require a documented component contrast reason.
|
|
25
|
+
21. Design tokens: density CSS MUST select token aliases and MUST NOT introduce new raw component dimensions when a token tier can hold the value.
|
|
26
|
+
22. Control sizing: an interactive control's box height/width MUST resolve from the `--control-height` tier (or its official steps `--control-height-{xs,sm,lg}`). Primitives MUST NOT bake in a control size via a literal length (`height: 2rem`) or an ad-hoc `calc(var(--control-height) ± <len>)` — the named tier carries the density-aware value, and per-instance size changes are the app's call via the `size` prop / `className`. Enforced by `pnpm check:control-sizing`.
|
|
27
|
+
|
|
28
|
+
Examples:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
type SelectLikeProp<T = string> = {
|
|
32
|
+
value?: ValueProp<T>;
|
|
33
|
+
defaultValue?: DefaultValueProp<T>;
|
|
34
|
+
onValueChange?: OnValueChangeProp<T>;
|
|
35
|
+
};
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
<Badge tone="success" variant="outline">
|
|
40
|
+
公開中
|
|
41
|
+
</Badge>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```css
|
|
45
|
+
@theme {
|
|
46
|
+
--color-chart-1: var(--chart-1);
|
|
47
|
+
}
|
|
48
|
+
```
|
package/docs/TESTING.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Testing @godxjp/ui
|
|
2
|
+
|
|
3
|
+
Every component **must** ship with a Vitest suite before merge.
|
|
4
|
+
|
|
5
|
+
## Run
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cd packages/ui
|
|
9
|
+
pnpm test # single run
|
|
10
|
+
pnpm test:watch # watch mode
|
|
11
|
+
pnpm test:coverage # v8 coverage report
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## File location
|
|
15
|
+
|
|
16
|
+
Co-locate tests next to components:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
src/components/layout/page-container.tsx
|
|
20
|
+
src/components/layout/__tests__/page-container.test.tsx
|
|
21
|
+
src/form/use-zod-form.ts
|
|
22
|
+
src/form/__tests__/use-zod-form.test.tsx
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Required coverage per component
|
|
26
|
+
|
|
27
|
+
Each `*.test.tsx` must include:
|
|
28
|
+
|
|
29
|
+
1. **Render** — component mounts without throw
|
|
30
|
+
2. **Props** — key prop variations (variants, sizes, density, slots)
|
|
31
|
+
3. **Interaction** — userEvent for clicks, typing, keyboard where applicable
|
|
32
|
+
4. **A11y** — roles, labels, aria-\* attributes for form controls
|
|
33
|
+
5. **Edge cases** — empty, error, loading, disabled states
|
|
34
|
+
|
|
35
|
+
## Test utilities
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { renderWithUi, screen, userEvent } from "@/test/render";
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`renderWithUi` wraps `MemoryRouter` + `React.StrictMode` + **`RenderLoopGuard`** (fails fast on infinite re-render loops, default max 25 renders).
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
// Optional: disable guard for stress tests
|
|
45
|
+
renderWithUi(<HeavyChart />, { loopGuard: false });
|
|
46
|
+
|
|
47
|
+
// Custom threshold
|
|
48
|
+
renderWithUi(<Widget />, { loopGuard: { maxRenders: 40, label: "Widget" } });
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Shared guard lives in `@godxjp/tooling/test` — apps import the same helper.
|
|
52
|
+
|
|
53
|
+
Vitest setup (apps):
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
// vitest.setup.ts
|
|
57
|
+
import "@godxjp/tooling/test/vitest.setup.react";
|
|
58
|
+
import "@testing-library/jest-dom/vitest";
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`testTimeout: 8000` — hung tests fail before blocking CI.
|
|
62
|
+
|
|
63
|
+
## Render loop prevention (ESLint + test)
|
|
64
|
+
|
|
65
|
+
| Layer | Catches |
|
|
66
|
+
| --------------------------------- | -------------------------------- |
|
|
67
|
+
| `react-hooks/exhaustive-deps` | missing/unstable effect deps |
|
|
68
|
+
| `react-hooks/set-state-in-effect` | sync setState in effects |
|
|
69
|
+
| `RenderLoopGuard` in tests | runaway re-renders during Vitest |
|
|
70
|
+
|
|
71
|
+
Run `pnpm lint` before `pnpm test` — official React Compiler rules align with test guard.
|
|
72
|
+
|
|
73
|
+
## Forms testing
|
|
74
|
+
|
|
75
|
+
Form integration tests **must** use Zod 4 schemas:
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
const schema = z.object({ email: z.string().email() });
|
|
79
|
+
const form = useZodForm(schema);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Never test forms with raw `useState` — mirror production `FormRoot` + `FormFieldControl`.
|
|
83
|
+
|
|
84
|
+
## CI gate
|
|
85
|
+
|
|
86
|
+
`pnpm test` in `packages/ui` must pass with zero failures before any UI PR merges.
|
|
87
|
+
|
|
88
|
+
## When tests fail
|
|
89
|
+
|
|
90
|
+
Guard suites and fix playbooks:
|
|
91
|
+
|
|
92
|
+
| Suite | File |
|
|
93
|
+
| ------------------------ | ------------------------------------------------------------- |
|
|
94
|
+
| Theme token audit | `src/lib/__tests__/theme-tokens-audit.test.ts` |
|
|
95
|
+
| Theme axes integration | `src/components/__tests__/theme-axes-integration.test.tsx` |
|
|
96
|
+
| formatDate / AppProvider | `src/lib/__tests__/format-date.test.ts`, `src/app/__tests__/` |
|
|
97
|
+
|
|
98
|
+
**Full failure routing:** MCP tool `godxjp_ui_guide` topic=`testing-troubleshooting` or `godxjp_ui_verify` with `failureHint` from CI log (see `tools/godxjp-ui-mcp/`).
|
package/docs/TOKENS.md
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
# Design tokens — single owner model (@godxjp/ui)
|
|
2
|
+
|
|
3
|
+
Every visual dimension has **one canonical owner**. Apps never patch spacing, density, typography, or color ad hoc.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
src/tokens/base.css ← token manifest; imports every base token file
|
|
9
|
+
src/tokens/foundation.css ← primitive color accents, typography, raw spacing, icon size, ratio, radius, shadow
|
|
10
|
+
src/tokens/semantic/ ← semantic aliases by UI role
|
|
11
|
+
layout.css ← page/section/stack/inline tokens
|
|
12
|
+
src/tokens/components/ ← component token files
|
|
13
|
+
control.css ← control height + control padding
|
|
14
|
+
card.css ← Card component tokens
|
|
15
|
+
table.css ← Table component tokens
|
|
16
|
+
feedback.css ← Dialog/Alert/EmptyState component tokens
|
|
17
|
+
badge.css ← Badge component tokens
|
|
18
|
+
src/styles/
|
|
19
|
+
index.css ← @theme bridge (Tailwind ↔ tokens) + body defaults
|
|
20
|
+
density.css ← .ui-density-* (PageContainer density prop)
|
|
21
|
+
layout.css ← Flex / Page / EmptyState
|
|
22
|
+
control.css ← inputs, buttons height (--control-height)
|
|
23
|
+
card-layout.css ← Card* slots
|
|
24
|
+
table-layout.css ← Table + DataTable chrome
|
|
25
|
+
dialog-layout.css ← Dialog* slots
|
|
26
|
+
alert-layout.css ← Alert* slots + semantic variant colors
|
|
27
|
+
badge-layout.css ← Badge spacing
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Components emit `data-slot` + flags. Layout CSS applies padding/margin/gap/font-size/color.**
|
|
31
|
+
|
|
32
|
+
`base.css` is the single entry point. Primitive token files are split only for governance and audit; apps still import `@godxjp/ui/styles` once and override tokens in `theme.css`.
|
|
33
|
+
|
|
34
|
+
## By concern
|
|
35
|
+
|
|
36
|
+
### Color
|
|
37
|
+
|
|
38
|
+
| Owner | Rule |
|
|
39
|
+
| --------------------------------------- | ------------------------------------------------------------------- |
|
|
40
|
+
| `base.css` `:root` / `.dark` | HSL components (`--primary`, `--destructive`, …) |
|
|
41
|
+
| `index.css` `@theme` | Maps to Tailwind `bg-primary`, `text-muted-foreground`, … |
|
|
42
|
+
| App `theme.css` | Override `:root` only — never component CSS |
|
|
43
|
+
| `alert-layout.css`, `control-styles.ts` | Semantic tones (`success`, `warning`, …) — never `text-emerald-600` |
|
|
44
|
+
|
|
45
|
+
Default brand tokens use the GodX Agent Portal palette: navy primary, 朱 orange focus/accent, warm neutral surfaces. App or customer identity colors belong in the consuming app theme, not in package tokens.
|
|
46
|
+
|
|
47
|
+
#### `--border` vs `--input` — decorative chrome vs control boundary (gh#315)
|
|
48
|
+
|
|
49
|
+
These two look like synonyms and are not. Keep them apart:
|
|
50
|
+
|
|
51
|
+
| Role | What it draws | Contrast bar |
|
|
52
|
+
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
53
|
+
| `--border` | Decorative chrome — table rules, card edges, section dividers, `<Separator>` | **None.** WCAG 2.2 SC 1.4.11 does not reach a divider; this system's dense JP grid depends on it staying quiet |
|
|
54
|
+
| `--input` | The boundary that **is** the control — Input, Textarea, Select, outline Button, TagInput, composite date field, topbar search, and the Switch's unchecked track | **≥ 3:1** (SC 1.4.11 Non-text Contrast) against every surface a control sits on — page, card, popover, muted/secondary panel, striped and hovered rows |
|
|
55
|
+
|
|
56
|
+
A field here has no fill of its own (`background: hsl(var(--background))`) and no shadow to speak of, so that 1px edge is the whole visual claim that you may type there. Current values: `30 7% 53%` light (3.47:1 on `--background`/`--card`, 3.18:1 on `--muted`) and `45 6% 47%` dark (4.22:1 on `--background`, 3.88:1 on `--card`/`--popover`, 3.17:1 on `--muted`).
|
|
57
|
+
|
|
58
|
+
**Re-theming rule:** a service theme that retints neutrals must move these two **independently** — setting `--input: var(--border)` re-opens the bug. `src/tokens/__tests__/input-boundary-contrast.test.ts` recomputes the ratios from `foundation.css` and fails below 3:1, and fails outright if the two roles are given the same value again.
|
|
59
|
+
|
|
60
|
+
The Switch's off-track borrows `--input` by default. If a service wants it quieter than the boundary role, override `--switch-unchecked-background` (component token, `initial`, call-site default `hsl(var(--input))`) rather than dragging `--input` back down — but whatever you set still owes 3:1 against the page and against the thumb (`--background`), or "off" stops being a visible state.
|
|
61
|
+
|
|
62
|
+
### Typography
|
|
63
|
+
|
|
64
|
+
| Owner | Rule |
|
|
65
|
+
| ------------------- | ----------------------------------------------------------------------------------------------- |
|
|
66
|
+
| `base.css` | `--font-size-xs` … `--font-size-2xl`, weights, line-heights |
|
|
67
|
+
| `layout.css` | Page title/subtitle, empty-state title |
|
|
68
|
+
| `card-layout.css` | Banded header title override |
|
|
69
|
+
| `dialog-layout.css` | Dialog title/description |
|
|
70
|
+
| Components | Use `text-sm`, `text-base` (wired to tokens) or `data-slot` CSS — never arbitrary `text-[14px]` |
|
|
71
|
+
|
|
72
|
+
Runtime scale: app `theme.css` overrides → `--font-size-sm` on root.
|
|
73
|
+
|
|
74
|
+
### Spacing / margin / gap
|
|
75
|
+
|
|
76
|
+
| App API | Internal owner |
|
|
77
|
+
| --------------------------------- | ------------------------------------------ |
|
|
78
|
+
| `<Flex direction="col" gap="md">` | `layout.css` `.ui-flex-gap-md` |
|
|
79
|
+
| `<Flex gap="sm">` | `layout.css` `.ui-flex-gap-sm` |
|
|
80
|
+
| `<PageContainer>` | `layout.css` `.ui-page-*` |
|
|
81
|
+
| `<Card>` slots | `card-layout.css` |
|
|
82
|
+
| `<Table>` cells | `table-layout.css` `[data-slot="table-*"]` |
|
|
83
|
+
|
|
84
|
+
**Apps:** no Tailwind `p-*`, `m-*`, `gap-*`, `space-*`.
|
|
85
|
+
|
|
86
|
+
### Icon size (gh#326)
|
|
87
|
+
|
|
88
|
+
Icon was the last geometric axis without a scale. Twenty-eight component tokens declared raw numbers, and between them they used exactly **nine values** — the vocabulary was already there, nobody had written it down. `foundation.css` now does:
|
|
89
|
+
|
|
90
|
+
| Token | rem | px | |
|
|
91
|
+
| ----------------- | ---------- | ------ | --------------------------- |
|
|
92
|
+
| `--icon-size-2xs` | `0.625rem` | **10** | presence dot on an avatar |
|
|
93
|
+
| `--icon-size-xs` | `0.75rem` | **12** | table sort caret, xs button |
|
|
94
|
+
| `--icon-size-sm` | `0.875rem` | **14** | `size="sm"` controls |
|
|
95
|
+
| `--icon-size-md` | `1rem` | **16** | **the default icon step** |
|
|
96
|
+
| `--icon-size-lg` | `1.25rem` | **20** | alert / launcher glyph |
|
|
97
|
+
| `--icon-size-xl` | `1.5rem` | **24** | upload tile, empty state |
|
|
98
|
+
| `--icon-size-2xl` | `2.25rem` | **36** | StatCard medallion |
|
|
99
|
+
| `--icon-size-3xl` | `2.5rem` | **40** | dropzone |
|
|
100
|
+
| `--icon-size-4xl` | `3rem` | **48** | empty-state box |
|
|
101
|
+
|
|
102
|
+
Type can sit between pixels because hinting and antialiasing carry it; a 1px-stroke glyph cannot — half a pixel of icon is a blurred icon. Every step is a whole pixel at the 16px root, and a service retunes a **step**, never a ratio.
|
|
103
|
+
|
|
104
|
+
**Not `--scaling`-multiplied.** The scale is the crisp pixel list; density is opted into by the tokens that want it — `--control-icon-size: calc(var(--icon-size-md) * var(--scaling))`. Whether a given icon tracks density stays a per-token decision.
|
|
105
|
+
|
|
106
|
+
#### Two tiers, and where the boundary sits
|
|
107
|
+
|
|
108
|
+
| | When | How |
|
|
109
|
+
| ---------- | -------------------------------------------- | --------------------------------------------------------------------- |
|
|
110
|
+
| **Tier 1** | the value appears in **more than one place** | it earns a step on the scale; a service retunes the step once |
|
|
111
|
+
| **Tier 2** | the value appears in **exactly one place** | set that component's own token **at the call site** — never the scale |
|
|
112
|
+
|
|
113
|
+
A system with only tier 1 turns every exception into a hack (`!important`, a global override, a forked stylesheet); a system with only tier 2 loses consistency. The 6px status dot is the proof case: it will never be on an icon scale, and it is a real need.
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
// Tier 2 — one instance, one arbitrary value. No !important, no :root override, no fork.
|
|
117
|
+
<DropdownMenuItem style={{ "--menu-icon-size": "6px" } as React.CSSProperties}>…</DropdownMenuItem>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```css
|
|
121
|
+
/* Tier 2, the theme form — scope it, don't globalise it. */
|
|
122
|
+
[data-tenant="acme"] [data-slot="alert-icon"] {
|
|
123
|
+
--alert-dismiss-icon-size: 0.375rem;
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
An inline custom property wins by **inheritance proximity**, not specificity, so it beats the `:root` default without any weight games. What keeps the route open is that every icon rule in `src/styles` reads its token through `var()` with no baked literal — `src/tokens/__tests__/icon-size-scale.test.ts` asserts exactly that, and carries a shrink-only list of the rules that still bake a literal and are therefore unreachable from an app.
|
|
128
|
+
|
|
129
|
+
The three left need tokens in `components/control.css` (`.ui-otp-separator-icon`) and `components/shell.css` (`.tb-icon-btn svg`, `.tb-chip-icon`). Note that `.tb-chip-icon`'s `1.125rem` is **not** a snap case even though 18px is off the scale: it is a whole pixel, and the box is a letter medallion (`display: grid`, `place-items: center`, a radius, `color: white`), not a stroked glyph — so it wants a `scale-exempt:` marker, not the nearest step. Off-scale and off-grid are different findings; decide each on what the icon actually is.
|
|
130
|
+
|
|
131
|
+
**Before you add a step:** if a value is wanted in two places it belongs on the scale, and if it is wanted in one it does not. Adding a tenth step to serve a single call site is how a scale stops meaning anything.
|
|
132
|
+
|
|
133
|
+
### Stroke and band height (gh#324)
|
|
134
|
+
|
|
135
|
+
The census confirmed the number and rejected the diagnosis: **`width` is not one axis.** Three unrelated concerns wear the suffix.
|
|
136
|
+
|
|
137
|
+
| concern | example | verdict |
|
|
138
|
+
| ------------------------ | -------------------------------------------- | ---------------------------- |
|
|
139
|
+
| thickness of a line | `--control-border-width: 1px` | **one vocabulary** → a scale |
|
|
140
|
+
| measure of a container | `--dialog-width-default: 32rem` | not a scale — tier 2 |
|
|
141
|
+
| content width of a field | `--app-setting-picker-timezone-width: 14rem` | not a scale — tier 2 |
|
|
142
|
+
|
|
143
|
+
`height` split the same way: a control, a table row, a menu item, a nav row and the app-shell top bar are one decision sharing one vocabulary; a chart plot's height and a popover's max-height are container measures chosen per surface. `size` and `offset` came out no-scale on the same test. **Naming a scale is the fix for an axis; declaring that an axis is _not_ one is the fix for the rest** — both verdicts, and the census behind them, live in `scripts/token-scale-bypass-rules.mjs` so the question is not re-asked every quarter.
|
|
144
|
+
|
|
145
|
+
#### `--stroke-*` — the thickness of a painted line
|
|
146
|
+
|
|
147
|
+
| Token | px | |
|
|
148
|
+
| ------------------- | ------- | ------------------------------------------------------- |
|
|
149
|
+
| `--stroke-hairline` | **1** | every resting border, divider and rule |
|
|
150
|
+
| `--stroke-sm` | **1.5** | avatar presence stroke |
|
|
151
|
+
| `--stroke-md` | **2** | **the emphasis stroke** — focus rings, selected markers |
|
|
152
|
+
| `--stroke-lg` | **3** | the open/focus ring on toggles |
|
|
153
|
+
| `--stroke-xl` | **4** | Steps process ring |
|
|
154
|
+
| `--stroke-2xl` | **6** | the Card accent rail |
|
|
155
|
+
|
|
156
|
+
**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.
|
|
157
|
+
|
|
158
|
+
`--focus-ring-width` is now a member (`var(--stroke-md)`) rather than a parallel authority, so a high-contrast theme that wants every emphasis stroke at 3px sets one token.
|
|
159
|
+
|
|
160
|
+
#### `--band-height-*` — the vertical extent of a horizontal band
|
|
161
|
+
|
|
162
|
+
| Token | rem | px | |
|
|
163
|
+
| ------------------- | --------- | ------ | ---------------------------------------- |
|
|
164
|
+
| `--band-height-xs` | `1.5rem` | **24** | `--control-height-xs` |
|
|
165
|
+
| `--band-height-sm` | `1.75rem` | **28** | compact control / table row, file button |
|
|
166
|
+
| `--band-height-md` | `2rem` | **32** | **the default control and row band** |
|
|
167
|
+
| `--band-height-lg` | `2.25rem` | **36** | the canonical DXS auth control |
|
|
168
|
+
| `--band-height-xl` | `2.75rem` | **44** | the WCAG 2.2 AA touch floor (rule #24) |
|
|
169
|
+
| `--band-height-2xl` | `3rem` | **48** | the AppShell top bar |
|
|
170
|
+
| `--band-height-3xl` | `3.5rem` | **56** | the AppShell top bar on a coarse pointer |
|
|
171
|
+
|
|
172
|
+
**This is not a replacement for `--control-height-*`, and the difference matters.** The control tier is a **runtime ladder**: it multiplies by `--scaling`, steps ±`--space-1` for `sm`/`lg`/`xs`, and `@media (pointer: coarse)` lifts the whole thing to the 44px tap floor. `--band-height-*` is the **static vocabulary the ladder is anchored on** — `--control-height-default: var(--band-height-md)` — exactly as `--font-size-base` anchors the type scale.
|
|
173
|
+
|
|
174
|
+
> Point a band token at `--control-height-*` to "reuse a step" and you silently enrol it in
|
|
175
|
+
> density **and** in the coarse-pointer growth. That is a geometry change, not a rename.
|
|
176
|
+
> `--table-row-height-default` reads `var(--band-height-md)`, not `var(--control-height-default)`,
|
|
177
|
+
> for precisely that reason.
|
|
178
|
+
|
|
179
|
+
That trap had already been sprung once: `--card-service-launcher-icon-size` read `var(--control-height-lg)` — a control tier sizing an _icon_ box. Invisible at the desk and wrong on a phone, where the medallion inflated 36px → 48px while the glyph inside it stayed 20px. It is `calc(var(--icon-size-2xl) * var(--scaling))` now: right axis, same value on every density, and it stops growing on touch.
|
|
180
|
+
|
|
181
|
+
#### Mis-named axes are worth renaming, with an alias
|
|
182
|
+
|
|
183
|
+
`--table-skeleton-line-height` was a **length** on the line-height axis, whose scale is a set of unitless _ratios_ — so it was never a bypass, it was a mis-named height, and while it stood the axis could not be gated at all. One rename unlocked a whole axis at zero baseline cost.
|
|
184
|
+
|
|
185
|
+
### Component Tokens
|
|
186
|
+
|
|
187
|
+
Each component owns a token file under `src/tokens/components/`. The file may only derive from foundation, semantic, or other component tokens; component CSS may only consume those component tokens.
|
|
188
|
+
|
|
189
|
+
#### Role-mirror knobs MUST be `initial` + a call-site fallback (the `:root` freeze rule)
|
|
190
|
+
|
|
191
|
+
When a component-token default is just a **role token** (`--card-background` defaults to `--card`, `--table-header-background` to `--muted`, `--checkbox-checked-background` to `--primary`, `--focus-ring-color` to `--ring` …), you may **not** write the binding at `:root`:
|
|
192
|
+
|
|
193
|
+
```css
|
|
194
|
+
/* ✗ WRONG — freezes at the :root role value */
|
|
195
|
+
:root {
|
|
196
|
+
--card-background: var(--card);
|
|
197
|
+
}
|
|
198
|
+
.ui-card {
|
|
199
|
+
background: hsl(var(--card-background));
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
CSS substitutes a `var()` at the element that **declares** it, so `--card-background` computes to `:root`'s `--card` and inherits that frozen value down. A consumer who scopes the _role_ (`[data-tenant] { --card: <dark> }` or `.dark`) overrides `--card` but **never reaches** `--card-background` — the component keeps the light `:root` value. Under a dark theme this is glaring (a frozen light card under white text → invisible text); under a light theme it hides silently.
|
|
204
|
+
|
|
205
|
+
Instead, declare the knob `initial` (a real, catalogued, guaranteed-invalid declaration — no role to freeze) and move the role default to the **call site** as a fallback, so it re-resolves live at the painting element under any scope, while an explicit theme override of the knob still wins:
|
|
206
|
+
|
|
207
|
+
```css
|
|
208
|
+
/* ✓ RIGHT — default re-resolves under scope; knob still overridable */
|
|
209
|
+
:root {
|
|
210
|
+
--card-background: initial;
|
|
211
|
+
} /* documented default = hsl(var(--card)) */
|
|
212
|
+
.ui-card {
|
|
213
|
+
background: hsl(var(--card-background, var(--card)));
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The same rule applies to `@theme inline` (utilities re-resolve scoped roles) and to any `:root`-declared **composite** that wraps a role (e.g. a focus-ring box-shadow): read the role **directly** at the call site, never through a frozen `:root` intermediate. Pure non-colour knobs (spacing, radius, font-size) don't need this — they aren't scope-retinted — but any colour/fill/ border/shadow knob whose default is a role token does.
|
|
218
|
+
|
|
219
|
+
**The same freeze bites any knob whose default is a RE-SCOPED tier, colour or not.** `--control-height` is re-scoped by `.ui-auth-shell` (44px comfortable) and by `.ui-auth-shell[data-variant="canonical"]` (36px), so a knob that mirrors it must follow the same `initial` + call-site-fallback shape:
|
|
220
|
+
|
|
221
|
+
```css
|
|
222
|
+
:root {
|
|
223
|
+
--otp-slot-size: initial;
|
|
224
|
+
} /* documented default = var(--control-height) */
|
|
225
|
+
.ui-otp-slot {
|
|
226
|
+
width: var(--otp-slot-size, var(--control-height));
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Ask "is the default a token that some scope re-declares?", not "is the default a colour?".
|
|
231
|
+
|
|
232
|
+
Card primitive tokens:
|
|
233
|
+
|
|
234
|
+
| Token | Purpose |
|
|
235
|
+
| -------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
236
|
+
| `--card-space-inset` | Shared header/body/footer **inline** inset — the column all slots align to |
|
|
237
|
+
| `--card-space-shell-y` | **Block** shell padding (header top · `solo` body top · terminal bottom) — default = the inset |
|
|
238
|
+
| `--card-space-header-y` | Banded header band vertical density (feeds `--card-space-divided-y`) |
|
|
239
|
+
| `--card-space-body-y` | Gap under the header + the body's own top padding |
|
|
240
|
+
| `--card-space-footer-y` | Separated footer band vertical density (feeds `--card-space-divided-y`) |
|
|
241
|
+
| `--card-space-divided-y` | **Border-aware** symmetric top+bottom padding of a DIVIDED band |
|
|
242
|
+
| `--card-space-gap` | In-slot stack gap (header title ↕ description) |
|
|
243
|
+
| `--card-accent-rail-width` | Width of the `accent` leading-edge stripe (default `6px`) |
|
|
244
|
+
| `--card-title-font-size` | Card title scale |
|
|
245
|
+
| `--card-header-background` | Banded header background color token |
|
|
246
|
+
| `--card-shadow` | Card elevation |
|
|
247
|
+
|
|
248
|
+
#### Border-aware vertical padding (dividers)
|
|
249
|
+
|
|
250
|
+
A card slot's vertical padding depends on **whether it carries a divider border** — set it once via a token, never hard-code padding on the slot:
|
|
251
|
+
|
|
252
|
+
- **Divided band** — a `<CardHeader banded>` (bottom border + muted band) or a `<CardFooter separated>` (top border). It reads as its own region, so it pads **symmetrically** top+bottom from `--card-space-divided-y` (which defaults to `--card-space-header-y`). One knob keeps the header- and footer-band rhythm in sync. - **Plain header** — no border; it _flows_ into the body.
|
|
253
|
+
|
|
254
|
+
So: WITH a divider → symmetric band padding; WITHOUT → asymmetric flow padding. Tune the band density once at `--card-space-divided-y`; tune the accent stripe at `--card-accent-rail-width`.
|
|
255
|
+
|
|
256
|
+
#### The two card axes are independent (gh#232)
|
|
257
|
+
|
|
258
|
+
`--card-space-inset` owns the **inline** column; `--card-space-shell-y` owns the **block** shell edges (a plain header's top, a `solo` body's top, the terminal slot's bottom). `--card-space-shell-y` is declared `initial`, so its default resolves at the call site to `--card-space-inset` — a card that sets neither, or that only re-tunes the inset (including `density="tight|cozy"`), renders exactly as before. Override `--card-space-shell-y` alone to make a card **shorter without narrowing it**:
|
|
259
|
+
|
|
260
|
+
```css
|
|
261
|
+
/* a short login card that keeps its 24px column */
|
|
262
|
+
.ui-auth-shell {
|
|
263
|
+
--auth-shell-card-padding-block-compact: 14px;
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
That AuthShell knob is wired straight to `--card-space-shell-y` on the compact auth card; the inline column stays on `--auth-shell-compact-card-inset` and the header↔body gap on `--auth-shell-card-body-gap-compact`. Three knobs, three axes, no consumer bridge selector on `[data-slot="card-content"]`.
|
|
268
|
+
|
|
269
|
+
Example app override:
|
|
270
|
+
|
|
271
|
+
```css
|
|
272
|
+
:root {
|
|
273
|
+
--card-space-inset: var(--space-section-active);
|
|
274
|
+
--card-space-divided-y: var(--space-stack-md); /* roomier banded header / separated footer */
|
|
275
|
+
--card-accent-rail-width: 4px; /* thinner accent stripe */
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Density
|
|
280
|
+
|
|
281
|
+
| App API | Owner |
|
|
282
|
+
| --------------------------------------------------------- | ------------- |
|
|
283
|
+
| `<PageContainer density="compact\|default\|comfortable">` | `density.css` |
|
|
284
|
+
|
|
285
|
+
Retunes `--phi-unit`, `--control-height`, `--table-row-height`, `--table-cell-padding-y` for the whole subtree.
|
|
286
|
+
|
|
287
|
+
Control heights are `compact` 28px, `default` 32px, and `comfortable` 44px. Use `comfortable` for handheld/public surfaces that need the touch floor.
|
|
288
|
+
|
|
289
|
+
### Card / Table / Dialog / Alert
|
|
290
|
+
|
|
291
|
+
See `docs/SPACING.md` for Card slot matrix. Same pattern everywhere:
|
|
292
|
+
|
|
293
|
+
1. Component TSX → `data-slot` + modifier flags only
|
|
294
|
+
2. `*-layout.css` → all inset/gap/border-band rules
|
|
295
|
+
3. Governance test fails if TSX reintroduces padding utilities
|
|
296
|
+
|
|
297
|
+
## Preset components (avoid reinventing layout)
|
|
298
|
+
|
|
299
|
+
| Need | Use |
|
|
300
|
+
| --------------- | --------------------------------- |
|
|
301
|
+
| KPI stat tile | `<StatCard label value delta />` |
|
|
302
|
+
| Page sections | `<Flex direction="col" gap="md">` |
|
|
303
|
+
| Row of controls | `<Flex gap="sm">` |
|
|
304
|
+
| Status enum | `<Badge status="…" />` |
|
|
305
|
+
| Empty list | `<EmptyState … />` |
|
|
306
|
+
|
|
307
|
+
## The layer contract
|
|
308
|
+
|
|
309
|
+
Every rule this package ships sits inside a cascade layer, and **layer order beats specificity outright**. Two halves, and both have already cost a release.
|
|
310
|
+
|
|
311
|
+
### Inside the package
|
|
312
|
+
|
|
313
|
+
`@import "tailwindcss"` establishes `theme, base, components, utilities`. Component CSS lives in `@layer components`, which is **earlier** than `utilities` — so a Tailwind utility a component emits on its own element outranks the layered rule that is supposed to own the same property, and no selector can win that fight.
|
|
314
|
+
|
|
315
|
+
The documented token was dead, the narrow frame stayed at 14px, and a 5–6 character Japanese label could not fit its column measure — a WCAG 2.2 SC 1.4.10 failure that only manifests in Japanese. Two independent consumers reported it.
|
|
316
|
+
|
|
317
|
+
A **responsive re-point** that must beat such a utility goes in **`@layer godxjp-ui-responsive`**, declared straight after Tailwind in `src/styles/base.css` and therefore the last layer:
|
|
318
|
+
|
|
319
|
+
```css
|
|
320
|
+
@layer godxjp-ui-responsive {
|
|
321
|
+
@container ui-table-collection (width < 40rem) {
|
|
322
|
+
[data-collapse-below="sm"] [data-slot="table"] {
|
|
323
|
+
font-size: var(--table-action-collection-font-size-compact);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
It is reserved for `@container` / `@media` re-points. Everything static stays in `@layer components`.
|
|
330
|
+
|
|
331
|
+
### In a consumer app
|
|
332
|
+
|
|
333
|
+
**Unlayered CSS outranks every layer, including `godxjp-ui-responsive`.** So:
|
|
334
|
+
|
|
335
|
+
- Theme this package by setting **tokens** on a wrapper element (`.my-page { --table-…: 7rem; }`). - Do **not** write app selectors against package internals (`[data-slot]`, `[data-priority]`, `.ui-*`). An unlayered rule that does wins at _every_ width and kills the package's responsive re-points.
|
|
336
|
+
|
|
337
|
+
## Adding a new component
|
|
338
|
+
|
|
339
|
+
1. Add/update the component token file in `src/tokens/components/`.
|
|
340
|
+
2. Add `src/styles/<component>-layout.css` with `[data-slot="…"]` rules.
|
|
341
|
+
3. Import in `index.css`.
|
|
342
|
+
4. Component TSX: structure + `data-slot` only.
|
|
343
|
+
5. Extend `token-governance.test.ts` allowlist only for third-party adapters (calendar, cmdk).
|
|
344
|
+
|
|
345
|
+
## MCP
|
|
346
|
+
|
|
347
|
+
`godxjp_ui_guide` topic=`golden-ratio` · `tokens`
|