@godxjp/ui 19.1.0 → 19.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +2 -12
- 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 +48 -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 +31 -0
- package/dist/props/registry.js +33 -0
- 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 +4 -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 +4 -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 +247 -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 +156 -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 +184 -0
- package/docs/data-display/popover-touch.tsx +27 -0
- package/docs/data-display/popover.tsx +245 -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 +271 -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 +170 -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 +326 -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 +106 -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 +410 -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 +202 -0
- package/docs/foundation/density.tsx +232 -0
- package/docs/foundation/email-tokens.tsx +306 -0
- package/docs/foundation/radius-shadow.tsx +152 -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 +119 -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 +262 -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 +946 -0
- package/docs/layout/resizable-panel.tsx +419 -0
- package/docs/layout/responsive-grid.tsx +235 -0
- package/docs/layout/separator.tsx +327 -0
- package/docs/layout/service-role-panel.tsx +144 -0
- package/docs/layout/sidebar.tsx +586 -0
- package/docs/layout/split-pane.tsx +451 -0
- package/docs/layout/topbar.tsx +347 -0
- package/docs/navigation/app-setting-picker.tsx +141 -0
- package/docs/navigation/breadcrumb.tsx +128 -0
- package/docs/navigation/context-menu.tsx +117 -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 +165 -0
- package/docs/navigation/pagination.tsx +241 -0
- package/docs/navigation/steps.tsx +263 -0
- package/docs/navigation/tabs-rtl.tsx +28 -0
- package/docs/navigation/tabs.tsx +308 -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 +441 -0
- package/docs/showcase/acme-website.tsx +455 -0
- package/docs/showcase/case1-warehouse-dashboard.tsx +343 -0
- package/docs/showcase/case2-employee-me.tsx +441 -0
- package/docs/showcase/case3-approval-workflow.tsx +527 -0
- package/docs/showcase/case4-login.tsx +307 -0
- package/docs/showcase/case5-shift-calendar.tsx +795 -0
- package/docs/showcase/case6-agency-handy.tsx +1072 -0
- package/docs/showcase/futurelastic-web.tsx +390 -0
- package/docs/showcase/org-switcher.tsx +313 -0
- package/docs/showcase/permission-matrix.tsx +343 -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 +340 -0
- package/docs/showcase/table-expandable-rows.tsx +471 -0
- package/docs/showcase/table-filter-chips.tsx +461 -0
- package/docs/showcase/table-footer-totals.tsx +311 -0
- package/docs/showcase/table-grouped-subtotals.tsx +388 -0
- package/docs/showcase/table-master-detail.tsx +479 -0
- package/docs/showcase/table-pagination.tsx +320 -0
- package/docs/showcase/table-states.tsx +363 -0
- package/docs/showcase/table-sticky-columns.tsx +373 -0
- package/docs/showcase/table-tree-rows.tsx +444 -0
- package/docs/showcase/table-view-tabs.tsx +488 -0
- package/package.json +9 -11
- 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
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Showcase · table-footer-totals — 合計行 (V17)
|
|
3
|
+
*
|
|
4
|
+
* A 勤怠 (attendance) summary table whose numeric columns roll up into a sticky
|
|
5
|
+
* FOOTER totals row. The footer survives vertical scroll: the header stays
|
|
6
|
+
* pinned to the top, the totals stay pinned to the bottom, and the body of
|
|
7
|
+
* 部署 × 従業員 rows scrolls between them.
|
|
8
|
+
*
|
|
9
|
+
* GAP → composition note
|
|
10
|
+
* ──────────────────────
|
|
11
|
+
* `DataTable` (src/components/data-display/data-table.tsx) has NO footer slot:
|
|
12
|
+
* its compound API is Toolbar / SelectAll / BulkActions / DensityToggle /
|
|
13
|
+
* Content / Pagination — `DataTable.Content` renders <thead>+<tbody> only.
|
|
14
|
+
* The `Table` family (src/components/data-display/table.tsx) likewise exports
|
|
15
|
+
* Table / TableHeader / TableBody / TableHead / TableRow / TableCell — there is
|
|
16
|
+
* NO `TableFooter` / <tfoot> primitive. A footer totals row is therefore not
|
|
17
|
+
* expressible through DataTable. Per the rules I compose it from the real
|
|
18
|
+
* Table primitives plus a semantic <tfoot> (a real HTML table section, not a
|
|
19
|
+
* hand-rolled control), and record the missing capability in gapNotes.
|
|
20
|
+
*
|
|
21
|
+
* DNA: compact density, small heading, tabular-nums on every numeric column,
|
|
22
|
+
* fixed colour signalling (warning 山吹 = 残業 over threshold, info 群青 =
|
|
23
|
+
* mid 残業, success 若竹 = on-plan, destructive 茜 = 遅刻 lateness — Badge has
|
|
24
|
+
* no attention/朱 tone), quiet JP copy, no emoji.
|
|
25
|
+
*/
|
|
26
|
+
import * as React from "react";
|
|
27
|
+
|
|
28
|
+
import {
|
|
29
|
+
Badge,
|
|
30
|
+
Card,
|
|
31
|
+
CardContent,
|
|
32
|
+
CardHeader,
|
|
33
|
+
CardTitle,
|
|
34
|
+
Table,
|
|
35
|
+
TableBody,
|
|
36
|
+
TableCell,
|
|
37
|
+
TableHead,
|
|
38
|
+
TableHeader,
|
|
39
|
+
TableRow,
|
|
40
|
+
} from "@godxjp/ui/data-display";
|
|
41
|
+
import { Text } from "@godxjp/ui/general";
|
|
42
|
+
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
43
|
+
|
|
44
|
+
// ── Data ────────────────────────────────────────────────────────────────────
|
|
45
|
+
// 2026年5月度 勤怠サマリ — 従業員ごとの月次集計。数値列を合計行へ畳み込む。
|
|
46
|
+
|
|
47
|
+
type Row = {
|
|
48
|
+
id: string;
|
|
49
|
+
name: string;
|
|
50
|
+
dept: string;
|
|
51
|
+
workDays: number; // 勤務日数
|
|
52
|
+
overtime: number; // 残業時間 (h)
|
|
53
|
+
late: number; // 遅刻回数
|
|
54
|
+
paidLeave: number; // 有給取得 (日)
|
|
55
|
+
pay: number; // 総支給額 (¥)
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const ROWS: Row[] = [
|
|
59
|
+
{
|
|
60
|
+
id: "E-1042",
|
|
61
|
+
name: "佐藤 美咲",
|
|
62
|
+
dept: "営業一課",
|
|
63
|
+
workDays: 20,
|
|
64
|
+
overtime: 12.5,
|
|
65
|
+
late: 0,
|
|
66
|
+
paidLeave: 1,
|
|
67
|
+
pay: 318500,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: "E-1043",
|
|
71
|
+
name: "鈴木 健太",
|
|
72
|
+
dept: "営業一課",
|
|
73
|
+
workDays: 21,
|
|
74
|
+
overtime: 28.0,
|
|
75
|
+
late: 2,
|
|
76
|
+
paidLeave: 0,
|
|
77
|
+
pay: 352000,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: "E-1051",
|
|
81
|
+
name: "高橋 直樹",
|
|
82
|
+
dept: "営業二課",
|
|
83
|
+
workDays: 19,
|
|
84
|
+
overtime: 6.0,
|
|
85
|
+
late: 0,
|
|
86
|
+
paidLeave: 2,
|
|
87
|
+
pay: 301200,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: "E-1058",
|
|
91
|
+
name: "田中 彩花",
|
|
92
|
+
dept: "営業二課",
|
|
93
|
+
workDays: 20,
|
|
94
|
+
overtime: 15.5,
|
|
95
|
+
late: 1,
|
|
96
|
+
paidLeave: 1,
|
|
97
|
+
pay: 309800,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: "E-1064",
|
|
101
|
+
name: "伊藤 拓海",
|
|
102
|
+
dept: "開発部",
|
|
103
|
+
workDays: 21,
|
|
104
|
+
overtime: 31.5,
|
|
105
|
+
late: 0,
|
|
106
|
+
paidLeave: 0,
|
|
107
|
+
pay: 388400,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
id: "E-1067",
|
|
111
|
+
name: "渡辺 さくら",
|
|
112
|
+
dept: "開発部",
|
|
113
|
+
workDays: 18,
|
|
114
|
+
overtime: 8.0,
|
|
115
|
+
late: 3,
|
|
116
|
+
paidLeave: 3,
|
|
117
|
+
pay: 295600,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: "E-1071",
|
|
121
|
+
name: "山本 涼介",
|
|
122
|
+
dept: "開発部",
|
|
123
|
+
workDays: 20,
|
|
124
|
+
overtime: 22.0,
|
|
125
|
+
late: 0,
|
|
126
|
+
paidLeave: 1,
|
|
127
|
+
pay: 364100,
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: "E-1078",
|
|
131
|
+
name: "中村 結衣",
|
|
132
|
+
dept: "管理部",
|
|
133
|
+
workDays: 21,
|
|
134
|
+
overtime: 4.5,
|
|
135
|
+
late: 0,
|
|
136
|
+
paidLeave: 0,
|
|
137
|
+
pay: 286000,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: "E-1082",
|
|
141
|
+
name: "小林 大輔",
|
|
142
|
+
dept: "管理部",
|
|
143
|
+
workDays: 19,
|
|
144
|
+
overtime: 18.0,
|
|
145
|
+
late: 1,
|
|
146
|
+
paidLeave: 2,
|
|
147
|
+
pay: 333700,
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: "E-1090",
|
|
151
|
+
name: "加藤 七海",
|
|
152
|
+
dept: "管理部",
|
|
153
|
+
workDays: 20,
|
|
154
|
+
overtime: 9.5,
|
|
155
|
+
late: 0,
|
|
156
|
+
paidLeave: 1,
|
|
157
|
+
pay: 298400,
|
|
158
|
+
},
|
|
159
|
+
];
|
|
160
|
+
|
|
161
|
+
// ── Aggregation (the totals row) ──────────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
const totals = ROWS.reduce(
|
|
164
|
+
(acc, r) => ({
|
|
165
|
+
workDays: acc.workDays + r.workDays,
|
|
166
|
+
overtime: acc.overtime + r.overtime,
|
|
167
|
+
late: acc.late + r.late,
|
|
168
|
+
paidLeave: acc.paidLeave + r.paidLeave,
|
|
169
|
+
pay: acc.pay + r.pay,
|
|
170
|
+
}),
|
|
171
|
+
{ workDays: 0, overtime: 0, late: 0, paidLeave: 0, pay: 0 },
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const yen = new Intl.NumberFormat("ja-JP", {
|
|
175
|
+
style: "currency",
|
|
176
|
+
currency: "JPY",
|
|
177
|
+
maximumFractionDigits: 0,
|
|
178
|
+
});
|
|
179
|
+
const hours = new Intl.NumberFormat("ja-JP", {
|
|
180
|
+
minimumFractionDigits: 1,
|
|
181
|
+
maximumFractionDigits: 1,
|
|
182
|
+
});
|
|
183
|
+
const count = new Intl.NumberFormat("ja-JP");
|
|
184
|
+
|
|
185
|
+
// 残業 fixed-mapping: ≥25h 山吹(warning), ≥15h 群青(info), 以下 若竹(success).
|
|
186
|
+
function overtimeTone(h: number): "warning" | "info" | "success" {
|
|
187
|
+
if (h >= 25) return "warning";
|
|
188
|
+
if (h >= 15) return "info";
|
|
189
|
+
return "success";
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ── Component ────────────────────────────────────────────────────────────────
|
|
193
|
+
|
|
194
|
+
export default function Demo() {
|
|
195
|
+
return (
|
|
196
|
+
<PageContainer
|
|
197
|
+
title="勤怠サマリ"
|
|
198
|
+
subtitle="2026年5月度 · 全10名 · 合計行は縦スクロールでも固定"
|
|
199
|
+
density="compact"
|
|
200
|
+
>
|
|
201
|
+
<Card>
|
|
202
|
+
<CardHeader className="flex flex-row items-center justify-between">
|
|
203
|
+
<CardTitle level={2}>従業員別 月次集計</CardTitle>
|
|
204
|
+
<Text size="xs" tone="muted" tabular>
|
|
205
|
+
対象 {ROWS.length} 名
|
|
206
|
+
</Text>
|
|
207
|
+
</CardHeader>
|
|
208
|
+
{/* flush so the table meets the card edge; vertical scroll inside the
|
|
209
|
+
card with header pinned top and totals pinned bottom. */}
|
|
210
|
+
<CardContent flush>
|
|
211
|
+
<div className="max-h-80 overflow-auto">
|
|
212
|
+
<Table>
|
|
213
|
+
<TableHeader className="bg-secondary sticky top-0 z-10">
|
|
214
|
+
<TableRow>
|
|
215
|
+
<TableHead className="w-24">社員番号</TableHead>
|
|
216
|
+
<TableHead>氏名</TableHead>
|
|
217
|
+
<TableHead className="hidden md:table-cell">部署</TableHead>
|
|
218
|
+
<TableHead className="text-end">勤務日数</TableHead>
|
|
219
|
+
<TableHead className="text-end">残業時間</TableHead>
|
|
220
|
+
<TableHead className="text-end">遅刻</TableHead>
|
|
221
|
+
<TableHead className="text-end">有給</TableHead>
|
|
222
|
+
<TableHead className="text-end">総支給額</TableHead>
|
|
223
|
+
</TableRow>
|
|
224
|
+
</TableHeader>
|
|
225
|
+
|
|
226
|
+
<TableBody>
|
|
227
|
+
{ROWS.map((r) => (
|
|
228
|
+
<TableRow key={r.id}>
|
|
229
|
+
<TableCell className="font-mono text-xs">{r.id}</TableCell>
|
|
230
|
+
<TableCell className="font-medium">{r.name}</TableCell>
|
|
231
|
+
<TableCell className="text-muted-foreground hidden md:table-cell">
|
|
232
|
+
{r.dept}
|
|
233
|
+
</TableCell>
|
|
234
|
+
<TableCell className="text-end tabular-nums">
|
|
235
|
+
{count.format(r.workDays)}
|
|
236
|
+
</TableCell>
|
|
237
|
+
<TableCell className="text-end tabular-nums">
|
|
238
|
+
<Badge tone={overtimeTone(r.overtime)} variant="outline">
|
|
239
|
+
{hours.format(r.overtime)}h
|
|
240
|
+
</Badge>
|
|
241
|
+
</TableCell>
|
|
242
|
+
<TableCell className="text-end tabular-nums">
|
|
243
|
+
{r.late > 0 ? (
|
|
244
|
+
<Badge tone="destructive" variant="outline">
|
|
245
|
+
{count.format(r.late)}
|
|
246
|
+
</Badge>
|
|
247
|
+
) : (
|
|
248
|
+
<Text tone="muted">0</Text>
|
|
249
|
+
)}
|
|
250
|
+
</TableCell>
|
|
251
|
+
<TableCell className="text-end tabular-nums">
|
|
252
|
+
{count.format(r.paidLeave)}
|
|
253
|
+
</TableCell>
|
|
254
|
+
<TableCell className="text-end tabular-nums">{yen.format(r.pay)}</TableCell>
|
|
255
|
+
</TableRow>
|
|
256
|
+
))}
|
|
257
|
+
</TableBody>
|
|
258
|
+
|
|
259
|
+
{/* Sticky footer totals row. No TableFooter primitive exists, so we
|
|
260
|
+
use a semantic <tfoot> with the same cell primitives. It is
|
|
261
|
+
pinned to the bottom of the scroll container. */}
|
|
262
|
+
<tfoot className="bg-secondary sticky bottom-0 z-10">
|
|
263
|
+
<TableRow className="hover:bg-secondary border-t-2">
|
|
264
|
+
<TableCell className="font-semibold">合計</TableCell>
|
|
265
|
+
<TableCell />
|
|
266
|
+
<TableCell className="hidden md:table-cell" />
|
|
267
|
+
<TableCell className="text-end font-semibold tabular-nums">
|
|
268
|
+
{count.format(totals.workDays)}
|
|
269
|
+
</TableCell>
|
|
270
|
+
<TableCell className="text-end font-semibold tabular-nums">
|
|
271
|
+
{hours.format(totals.overtime)}h
|
|
272
|
+
</TableCell>
|
|
273
|
+
<TableCell className="text-end font-semibold tabular-nums">
|
|
274
|
+
{count.format(totals.late)}
|
|
275
|
+
</TableCell>
|
|
276
|
+
<TableCell className="text-end font-semibold tabular-nums">
|
|
277
|
+
{count.format(totals.paidLeave)}
|
|
278
|
+
</TableCell>
|
|
279
|
+
<TableCell className="text-end font-semibold tabular-nums">
|
|
280
|
+
{yen.format(totals.pay)}
|
|
281
|
+
</TableCell>
|
|
282
|
+
</TableRow>
|
|
283
|
+
</tfoot>
|
|
284
|
+
</Table>
|
|
285
|
+
</div>
|
|
286
|
+
</CardContent>
|
|
287
|
+
</Card>
|
|
288
|
+
|
|
289
|
+
<Flex direction="row" align="center" gap="xs" className="mt-3">
|
|
290
|
+
<Text size="xs" tone="muted">
|
|
291
|
+
残業 凡例:
|
|
292
|
+
</Text>
|
|
293
|
+
<Badge tone="success" variant="outline">
|
|
294
|
+
~15h
|
|
295
|
+
</Badge>
|
|
296
|
+
<Badge tone="info" variant="outline">
|
|
297
|
+
15h~
|
|
298
|
+
</Badge>
|
|
299
|
+
<Badge tone="warning" variant="outline">
|
|
300
|
+
25h~
|
|
301
|
+
</Badge>
|
|
302
|
+
<Text size="xs" tone="muted" className="ms-2">
|
|
303
|
+
遅刻:
|
|
304
|
+
</Text>
|
|
305
|
+
<Badge tone="destructive" variant="outline">
|
|
306
|
+
回数
|
|
307
|
+
</Badge>
|
|
308
|
+
</Flex>
|
|
309
|
+
</PageContainer>
|
|
310
|
+
);
|
|
311
|
+
}
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Showcase · table-grouped-subtotals — グループ集計 (V11)
|
|
3
|
+
*
|
|
4
|
+
* 勤怠の部署別グループ集計。グループヘッダー行(部署名 + 人数 + 右寄せ数値小計)と
|
|
5
|
+
* 折りたたみ可能なグループ、最下部に総計行を備えた DataTable パターン。
|
|
6
|
+
*
|
|
7
|
+
* GAP: DataTable には「グループ行 / 折りたたみグループ / グループ小計 / 総計フッター」が
|
|
8
|
+
* ないため、real な Table ファミリ(Table/TableHeader/TableBody/TableRow/TableHead/
|
|
9
|
+
* TableCell)+ Button(折りたたみトグル) + Badge(人数/状態) + Card で COMPOSE している。
|
|
10
|
+
* 生の <table> や手書きコントロールは一切使わず、全て @godxjp/ui プリミティブのみ。
|
|
11
|
+
*
|
|
12
|
+
* DNA: compact 密度・小見出し・tabular-nums の数値列・固定カラーシグナル
|
|
13
|
+
* (success 若竹 / warning 山吹 / attention 朱 = 遅刻 / info 群青)・静かな JP コピー・絵文字なし。
|
|
14
|
+
*/
|
|
15
|
+
import * as React from "react";
|
|
16
|
+
import { ChevronDown, ChevronRight } from "lucide-react";
|
|
17
|
+
|
|
18
|
+
import { Button, Text } from "@godxjp/ui/general";
|
|
19
|
+
import {
|
|
20
|
+
Badge,
|
|
21
|
+
Card,
|
|
22
|
+
CardContent,
|
|
23
|
+
CardHeader,
|
|
24
|
+
CardTitle,
|
|
25
|
+
Table,
|
|
26
|
+
TableBody,
|
|
27
|
+
TableCell,
|
|
28
|
+
TableHead,
|
|
29
|
+
TableHeader,
|
|
30
|
+
TableRow,
|
|
31
|
+
} from "@godxjp/ui/data-display";
|
|
32
|
+
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
33
|
+
|
|
34
|
+
// ── 型 ────────────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
type AttendanceStatus = "present" | "late" | "leave-early";
|
|
37
|
+
|
|
38
|
+
type Employee = {
|
|
39
|
+
id: string;
|
|
40
|
+
name: string;
|
|
41
|
+
/** 勤務日数 */
|
|
42
|
+
days: number;
|
|
43
|
+
/** 総労働時間(時間) */
|
|
44
|
+
work: number;
|
|
45
|
+
/** 残業時間(時間) */
|
|
46
|
+
overtime: number;
|
|
47
|
+
/** 遅刻回数 */
|
|
48
|
+
late: number;
|
|
49
|
+
status: AttendanceStatus;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
type Group = {
|
|
53
|
+
id: string;
|
|
54
|
+
/** 部署名 */
|
|
55
|
+
label: string;
|
|
56
|
+
members: Employee[];
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// ── ダミーデータ(2026年5月度・部署別)─────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
const GROUPS: Group[] = [
|
|
62
|
+
{
|
|
63
|
+
id: "sales",
|
|
64
|
+
label: "営業部",
|
|
65
|
+
members: [
|
|
66
|
+
{
|
|
67
|
+
id: "E-1042",
|
|
68
|
+
name: "佐藤 健一",
|
|
69
|
+
days: 21,
|
|
70
|
+
work: 176.5,
|
|
71
|
+
overtime: 12.0,
|
|
72
|
+
late: 0,
|
|
73
|
+
status: "present",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: "E-1051",
|
|
77
|
+
name: "鈴木 美咲",
|
|
78
|
+
days: 20,
|
|
79
|
+
work: 168.0,
|
|
80
|
+
overtime: 4.5,
|
|
81
|
+
late: 2,
|
|
82
|
+
status: "late",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: "E-1063",
|
|
86
|
+
name: "高橋 涼",
|
|
87
|
+
days: 21,
|
|
88
|
+
work: 171.0,
|
|
89
|
+
overtime: 8.0,
|
|
90
|
+
late: 0,
|
|
91
|
+
status: "present",
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: "E-1077",
|
|
95
|
+
name: "田中 由美",
|
|
96
|
+
days: 19,
|
|
97
|
+
work: 152.5,
|
|
98
|
+
overtime: 0.0,
|
|
99
|
+
late: 0,
|
|
100
|
+
status: "leave-early",
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: "dev",
|
|
106
|
+
label: "開発部",
|
|
107
|
+
members: [
|
|
108
|
+
{
|
|
109
|
+
id: "E-2008",
|
|
110
|
+
name: "伊藤 大輔",
|
|
111
|
+
days: 21,
|
|
112
|
+
work: 180.0,
|
|
113
|
+
overtime: 22.5,
|
|
114
|
+
late: 0,
|
|
115
|
+
status: "present",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
id: "E-2015",
|
|
119
|
+
name: "渡辺 翔太",
|
|
120
|
+
days: 21,
|
|
121
|
+
work: 178.5,
|
|
122
|
+
overtime: 18.0,
|
|
123
|
+
late: 1,
|
|
124
|
+
status: "late",
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: "E-2031",
|
|
128
|
+
name: "山本 彩",
|
|
129
|
+
days: 20,
|
|
130
|
+
work: 165.0,
|
|
131
|
+
overtime: 9.5,
|
|
132
|
+
late: 0,
|
|
133
|
+
status: "present",
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
id: "support",
|
|
139
|
+
label: "カスタマーサポート部",
|
|
140
|
+
members: [
|
|
141
|
+
{
|
|
142
|
+
id: "E-3004",
|
|
143
|
+
name: "中村 拓也",
|
|
144
|
+
days: 22,
|
|
145
|
+
work: 176.0,
|
|
146
|
+
overtime: 6.0,
|
|
147
|
+
late: 0,
|
|
148
|
+
status: "present",
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
id: "E-3019",
|
|
152
|
+
name: "小林 結衣",
|
|
153
|
+
days: 20,
|
|
154
|
+
work: 160.0,
|
|
155
|
+
overtime: 2.0,
|
|
156
|
+
late: 3,
|
|
157
|
+
status: "late",
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
];
|
|
162
|
+
|
|
163
|
+
// ── フォーマッタ ────────────────────────────────────────────────────────────────
|
|
164
|
+
|
|
165
|
+
const hours = new Intl.NumberFormat("ja-JP", {
|
|
166
|
+
minimumFractionDigits: 1,
|
|
167
|
+
maximumFractionDigits: 1,
|
|
168
|
+
});
|
|
169
|
+
const fmtH = (n: number) => `${hours.format(n)}h`;
|
|
170
|
+
|
|
171
|
+
const STATUS_LABEL: Record<AttendanceStatus, string> = {
|
|
172
|
+
present: "出勤",
|
|
173
|
+
late: "遅刻あり",
|
|
174
|
+
"leave-early": "早退あり",
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// 固定カラーシグナル: 出勤=success若竹 / 遅刻=attention(=warning 山吹) / 早退=info群青
|
|
178
|
+
const STATUS_TONE: Record<AttendanceStatus, "success" | "warning" | "info"> = {
|
|
179
|
+
present: "success",
|
|
180
|
+
late: "warning",
|
|
181
|
+
"leave-early": "info",
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
type Subtotal = { days: number; work: number; overtime: number; late: number };
|
|
185
|
+
|
|
186
|
+
function subtotal(members: Employee[]): Subtotal {
|
|
187
|
+
return members.reduce<Subtotal>(
|
|
188
|
+
(acc, m) => ({
|
|
189
|
+
days: acc.days + m.days,
|
|
190
|
+
work: acc.work + m.work,
|
|
191
|
+
overtime: acc.overtime + m.overtime,
|
|
192
|
+
late: acc.late + m.late,
|
|
193
|
+
}),
|
|
194
|
+
{ days: 0, work: 0, overtime: 0, late: 0 },
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function grandTotal(groups: Group[]): Subtotal {
|
|
199
|
+
return groups.reduce<Subtotal>(
|
|
200
|
+
(acc, g) => {
|
|
201
|
+
const s = subtotal(g.members);
|
|
202
|
+
return {
|
|
203
|
+
days: acc.days + s.days,
|
|
204
|
+
work: acc.work + s.work,
|
|
205
|
+
overtime: acc.overtime + s.overtime,
|
|
206
|
+
late: acc.late + s.late,
|
|
207
|
+
};
|
|
208
|
+
},
|
|
209
|
+
{ days: 0, work: 0, overtime: 0, late: 0 },
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ── グループヘッダー行(部署名 + 人数バッジ + 右寄せ数値小計 + 折りたたみ)──────────
|
|
214
|
+
|
|
215
|
+
function GroupHeaderRow({
|
|
216
|
+
group,
|
|
217
|
+
open,
|
|
218
|
+
onToggle,
|
|
219
|
+
}: {
|
|
220
|
+
group: Group;
|
|
221
|
+
open: boolean;
|
|
222
|
+
onToggle: () => void;
|
|
223
|
+
}) {
|
|
224
|
+
const s = subtotal(group.members);
|
|
225
|
+
const Chevron = open ? ChevronDown : ChevronRight;
|
|
226
|
+
return (
|
|
227
|
+
<TableRow className="bg-secondary hover:bg-secondary border-b">
|
|
228
|
+
<TableCell className="py-2 ps-2 pe-0" colSpan={2}>
|
|
229
|
+
<Button
|
|
230
|
+
variant="ghost"
|
|
231
|
+
size="sm"
|
|
232
|
+
onClick={onToggle}
|
|
233
|
+
aria-expanded={open}
|
|
234
|
+
aria-controls={`grp-${group.id}`}
|
|
235
|
+
className="h-7 gap-2 font-medium"
|
|
236
|
+
>
|
|
237
|
+
<Chevron className="text-muted-foreground size-4" aria-hidden="true" />
|
|
238
|
+
{group.label}
|
|
239
|
+
<Badge variant="outline" tone="neutral" className="ms-1">
|
|
240
|
+
{group.members.length}名
|
|
241
|
+
</Badge>
|
|
242
|
+
</Button>
|
|
243
|
+
</TableCell>
|
|
244
|
+
<TableCell className="py-2 text-end font-medium tabular-nums">{s.days}日</TableCell>
|
|
245
|
+
<TableCell className="py-2 text-end font-medium tabular-nums">{fmtH(s.work)}</TableCell>
|
|
246
|
+
<TableCell className="py-2 text-end font-medium tabular-nums">{fmtH(s.overtime)}</TableCell>
|
|
247
|
+
<TableCell className="py-2 text-end tabular-nums">
|
|
248
|
+
{s.late > 0 ? (
|
|
249
|
+
<Badge variant="outline" tone="warning">
|
|
250
|
+
{s.late}回
|
|
251
|
+
</Badge>
|
|
252
|
+
) : (
|
|
253
|
+
<Text tone="muted" weight="medium">
|
|
254
|
+
0回
|
|
255
|
+
</Text>
|
|
256
|
+
)}
|
|
257
|
+
</TableCell>
|
|
258
|
+
<TableCell className="py-2" />
|
|
259
|
+
</TableRow>
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// ── 明細行 ──────────────────────────────────────────────────────────────────────
|
|
264
|
+
|
|
265
|
+
function MemberRow({ m }: { m: Employee }) {
|
|
266
|
+
return (
|
|
267
|
+
<TableRow>
|
|
268
|
+
<TableCell className="text-muted-foreground ps-10 font-mono text-xs">{m.id}</TableCell>
|
|
269
|
+
<TableCell>{m.name}</TableCell>
|
|
270
|
+
<TableCell className="text-end tabular-nums">{m.days}日</TableCell>
|
|
271
|
+
<TableCell className="text-end tabular-nums">{fmtH(m.work)}</TableCell>
|
|
272
|
+
<TableCell className="text-end tabular-nums">{fmtH(m.overtime)}</TableCell>
|
|
273
|
+
<TableCell className="text-end tabular-nums">
|
|
274
|
+
{m.late > 0 ? m.late : <Text tone="muted">—</Text>}
|
|
275
|
+
{m.late > 0 ? "回" : ""}
|
|
276
|
+
</TableCell>
|
|
277
|
+
<TableCell className="text-center">
|
|
278
|
+
<Badge variant="outline" tone={STATUS_TONE[m.status]}>
|
|
279
|
+
{STATUS_LABEL[m.status]}
|
|
280
|
+
</Badge>
|
|
281
|
+
</TableCell>
|
|
282
|
+
</TableRow>
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ── 集計テーブル ────────────────────────────────────────────────────────────────
|
|
287
|
+
|
|
288
|
+
function GroupedTable({
|
|
289
|
+
groups,
|
|
290
|
+
defaultClosed = [],
|
|
291
|
+
}: {
|
|
292
|
+
groups: Group[];
|
|
293
|
+
/** 初期状態で折りたたむグループ ID(静的に閉じた状態を見せる)*/
|
|
294
|
+
defaultClosed?: string[];
|
|
295
|
+
}) {
|
|
296
|
+
const [closed, setClosed] = React.useState<Set<string>>(new Set(defaultClosed));
|
|
297
|
+
const toggle = (id: string) => {
|
|
298
|
+
setClosed((prev) => {
|
|
299
|
+
const next = new Set(prev);
|
|
300
|
+
if (next.has(id)) next.delete(id);
|
|
301
|
+
else next.add(id);
|
|
302
|
+
return next;
|
|
303
|
+
});
|
|
304
|
+
};
|
|
305
|
+
const total = grandTotal(groups);
|
|
306
|
+
|
|
307
|
+
return (
|
|
308
|
+
<div className="ui-data-table-root">
|
|
309
|
+
<Table>
|
|
310
|
+
<TableHeader className="bg-background sticky top-0 z-10">
|
|
311
|
+
<TableRow>
|
|
312
|
+
<TableHead className="w-40">従業員番号</TableHead>
|
|
313
|
+
<TableHead>氏名 / 部署</TableHead>
|
|
314
|
+
<TableHead className="w-20 text-end">勤務日数</TableHead>
|
|
315
|
+
<TableHead className="w-24 text-end">総労働</TableHead>
|
|
316
|
+
<TableHead className="w-24 text-end">残業</TableHead>
|
|
317
|
+
<TableHead className="w-20 text-end">遅刻</TableHead>
|
|
318
|
+
<TableHead className="w-28 text-center">状態</TableHead>
|
|
319
|
+
</TableRow>
|
|
320
|
+
</TableHeader>
|
|
321
|
+
<TableBody>
|
|
322
|
+
{groups.map((g) => {
|
|
323
|
+
const open = !closed.has(g.id);
|
|
324
|
+
return (
|
|
325
|
+
<React.Fragment key={g.id}>
|
|
326
|
+
<GroupHeaderRow group={g} open={open} onToggle={() => toggle(g.id)} />
|
|
327
|
+
{open && g.members.map((m) => <MemberRow key={m.id} m={m} />)}
|
|
328
|
+
</React.Fragment>
|
|
329
|
+
);
|
|
330
|
+
})}
|
|
331
|
+
{/* 総計フッター行 */}
|
|
332
|
+
<TableRow className="bg-muted/40 hover:bg-muted/40 border-t-2">
|
|
333
|
+
<TableCell className="py-2 font-medium" colSpan={2}>
|
|
334
|
+
総計 · 全{groups.reduce((n, g) => n + g.members.length, 0)}名
|
|
335
|
+
</TableCell>
|
|
336
|
+
<TableCell className="py-2 text-end font-bold tabular-nums">{total.days}日</TableCell>
|
|
337
|
+
<TableCell className="py-2 text-end font-bold tabular-nums">
|
|
338
|
+
{fmtH(total.work)}
|
|
339
|
+
</TableCell>
|
|
340
|
+
<TableCell className="py-2 text-end font-bold tabular-nums">
|
|
341
|
+
{fmtH(total.overtime)}
|
|
342
|
+
</TableCell>
|
|
343
|
+
<TableCell className="py-2 text-end font-bold tabular-nums">{total.late}回</TableCell>
|
|
344
|
+
<TableCell className="py-2" />
|
|
345
|
+
</TableRow>
|
|
346
|
+
</TableBody>
|
|
347
|
+
</Table>
|
|
348
|
+
</div>
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export default function Demo() {
|
|
353
|
+
return (
|
|
354
|
+
<PageContainer
|
|
355
|
+
title="グループ集計"
|
|
356
|
+
subtitle="部署別の勤怠サマリ · グループヘッダー(部署名 + 人数 + 右寄せ小計)+ 折りたたみ + 総計"
|
|
357
|
+
density="compact"
|
|
358
|
+
>
|
|
359
|
+
<Flex direction="col" gap="lg">
|
|
360
|
+
{/* 全展開(既定)— 各グループの小計と明細が同時に見える */}
|
|
361
|
+
<Card>
|
|
362
|
+
<CardHeader className="flex flex-row items-center justify-between">
|
|
363
|
+
<CardTitle level={2}>2026年5月度 勤怠集計</CardTitle>
|
|
364
|
+
<Text size="xs" tone="muted" tabular>
|
|
365
|
+
締め: 2026-05-31
|
|
366
|
+
</Text>
|
|
367
|
+
</CardHeader>
|
|
368
|
+
<CardContent flush>
|
|
369
|
+
<GroupedTable groups={GROUPS} />
|
|
370
|
+
</CardContent>
|
|
371
|
+
</Card>
|
|
372
|
+
|
|
373
|
+
{/* 折りたたみ済みの状態を静的に提示 — 「カスタマーサポート部」は閉じて小計のみ表示 */}
|
|
374
|
+
<Card>
|
|
375
|
+
<CardHeader className="flex flex-row items-center justify-between">
|
|
376
|
+
<CardTitle level={2}>折りたたみ状態</CardTitle>
|
|
377
|
+
<Text size="xs" tone="muted">
|
|
378
|
+
閉じたグループは小計のみ表示(クリックで展開)
|
|
379
|
+
</Text>
|
|
380
|
+
</CardHeader>
|
|
381
|
+
<CardContent flush>
|
|
382
|
+
<GroupedTable groups={GROUPS} defaultClosed={["support"]} />
|
|
383
|
+
</CardContent>
|
|
384
|
+
</Card>
|
|
385
|
+
</Flex>
|
|
386
|
+
</PageContainer>
|
|
387
|
+
);
|
|
388
|
+
}
|