@eifi1/ui-kit 0.31.1 → 0.32.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 +51 -28
- package/dist/account/delete-account-setting.d.ts +8 -3
- package/dist/admin/admin-action-confirm.d.ts +8 -3
- package/dist/admin/admin-action-log.d.ts +1 -1
- package/dist/admin/admin-action-log.js +4 -2
- package/dist/admin/admin-action-log.js.map +1 -1
- package/dist/admin/invitations-panel.d.ts +8 -3
- package/dist/admin/invitations-panel.js +29 -26
- package/dist/admin/invitations-panel.js.map +1 -1
- package/dist/admin/reviewer-scope-editor.d.ts +8 -3
- package/dist/admin/role-select.d.ts +10 -5
- package/dist/admin/transfer-ownership-dialog.d.ts +8 -3
- package/dist/admin/user-roster.d.ts +10 -5
- package/dist/admin/user-roster.js +8 -47
- package/dist/admin/user-roster.js.map +1 -1
- package/dist/auth/auth-errors.d.ts +43 -8
- package/dist/auth/auth-errors.js +24 -1
- package/dist/auth/auth-errors.js.map +1 -1
- package/dist/auth/register-form.d.ts +8 -3
- package/dist/billing/billing-banner.d.ts +184 -0
- package/dist/billing/billing-banner.js +98 -0
- package/dist/billing/billing-banner.js.map +1 -0
- package/dist/billing/billing-labels.d.ts +100 -0
- package/dist/billing/billing-labels.js +76 -0
- package/dist/billing/billing-labels.js.map +1 -0
- package/dist/billing/billing-lock.d.ts +158 -0
- package/dist/billing/billing-lock.js +17 -0
- package/dist/billing/billing-lock.js.map +1 -0
- package/dist/billing/billing-standing.d.ts +149 -0
- package/dist/billing/billing-standing.js +28 -0
- package/dist/billing/billing-standing.js.map +1 -0
- package/dist/billing/plan-card.d.ts +248 -0
- package/dist/billing/plan-card.js +248 -0
- package/dist/billing/plan-card.js.map +1 -0
- package/dist/billing/plan-limit-notice.d.ts +156 -0
- package/dist/billing/plan-limit-notice.js +76 -0
- package/dist/billing/plan-limit-notice.js.map +1 -0
- package/dist/billing/plan-limit.d.ts +34 -0
- package/dist/billing/plan-limit.js +20 -0
- package/dist/billing/plan-limit.js.map +1 -0
- package/dist/billing/plan-price.d.ts +61 -0
- package/dist/billing/plan-price.js +45 -0
- package/dist/billing/plan-price.js.map +1 -0
- package/dist/billing/subscription-actions.d.ts +133 -0
- package/dist/billing/subscription-actions.js +28 -0
- package/dist/billing/subscription-actions.js.map +1 -0
- package/dist/billing/subscription-status-chip.d.ts +149 -0
- package/dist/billing/subscription-status-chip.js +48 -0
- package/dist/billing/subscription-status-chip.js.map +1 -0
- package/dist/chart.d.ts +9 -3
- package/dist/chart.js.map +1 -1
- package/dist/components/account-chips.d.ts +16 -4
- package/dist/components/account-chips.js +21 -3
- package/dist/components/account-chips.js.map +1 -1
- package/dist/components/alert-banner.d.ts +6 -1
- package/dist/components/alert-banner.js +5 -4
- package/dist/components/alert-banner.js.map +1 -1
- package/dist/components/amount-input.d.ts +8 -3
- package/dist/components/amount-input.js +5 -5
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/appearance-labels.d.ts +38 -0
- package/dist/components/appearance-labels.js +19 -0
- package/dist/components/appearance-labels.js.map +1 -0
- package/dist/components/autocomplete.js +2 -2
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/breadcrumbs.js +3 -2
- package/dist/components/breadcrumbs.js.map +1 -1
- package/dist/components/bulk-action-bar.d.ts +2 -2
- package/dist/components/bulk-action-bar.js +7 -12
- package/dist/components/bulk-action-bar.js.map +1 -1
- package/dist/components/button-group.d.ts +8 -3
- package/dist/components/button-group.js +7 -1
- package/dist/components/button-group.js.map +1 -1
- package/dist/components/calculator.d.ts +8 -3
- package/dist/components/calculator.js +4 -3
- package/dist/components/calculator.js.map +1 -1
- package/dist/components/calendar-heatmap.js +5 -5
- package/dist/components/calendar-heatmap.js.map +1 -1
- package/dist/components/chart-height.d.ts +23 -0
- package/dist/components/chart-height.js +15 -0
- package/dist/components/chart-height.js.map +1 -0
- package/dist/components/chart-zoom.js +6 -1
- package/dist/components/chart-zoom.js.map +1 -1
- package/dist/components/checkbox-group.js +2 -2
- package/dist/components/checkbox-group.js.map +1 -1
- package/dist/components/checkbox.d.ts +10 -0
- package/dist/components/checkbox.js +25 -10
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/chip.d.ts +19 -3
- package/dist/components/chip.js +54 -23
- package/dist/components/chip.js.map +1 -1
- package/dist/components/choice-card.d.ts +1 -1
- package/dist/components/choice-card.js +9 -8
- package/dist/components/choice-card.js.map +1 -1
- package/dist/components/column-mapper.js +1 -1
- package/dist/components/column-mapper.js.map +1 -1
- package/dist/components/combobox-core.js +8 -7
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.js +8 -8
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/confirm-dialog.d.ts +8 -3
- package/dist/components/copy-button.d.ts +10 -5
- package/dist/components/country-select.js +1 -1
- package/dist/components/country-select.js.map +1 -1
- package/dist/components/currency-select.js +3 -3
- package/dist/components/currency-select.js.map +1 -1
- package/dist/components/danger-confirm.d.ts +8 -3
- package/dist/components/data-table-cells.d.ts +1 -1
- package/dist/components/data-table-filter-popover.d.ts +1 -1
- package/dist/components/data-table-filter-popover.js +4 -1
- package/dist/components/data-table-filter-popover.js.map +1 -1
- package/dist/components/data-table-filters.d.ts +1 -1
- package/dist/components/data-table-labels.d.ts +1 -1
- package/dist/components/data-table-pagination.d.ts +3 -2
- package/dist/components/data-table-pagination.js +15 -6
- package/dist/components/data-table-pagination.js.map +1 -1
- package/dist/components/data-table.d.ts +1 -1
- package/dist/components/data-table.js +123 -52
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +1 -1
- package/dist/components/date-picker.js +18 -6
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/description-list.js +2 -2
- package/dist/components/description-list.js.map +1 -1
- package/dist/components/dialog-frame.js +2 -1
- package/dist/components/dialog-frame.js.map +1 -1
- package/dist/components/disclosure.js +3 -2
- package/dist/components/disclosure.js.map +1 -1
- package/dist/components/dropdown.d.ts +1 -1
- package/dist/components/dropdown.js +7 -1
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/facing-pair.d.ts +19 -6
- package/dist/components/facing-pair.js +3 -2
- package/dist/components/facing-pair.js.map +1 -1
- package/dist/components/field-parts.d.ts +102 -6
- package/dist/components/field-parts.js +81 -6
- package/dist/components/field-parts.js.map +1 -1
- package/dist/components/field-sync.d.ts +4 -1
- package/dist/components/field-sync.js +12 -2
- package/dist/components/field-sync.js.map +1 -1
- package/dist/components/field.js +2 -2
- package/dist/components/field.js.map +1 -1
- package/dist/components/file-button.d.ts +8 -3
- package/dist/components/file-dropzone.d.ts +8 -3
- package/dist/components/floating-panel.js +7 -4
- package/dist/components/floating-panel.js.map +1 -1
- package/dist/components/focus-ring.d.ts +12 -0
- package/dist/components/focus-ring.js +8 -0
- package/dist/components/focus-ring.js.map +1 -0
- package/dist/components/form-actions.d.ts +8 -3
- package/dist/components/form-actions.js +33 -19
- package/dist/components/form-actions.js.map +1 -1
- package/dist/components/full-bleed-dialog.d.ts +11 -1
- package/dist/components/full-bleed-dialog.js +3 -1
- package/dist/components/full-bleed-dialog.js.map +1 -1
- package/dist/components/iban-input.d.ts +8 -3
- package/dist/components/image-grid.js +1 -1
- package/dist/components/image-grid.js.map +1 -1
- package/dist/components/inline-edit-field.js +10 -4
- package/dist/components/inline-edit-field.js.map +1 -1
- package/dist/components/language-select.d.ts +8 -3
- package/dist/components/legal-page.d.ts +26 -5
- package/dist/components/legal-page.js +3 -1
- package/dist/components/legal-page.js.map +1 -1
- package/dist/components/legal.d.ts +8 -3
- package/dist/components/legal.js +2 -1
- package/dist/components/legal.js.map +1 -1
- package/dist/components/lightbox.js +24 -2
- package/dist/components/lightbox.js.map +1 -1
- package/dist/components/line-items.js +2 -1
- package/dist/components/line-items.js.map +1 -1
- package/dist/components/list.d.ts +5 -0
- package/dist/components/list.js +13 -9
- package/dist/components/list.js.map +1 -1
- package/dist/components/measured-grid.d.ts +3 -1
- package/dist/components/measured-grid.js +38 -20
- package/dist/components/measured-grid.js.map +1 -1
- package/dist/components/menu-item.js +2 -1
- package/dist/components/menu-item.js.map +1 -1
- package/dist/components/mini-calendar.js +8 -4
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/money-field.d.ts +8 -3
- package/dist/components/month-picker.js +50 -39
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/nav-pills.js +1 -1
- package/dist/components/nav-pills.js.map +1 -1
- package/dist/components/number-field.d.ts +8 -3
- package/dist/components/number-input.d.ts +11 -4
- package/dist/components/number-input.js +8 -6
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +8 -3
- package/dist/components/numpad-sheet.js +2 -1
- package/dist/components/numpad-sheet.js.map +1 -1
- package/dist/components/one-time-code-input.js +2 -2
- package/dist/components/one-time-code-input.js.map +1 -1
- package/dist/components/page-contents.js +2 -2
- package/dist/components/page-contents.js.map +1 -1
- package/dist/components/phone-input.d.ts +8 -3
- package/dist/components/phone-input.js +4 -4
- package/dist/components/phone-input.js.map +1 -1
- package/dist/components/pie-chart.d.ts +8 -2
- package/dist/components/pie-chart.js +11 -7
- package/dist/components/pie-chart.js.map +1 -1
- package/dist/components/popover.d.ts +9 -1
- package/dist/components/popover.js +8 -4
- package/dist/components/popover.js.map +1 -1
- package/dist/components/row-actions.d.ts +100 -0
- package/dist/components/row-actions.js +231 -0
- package/dist/components/row-actions.js.map +1 -0
- package/dist/components/scroll-area.js +1 -1
- package/dist/components/scroll-area.js.map +1 -1
- package/dist/components/search-field.js +3 -2
- package/dist/components/search-field.js.map +1 -1
- package/dist/components/series-chart-budget.d.ts +30 -7
- package/dist/components/series-chart-budget.js +12 -4
- package/dist/components/series-chart-budget.js.map +1 -1
- package/dist/components/series-chart-ticks.d.ts +7 -1
- package/dist/components/series-chart-ticks.js +6 -0
- package/dist/components/series-chart-ticks.js.map +1 -1
- package/dist/components/series-chart.d.ts +58 -28
- package/dist/components/series-chart.js +42 -32
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/settings-fields.d.ts +57 -8
- package/dist/components/settings-fields.js +39 -1
- package/dist/components/settings-fields.js.map +1 -1
- package/dist/components/share-card.d.ts +11 -6
- package/dist/components/share-card.js +8 -2
- package/dist/components/share-card.js.map +1 -1
- package/dist/components/sign-chip.d.ts +4 -0
- package/dist/components/sign-chip.js +17 -4
- package/dist/components/sign-chip.js.map +1 -1
- package/dist/components/signature-pad.d.ts +3 -1
- package/dist/components/signature-pad.js +8 -5
- package/dist/components/signature-pad.js.map +1 -1
- package/dist/components/slider.js +7 -6
- package/dist/components/slider.js.map +1 -1
- package/dist/components/sparkline.d.ts +5 -1
- package/dist/components/sparkline.js +4 -2
- package/dist/components/sparkline.js.map +1 -1
- package/dist/components/stat-tile.d.ts +17 -1
- package/dist/components/stat-tile.js +48 -20
- package/dist/components/stat-tile.js.map +1 -1
- package/dist/components/status-dot.d.ts +4 -0
- package/dist/components/status-dot.js +9 -2
- package/dist/components/status-dot.js.map +1 -1
- package/dist/components/swipeable-row.js +10 -2
- package/dist/components/swipeable-row.js.map +1 -1
- package/dist/components/switch.d.ts +21 -7
- package/dist/components/switch.js +24 -11
- package/dist/components/switch.js.map +1 -1
- package/dist/components/table.js +2 -2
- package/dist/components/table.js.map +1 -1
- package/dist/components/text-link.d.ts +8 -3
- package/dist/components/text-link.js +1 -1
- package/dist/components/text-link.js.map +1 -1
- package/dist/components/text.d.ts +7 -2
- package/dist/components/text.js +5 -5
- package/dist/components/text.js.map +1 -1
- package/dist/components/tile-radio.js +2 -1
- package/dist/components/tile-radio.js.map +1 -1
- package/dist/components/time-input.d.ts +8 -3
- package/dist/components/toast.d.ts +18 -2
- package/dist/components/toast.js +8 -5
- package/dist/components/toast.js.map +1 -1
- package/dist/components/toggle-group.d.ts +25 -3
- package/dist/components/toggle-group.js +40 -11
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle-legend.d.ts +10 -1
- package/dist/components/toggle-legend.js +21 -7
- package/dist/components/toggle-legend.js.map +1 -1
- package/dist/components/translation-review-editor.js +1 -1
- package/dist/components/translation-review-editor.js.map +1 -1
- package/dist/components/translation-review-parts.d.ts +4 -0
- package/dist/components/translation-review.d.ts +4 -0
- package/dist/components/translation-review.js +3 -3
- package/dist/components/translation-review.js.map +1 -1
- package/dist/components/tree-view.js +3 -2
- package/dist/components/tree-view.js.map +1 -1
- package/dist/components/treemap.d.ts +5 -2
- package/dist/components/treemap.js +33 -16
- package/dist/components/treemap.js.map +1 -1
- package/dist/components/ui.d.ts +8 -3
- package/dist/components/ui.js +207 -119
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-table-state.d.ts +1 -1
- package/dist/components/user-avatar.d.ts +5 -1
- package/dist/components/user-avatar.js +1 -1
- package/dist/components/user-avatar.js.map +1 -1
- package/dist/components/wizard-stepper.js +20 -14
- package/dist/components/wizard-stepper.js.map +1 -1
- package/dist/{data-table-labels-DUELeXpa.d.ts → data-table-labels-kpAAVi6g.d.ts} +26 -2
- package/dist/data-table.d.ts +1 -1
- package/dist/{delete-account-setting-CpIhzxxZ.d.ts → delete-account-setting-FLyJf-kZ.d.ts} +642 -60
- package/dist/demo/demo-banner.js +1 -0
- package/dist/demo/demo-banner.js.map +1 -1
- package/dist/feedback/feedback-attachment.d.ts +8 -3
- package/dist/feedback/feedback-context.d.ts +8 -3
- package/dist/feedback/feedback-crash.d.ts +8 -3
- package/dist/feedback/feedback-dialog.d.ts +8 -3
- package/dist/feedback/feedback-dialog.js +3 -3
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-inbox.d.ts +8 -3
- package/dist/feedback/feedback-inbox.js +2 -2
- package/dist/feedback/feedback-inbox.js.map +1 -1
- package/dist/feedback/feedback-labels.d.ts +8 -3
- package/dist/feedback/feedback-menu.d.ts +9 -4
- package/dist/feedback/feedback-record.d.ts +8 -3
- package/dist/feedback/feedback-row-detail.d.ts +8 -3
- package/dist/feedback/feedback-status-undo.d.ts +8 -3
- package/dist/feedback/feedback-submit.d.ts +8 -3
- package/dist/feedback/feedback-swipe.d.ts +8 -3
- package/dist/feedback/feedback-table.d.ts +8 -3
- package/dist/feedback/feedback-thread.d.ts +8 -3
- package/dist/feedback/feedback-thread.js +3 -3
- package/dist/feedback/feedback-thread.js.map +1 -1
- package/dist/feedback.d.ts +8 -3
- package/dist/hooks/use-anchored-panel.d.ts +32 -3
- package/dist/hooks/use-anchored-panel.js +21 -3
- package/dist/hooks/use-anchored-panel.js.map +1 -1
- package/dist/hooks/use-breakpoint.d.ts +88 -0
- package/dist/hooks/use-breakpoint.js +50 -0
- package/dist/hooks/use-breakpoint.js.map +1 -0
- package/dist/hooks/use-file-drop.d.ts +8 -3
- package/dist/hooks/use-large-text.d.ts +29 -0
- package/dist/hooks/use-large-text.js +20 -0
- package/dist/hooks/use-large-text.js.map +1 -0
- package/dist/hooks/use-windowed-rows.d.ts +52 -8
- package/dist/hooks/use-windowed-rows.js +94 -5
- package/dist/hooks/use-windowed-rows.js.map +1 -1
- package/dist/i18n/defaults.d.ts +8 -3
- package/dist/i18n/defaults.js +8 -0
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.d.ts +8 -3
- package/dist/i18n/german.js +94 -3
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +8 -3
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/languages.d.ts +10 -5
- package/dist/i18n/locales/de-CH.d.ts +8 -3
- package/dist/i18n/locales/en.d.ts +8 -3
- package/dist/i18n/locales/es.d.ts +8 -3
- package/dist/i18n/locales/es.js +89 -3
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +8 -3
- package/dist/i18n/locales/fr.js +91 -3
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +8 -3
- package/dist/i18n/locales/hu.js +91 -3
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +8 -3
- package/dist/i18n/locales/it.js +92 -3
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +8 -3
- package/dist/i18n/locales/zh.js +89 -3
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.d.ts +8 -3
- package/dist/i18n/review.js +15 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +27 -11
- package/dist/index.js +77 -4
- package/dist/index.js.map +1 -1
- package/dist/landing/landing-actions.d.ts +8 -3
- package/dist/landing/landing-sections.d.ts +8 -3
- package/dist/landing/landing-sections.js +7 -3
- package/dist/landing/landing-sections.js.map +1 -1
- package/dist/landing/public-header.d.ts +9 -4
- package/dist/landing/public-header.js +3 -3
- package/dist/landing/public-header.js.map +1 -1
- package/dist/landing/routing.d.ts +8 -3
- package/dist/lib/cn.js +3 -2
- package/dist/lib/cn.js.map +1 -1
- package/dist/rhf/fields.d.ts +8 -3
- package/dist/rhf/fields.js +1 -1
- package/dist/rhf/fields.js.map +1 -1
- package/dist/rhf/form.d.ts +8 -3
- package/dist/rhf/form.js +2 -2
- package/dist/rhf/form.js.map +1 -1
- package/dist/rhf.d.ts +8 -3
- package/dist/search/command-palette.d.ts +1 -1
- package/dist/search/command-palette.js +9 -8
- package/dist/search/command-palette.js.map +1 -1
- package/dist/settings/settings-layout.js +2 -1
- package/dist/settings/settings-layout.js.map +1 -1
- package/dist/settings/settings-section.d.ts +8 -3
- package/dist/settings/use-account-appearance.d.ts +92 -0
- package/dist/settings/use-account-appearance.js +63 -0
- package/dist/settings/use-account-appearance.js.map +1 -0
- package/dist/settings/use-settings-route.d.ts +1 -1
- package/dist/settings/use-settings-route.js +2 -3
- package/dist/settings/use-settings-route.js.map +1 -1
- package/dist/shell/app-shell.d.ts +12 -171
- package/dist/shell/app-shell.js +144 -28
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/auth-layout.js +1 -1
- package/dist/shell/auth-layout.js.map +1 -1
- package/dist/shell/option-switcher-menu.js +1 -1
- package/dist/shell/option-switcher-menu.js.map +1 -1
- package/dist/shell/top-bar-brand.d.ts +8 -3
- package/dist/shell/top-bar-brand.js +3 -1
- package/dist/shell/top-bar-brand.js.map +1 -1
- package/dist/shell/topbar-action-menu.d.ts +4 -0
- package/dist/shell/topbar-action-menu.js +3 -3
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell/topbar-controls.js +4 -4
- package/dist/shell/topbar-controls.js.map +1 -1
- package/dist/shell.d.ts +9 -5
- package/dist/theme/contrast-tokens.d.ts +41 -0
- package/dist/theme/contrast-tokens.js +59 -0
- package/dist/theme/contrast-tokens.js.map +1 -0
- package/dist/theme/contrast.d.ts +110 -0
- package/dist/theme/contrast.js +128 -0
- package/dist/theme/contrast.js.map +1 -0
- package/dist/theme/palette-presets.d.ts +12 -1
- package/dist/theme/palette-presets.js +9 -4
- package/dist/theme/palette-presets.js.map +1 -1
- package/dist/theme/palette-store.js.map +1 -1
- package/dist/theme/text-size.d.ts +173 -0
- package/dist/theme/text-size.js +121 -0
- package/dist/theme/text-size.js.map +1 -0
- package/dist/wizard/stepper-nav.d.ts +8 -3
- package/dist/wizard/wizard-summary.js +1 -1
- package/dist/wizard/wizard-summary.js.map +1 -1
- package/dist/wizard.d.ts +8 -3
- package/package.json +1 -1
- package/src/admin/admin-action-log.tsx +6 -1
- package/src/admin/invitations-panel.tsx +36 -29
- package/src/admin/user-roster.tsx +17 -72
- package/src/auth/auth-errors.ts +68 -7
- package/src/billing/billing-banner.tsx +205 -0
- package/src/billing/billing-labels.ts +240 -0
- package/src/billing/billing-lock.ts +75 -0
- package/src/billing/billing-standing.ts +72 -0
- package/src/billing/plan-card.tsx +458 -0
- package/src/billing/plan-limit-notice.tsx +145 -0
- package/src/billing/plan-limit.ts +53 -0
- package/src/billing/plan-price.ts +101 -0
- package/src/billing/subscription-actions.tsx +76 -0
- package/src/billing/subscription-status-chip.tsx +95 -0
- package/src/chart.ts +2 -0
- package/src/components/account-chips.tsx +36 -10
- package/src/components/alert-banner.tsx +16 -7
- package/src/components/amount-input.tsx +5 -5
- package/src/components/appearance-labels.ts +47 -0
- package/src/components/autocomplete.tsx +2 -2
- package/src/components/breadcrumbs.tsx +3 -3
- package/src/components/bulk-action-bar.tsx +11 -14
- package/src/components/button-group.tsx +21 -0
- package/src/components/calculator.tsx +4 -3
- package/src/components/calendar-heatmap.tsx +5 -5
- package/src/components/chart-height.ts +30 -0
- package/src/components/chart-zoom.tsx +6 -1
- package/src/components/checkbox-group.tsx +2 -2
- package/src/components/checkbox.tsx +62 -20
- package/src/components/chip.tsx +139 -30
- package/src/components/choice-card.tsx +16 -11
- package/src/components/column-mapper.tsx +1 -1
- package/src/components/combobox-core.tsx +8 -7
- package/src/components/combobox.tsx +8 -8
- package/src/components/country-select.tsx +1 -1
- package/src/components/currency-select.tsx +3 -3
- package/src/components/data-table-filter-popover.tsx +7 -1
- package/src/components/data-table-pagination.tsx +60 -31
- package/src/components/data-table.tsx +164 -43
- package/src/components/date-picker.tsx +44 -10
- package/src/components/description-list.tsx +2 -2
- package/src/components/dialog-frame.tsx +2 -1
- package/src/components/disclosure.tsx +3 -2
- package/src/components/dropdown.tsx +10 -2
- package/src/components/facing-pair.ts +12 -5
- package/src/components/field-parts.tsx +190 -7
- package/src/components/field-sync.tsx +17 -3
- package/src/components/field.tsx +2 -2
- package/src/components/floating-panel.tsx +7 -4
- package/src/components/focus-ring.ts +12 -0
- package/src/components/form-actions.tsx +55 -18
- package/src/components/full-bleed-dialog.tsx +18 -4
- package/src/components/image-grid.tsx +1 -1
- package/src/components/inline-edit-field.tsx +26 -4
- package/src/components/legal-page.tsx +28 -2
- package/src/components/legal.tsx +19 -1
- package/src/components/lightbox.tsx +24 -2
- package/src/components/line-items.tsx +7 -1
- package/src/components/list.tsx +36 -10
- package/src/components/measured-grid.tsx +49 -24
- package/src/components/menu-item.tsx +2 -2
- package/src/components/mini-calendar.tsx +8 -4
- package/src/components/month-picker.tsx +15 -6
- package/src/components/nav-pills.tsx +1 -1
- package/src/components/number-input.tsx +14 -7
- package/src/components/numpad-sheet.tsx +2 -2
- package/src/components/one-time-code-input.tsx +2 -2
- package/src/components/page-contents.tsx +2 -2
- package/src/components/phone-input.tsx +9 -4
- package/src/components/pie-chart.tsx +19 -9
- package/src/components/popover.tsx +22 -5
- package/src/components/row-actions.tsx +450 -0
- package/src/components/scroll-area.tsx +1 -1
- package/src/components/search-field.tsx +4 -2
- package/src/components/series-chart-budget.ts +40 -8
- package/src/components/series-chart-ticks.ts +10 -0
- package/src/components/series-chart.tsx +123 -72
- package/src/components/settings-fields.tsx +89 -5
- package/src/components/share-card.tsx +31 -2
- package/src/components/sign-chip.tsx +28 -4
- package/src/components/signature-pad.tsx +13 -7
- package/src/components/slider.tsx +22 -9
- package/src/components/sparkline.tsx +11 -3
- package/src/components/stat-tile.tsx +70 -14
- package/src/components/status-dot.tsx +25 -2
- package/src/components/swipeable-row.tsx +10 -2
- package/src/components/switch.tsx +57 -23
- package/src/components/table.tsx +2 -2
- package/src/components/text-link.tsx +1 -1
- package/src/components/text.tsx +11 -6
- package/src/components/tile-radio.tsx +4 -1
- package/src/components/toast.tsx +27 -7
- package/src/components/toggle-group.tsx +115 -14
- package/src/components/toggle-legend.tsx +53 -8
- package/src/components/translation-review-editor.tsx +1 -1
- package/src/components/translation-review.tsx +11 -5
- package/src/components/tree-view.tsx +3 -2
- package/src/components/treemap.tsx +27 -10
- package/src/components/ui.tsx +353 -153
- package/src/components/user-avatar.tsx +1 -1
- package/src/components/wizard-stepper.tsx +5 -1
- package/src/demo/demo-banner.tsx +5 -0
- package/src/feedback/feedback-dialog.tsx +3 -3
- package/src/feedback/feedback-inbox.tsx +2 -2
- package/src/feedback/feedback-thread.tsx +3 -3
- package/src/hooks/use-anchored-panel.ts +67 -5
- package/src/hooks/use-breakpoint.ts +132 -0
- package/src/hooks/use-large-text.ts +41 -0
- package/src/hooks/use-windowed-rows.ts +168 -12
- package/src/i18n/defaults.ts +8 -0
- package/src/i18n/german.ts +107 -0
- package/src/i18n/kit-labels.tsx +12 -0
- package/src/i18n/locales/es.ts +98 -0
- package/src/i18n/locales/fr.ts +102 -0
- package/src/i18n/locales/hu.ts +100 -0
- package/src/i18n/locales/it.ts +103 -0
- package/src/i18n/locales/zh.ts +94 -0
- package/src/i18n/review.ts +14 -0
- package/src/index.ts +76 -6
- package/src/landing/landing-sections.tsx +7 -3
- package/src/landing/public-header.tsx +4 -4
- package/src/lib/cn.ts +13 -2
- package/src/rhf/fields.tsx +1 -1
- package/src/rhf/form.tsx +2 -2
- package/src/search/command-palette.tsx +10 -9
- package/src/settings/settings-layout.tsx +2 -1
- package/src/settings/use-account-appearance.ts +148 -0
- package/src/settings/use-settings-route.ts +3 -4
- package/src/shell/app-shell.tsx +278 -54
- package/src/shell/auth-layout.tsx +1 -1
- package/src/shell/option-switcher-menu.tsx +1 -1
- package/src/shell/top-bar-brand.tsx +3 -1
- package/src/shell/topbar-action-menu.tsx +3 -3
- package/src/shell/topbar-controls.tsx +4 -4
- package/src/theme/contrast-tokens.ts +112 -0
- package/src/theme/contrast.ts +225 -0
- package/src/theme/palette-presets.ts +24 -4
- package/src/theme/palette-store.ts +6 -1
- package/src/theme/text-size.ts +283 -0
- package/src/wizard/wizard-summary.tsx +4 -2
- package/tokens.css +158 -8
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { createContext, useId } from "react";
|
|
1
|
+
import { createContext, isValidElement, useContext, useId } from "react";
|
|
2
2
|
import type { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
3
|
+
import { HelpCircle } from "lucide-react";
|
|
3
4
|
import { cn } from "../lib/cn";
|
|
4
|
-
import {
|
|
5
|
+
import { useInlineFacts } from "../hooks/use-large-text";
|
|
6
|
+
import { FOCUS_RING } from "./focus-ring";
|
|
7
|
+
import { Tooltip, type TooltipSide } from "./tooltip";
|
|
5
8
|
import { useCommitReason } from "./write-lock";
|
|
6
9
|
import { hasMessage, mergeDescribedBy } from "./choice-parts";
|
|
7
10
|
|
|
@@ -29,7 +32,7 @@ import { hasMessage, mergeDescribedBy } from "./choice-parts";
|
|
|
29
32
|
// same baseline — which is what put dev#468's "?" three pixels above the word it
|
|
30
33
|
// belongs to.
|
|
31
34
|
export const STATIC_LABEL_TYPE =
|
|
32
|
-
"text-
|
|
35
|
+
"text-caption leading-tight text-[var(--text-muted)] peer-disabled:opacity-50";
|
|
33
36
|
|
|
34
37
|
// A field that always has a value (select / dropdown trigger) keeps the label
|
|
35
38
|
// permanently in the floated position — small, in the top strip, value below.
|
|
@@ -58,6 +61,92 @@ export function FieldLabel({ children, className, ...rest }: FieldLabelProps) {
|
|
|
58
61
|
|
|
59
62
|
/* ── hint ─────────────────────────────────────────────────────────────────── */
|
|
60
63
|
|
|
64
|
+
/**
|
|
65
|
+
* The "?" that explains a field, on the field's own label line (dev#468).
|
|
66
|
+
*
|
|
67
|
+
* Pass it to a labelled `Select` / `Input` as `hint`. It exists as a
|
|
68
|
+
* component rather than as a snippet each form repeats because the previous
|
|
69
|
+
* version was exactly that snippet — an absolutely-positioned button whose
|
|
70
|
+
* `top-1.5` was one guess at where an 11px label sits — and the reporter's
|
|
71
|
+
* follow-up was *"question mark is not centered. Is it part of the hoc?
|
|
72
|
+
* positioning problems seem quite frequently."* It was not part of the HOC. Now
|
|
73
|
+
* it is, and there is one place left where the answer can be wrong.
|
|
74
|
+
*
|
|
75
|
+
* A `<button>` rather than a bare icon: hover alone puts the explanation out of
|
|
76
|
+
* reach of a keyboard and of every touch device, and the tooltip shows on focus
|
|
77
|
+
* too. The text is also its accessible name, so a screen reader gets it without
|
|
78
|
+
* the bubble ever opening.
|
|
79
|
+
*/
|
|
80
|
+
export interface FieldHintProps extends Omit<ComponentPropsWithoutRef<"button">, "children"> {
|
|
81
|
+
/** The explanation. It is both the tooltip's text and, by default, the button's
|
|
82
|
+
* accessible name, so a screen reader gets it without the bubble ever opening. */
|
|
83
|
+
label: string;
|
|
84
|
+
/** Default `"start"`: before the hint in the reading direction (the left in LTR, the
|
|
85
|
+
* right in RTL). `left` / `right` stay physical. */
|
|
86
|
+
side?: TooltipSide;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function FieldHint({
|
|
90
|
+
label,
|
|
91
|
+
side = "start",
|
|
92
|
+
className,
|
|
93
|
+
"aria-label": ariaLabel,
|
|
94
|
+
...rest
|
|
95
|
+
}: FieldHintProps) {
|
|
96
|
+
return (
|
|
97
|
+
// `tap="toggle"` (0.25): the "?" exists only to explain, so a tap on a phone shows
|
|
98
|
+
// the bubble and the next tap hides it — the touch rule (no bubble left behind by a
|
|
99
|
+
// tap) would otherwise make it show nothing at all.
|
|
100
|
+
<Tooltip label={label} side={side} portal tap="toggle">
|
|
101
|
+
<button
|
|
102
|
+
{...rest}
|
|
103
|
+
// `type` after the spread, not before. These render inside forms — that is the
|
|
104
|
+
// only place a field has a label line — and a hint that defaulted to `submit`
|
|
105
|
+
// because a caller spread a props object at it would save the form on a click
|
|
106
|
+
// meant to explain a field.
|
|
107
|
+
type="button"
|
|
108
|
+
// The explanation names the button unless the caller says otherwise; passing
|
|
109
|
+
// `aria-label` is how you shorten it for a screen reader without shortening
|
|
110
|
+
// what the bubble shows.
|
|
111
|
+
aria-label={ariaLabel ?? label}
|
|
112
|
+
// Nothing to activate: the tooltip opens on hover and on focus, and a
|
|
113
|
+
// click that did something as well would be a second, undiscoverable
|
|
114
|
+
// behaviour on the same target.
|
|
115
|
+
onClick={(e) => e.preventDefault()}
|
|
116
|
+
// The kit's focus frame (0.32, §5): the "?" is a tab stop, and had no ring at all.
|
|
117
|
+
className={cn(
|
|
118
|
+
"flex rounded-full text-[var(--text-placeholder)] transition-colors hover:text-[var(--text-secondary)]",
|
|
119
|
+
FOCUS_RING,
|
|
120
|
+
className,
|
|
121
|
+
)}
|
|
122
|
+
>
|
|
123
|
+
<HelpCircle className="size-3.5" />
|
|
124
|
+
</button>
|
|
125
|
+
</Tooltip>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* A field's `hint` as the field should draw it here (0.32, docs/text-size-harmonization.md
|
|
131
|
+
* §4 "No fact only in a tooltip"): at Large and Extra large, and on a touch screen, a
|
|
132
|
+
* {@link FieldHint} becomes its own words — so the field shows them as its CAPTION under
|
|
133
|
+
* the box, where they are read without hovering or tapping a 14 px "?". Anywhere else,
|
|
134
|
+
* and for any other hint, the hint unchanged.
|
|
135
|
+
*
|
|
136
|
+
* The kit's fields call it through {@link useFieldHint} / {@link useFieldMessages}; a
|
|
137
|
+
* field that resolves its own `hint` (an app's, or one of the kit's own outside this
|
|
138
|
+
* file) calls it first and then treats the result as it treated a text hint.
|
|
139
|
+
*/
|
|
140
|
+
export function useInlineHint(hint: ReactNode): ReactNode {
|
|
141
|
+
const inline = useInlineFacts();
|
|
142
|
+
if (inline && isValidElement(hint) && hint.type === FieldHint) {
|
|
143
|
+
const words = (hint.props as FieldHintProps).label;
|
|
144
|
+
if (words) return words;
|
|
145
|
+
}
|
|
146
|
+
return hint;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
|
61
150
|
/**
|
|
62
151
|
* Whether a `hint` is a CAPTION (plain text: a non-empty string or a number) or
|
|
63
152
|
* something for the label line (a {@link FieldHint} "?", or any other node).
|
|
@@ -73,7 +162,7 @@ export function isTextHint(hint: ReactNode): hint is string | number {
|
|
|
73
162
|
|
|
74
163
|
/** The caption under a field — Select's and NumberInput's type, so every field's
|
|
75
164
|
* standing advice reads alike. */
|
|
76
|
-
export const FIELD_CAPTION_CLASS = "mt-1 text-
|
|
165
|
+
export const FIELD_CAPTION_CLASS = "mt-1 text-caption leading-tight text-[var(--text-muted)]";
|
|
77
166
|
|
|
78
167
|
export interface FieldHintParts {
|
|
79
168
|
/** The caller's `aria-describedby` with the caption's id appended — standing
|
|
@@ -92,7 +181,8 @@ export interface FieldHintParts {
|
|
|
92
181
|
* Split a field's `hint` into the caption under it (attached with `aria-describedby`)
|
|
93
182
|
* or the "?" on its label line. See {@link isTextHint}.
|
|
94
183
|
*/
|
|
95
|
-
export function useFieldHint(
|
|
184
|
+
export function useFieldHint(hintProp: ReactNode, describedBy: string | undefined): FieldHintParts {
|
|
185
|
+
const hint = useInlineHint(hintProp);
|
|
96
186
|
const captionId = useId();
|
|
97
187
|
const text = isTextHint(hint);
|
|
98
188
|
return {
|
|
@@ -197,13 +287,24 @@ export function useLockReason(commit: boolean | undefined, disabledReason: React
|
|
|
197
287
|
*/
|
|
198
288
|
export function LockedReason({
|
|
199
289
|
lock,
|
|
290
|
+
line = false,
|
|
200
291
|
className,
|
|
201
292
|
children,
|
|
202
293
|
}: {
|
|
203
294
|
lock: LockReason;
|
|
295
|
+
/** Draw the reason as a line under the control instead (0.32, §4) — see
|
|
296
|
+
* {@link DisabledReasonLine}; the caller decides with {@link useDisabledReasonLine}. */
|
|
297
|
+
line?: boolean;
|
|
204
298
|
className?: string;
|
|
205
299
|
children: ReactNode;
|
|
206
300
|
}) {
|
|
301
|
+
if (line) {
|
|
302
|
+
return (
|
|
303
|
+
<DisabledReasonLine id={lock.reasonId} reason={lock.reason} className={className}>
|
|
304
|
+
{children}
|
|
305
|
+
</DisabledReasonLine>
|
|
306
|
+
);
|
|
307
|
+
}
|
|
207
308
|
return (
|
|
208
309
|
<Tooltip label={lock.reason} className={className}>
|
|
209
310
|
<>
|
|
@@ -216,6 +317,87 @@ export function LockedReason({
|
|
|
216
317
|
);
|
|
217
318
|
}
|
|
218
319
|
|
|
320
|
+
/* ── no fact only in a tooltip (0.32, docs/text-size-harmonization.md §4, §10.8) ── */
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Where a control's `disabledReason` is shown (§4 "No fact only in a tooltip"):
|
|
324
|
+
*
|
|
325
|
+
* - `"auto"` (default): as a LINE under the control at Large and Extra large and on a
|
|
326
|
+
* touch screen (`useInlineFacts`) — the reader asked for bigger type, or cannot hover
|
|
327
|
+
* — and in the kit {@link Tooltip} otherwise, where a pointer can hover it open and
|
|
328
|
+
* the form keeps its rhythm. Inside {@link CompactControls} (a top bar, a dense row's
|
|
329
|
+
* inline actions) it stays the tooltip at every size: there is no room for a line.
|
|
330
|
+
* - `"line"`: always the line — a form whose locked submit should say why at once.
|
|
331
|
+
* - `"tooltip"`: always the tooltip — a place the caller knows has no room, and where
|
|
332
|
+
* the reason is also said elsewhere on the screen (a banner over the form).
|
|
333
|
+
*
|
|
334
|
+
* Either way the reason is the control's `aria-describedby`, so a screen reader hears
|
|
335
|
+
* it on focus; the line IS that description (one copy), the tooltip keeps its hidden
|
|
336
|
+
* copy as before.
|
|
337
|
+
*/
|
|
338
|
+
export type DisabledReasonDisplay = "auto" | "line" | "tooltip";
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Marks a region where the controls must stay compact at every text size (§4, §10.8):
|
|
342
|
+
* an IconButton keeps its icon alone (its `label` stays the name and the tooltip) and a
|
|
343
|
+
* `disabledReason` stays in the tooltip rather than a line. AppShell puts its top bar
|
|
344
|
+
* in one ("the top bar keeps its essential icons"); `RowActions` its inline icons.
|
|
345
|
+
*
|
|
346
|
+
* For a toolbar that has no room, not for a whole page: the contract asks that the icon
|
|
347
|
+
* alone be rare. A dense row's actions belong in `RowActions`, which collapses them
|
|
348
|
+
* into a "⋯" menu at Large instead.
|
|
349
|
+
*/
|
|
350
|
+
export const CompactControlsContext = createContext(false);
|
|
351
|
+
|
|
352
|
+
export function CompactControls({ children, compact = true }: { children: ReactNode; compact?: boolean }) {
|
|
353
|
+
return <CompactControlsContext.Provider value={compact}>{children}</CompactControlsContext.Provider>;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/** Whether a control's `disabledReason` is drawn as a line here — see
|
|
357
|
+
* {@link DisabledReasonDisplay}. For the kit's own controls (Button, IconButton, Chip,
|
|
358
|
+
* ToggleGroup) and an app's control that has a reason to give. */
|
|
359
|
+
export function useDisabledReasonLine(display: DisabledReasonDisplay = "auto"): boolean {
|
|
360
|
+
const compact = useContext(CompactControlsContext);
|
|
361
|
+
const inline = useInlineFacts();
|
|
362
|
+
if (display === "line") return true;
|
|
363
|
+
if (display === "tooltip") return false;
|
|
364
|
+
return inline && !compact;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/** The reason line's type: a field caption's ({@link FIELD_CAPTION_CLASS}), so a locked
|
|
368
|
+
* control's "why" reads like a field's standing advice. Capped, so a long reason under
|
|
369
|
+
* a small control wraps rather than widening its row without end. */
|
|
370
|
+
export const DISABLED_REASON_LINE_CLASS =
|
|
371
|
+
"mt-1 block max-w-[20rem] text-caption leading-tight text-[var(--text-muted)]";
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* A control and its `disabledReason` as a line under it — the `"line"` form of
|
|
375
|
+
* {@link DisabledReasonDisplay}. The wrapper is the flex item now (`className`: the
|
|
376
|
+
* control's own layout, e.g. `self-stretch`); `items-start` keeps the control its own
|
|
377
|
+
* width, and a column parent still stretches the wrapper (FormActions' phone stack).
|
|
378
|
+
* The line carries `id`, which the control's `aria-describedby` names.
|
|
379
|
+
*/
|
|
380
|
+
export function DisabledReasonLine({
|
|
381
|
+
id,
|
|
382
|
+
reason,
|
|
383
|
+
className,
|
|
384
|
+
children,
|
|
385
|
+
}: {
|
|
386
|
+
id: string;
|
|
387
|
+
reason: ReactNode;
|
|
388
|
+
className?: string;
|
|
389
|
+
children: ReactNode;
|
|
390
|
+
}) {
|
|
391
|
+
return (
|
|
392
|
+
<span data-slot="disabled-reason" className={cn("inline-flex max-w-full flex-col items-start", className)}>
|
|
393
|
+
{children}
|
|
394
|
+
<span id={id} className={DISABLED_REASON_LINE_CLASS}>
|
|
395
|
+
{reason}
|
|
396
|
+
</span>
|
|
397
|
+
</span>
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
|
|
219
401
|
/* ── groups ───────────────────────────────────────────────────────────────── */
|
|
220
402
|
|
|
221
403
|
/**
|
|
@@ -234,7 +416,7 @@ export function hasContent(node: ReactNode): boolean {
|
|
|
234
416
|
return node !== undefined && node !== null && node !== false && node !== "";
|
|
235
417
|
}
|
|
236
418
|
|
|
237
|
-
const FIELD_ERROR_CLASS = "mt-1 text-
|
|
419
|
+
const FIELD_ERROR_CLASS = "mt-1 text-caption leading-tight text-[var(--danger)]";
|
|
238
420
|
|
|
239
421
|
export interface FieldMessages {
|
|
240
422
|
/** `invalid`, a message, or an `aria-invalid` from outside (a form library). */
|
|
@@ -251,7 +433,7 @@ export interface FieldMessages {
|
|
|
251
433
|
|
|
252
434
|
/** `hint` / `error` / `invalid` resolved the way `Select` resolves them. */
|
|
253
435
|
export function useFieldMessages({
|
|
254
|
-
hint,
|
|
436
|
+
hint: hintProp,
|
|
255
437
|
error,
|
|
256
438
|
invalid,
|
|
257
439
|
describedBy,
|
|
@@ -263,6 +445,7 @@ export function useFieldMessages({
|
|
|
263
445
|
describedBy?: string;
|
|
264
446
|
ariaInvalid?: unknown;
|
|
265
447
|
}): FieldMessages {
|
|
448
|
+
const hint = useInlineHint(hintProp);
|
|
266
449
|
const hintId = useId();
|
|
267
450
|
const errorId = useId();
|
|
268
451
|
const textHint = isTextHint(hint);
|
|
@@ -3,7 +3,9 @@ import type { ReactNode } from "react";
|
|
|
3
3
|
import { AlertCircle, Check, Loader2, Pencil, PencilLine } from "lucide-react";
|
|
4
4
|
import { cn } from "../lib/cn";
|
|
5
5
|
import { Tooltip } from "./tooltip";
|
|
6
|
+
import { FOCUS_RING } from "./focus-ring";
|
|
6
7
|
import { useKitLabels } from "../i18n/kit-labels";
|
|
8
|
+
import { useLargeText } from "../hooks/use-large-text";
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Sync state for a field backed by a database row.
|
|
@@ -252,7 +254,10 @@ export interface FieldSyncIndicatorProps {
|
|
|
252
254
|
error?: Error | null;
|
|
253
255
|
/** Override any of the five English defaults. */
|
|
254
256
|
labels?: Partial<FieldSyncLabels>;
|
|
255
|
-
/** Render the label beside the icon instead of only in the tooltip.
|
|
257
|
+
/** Render the label beside the icon instead of only in the tooltip. Always on at
|
|
258
|
+
* Large and Extra large (0.32, docs/text-size-harmonization.md §4 "No fact only in a
|
|
259
|
+
* tooltip"): the reader who asked for bigger type gets the words, not a 14 px glyph
|
|
260
|
+
* and a bubble. */
|
|
256
261
|
showLabel?: boolean;
|
|
257
262
|
/** When given, the error state renders a retry button after the icon. */
|
|
258
263
|
onRetry?: () => void;
|
|
@@ -282,6 +287,8 @@ export function FieldSyncIndicator({
|
|
|
282
287
|
className,
|
|
283
288
|
}: FieldSyncIndicatorProps) {
|
|
284
289
|
const l = useKitLabels("fieldSync", DEFAULT_FIELD_SYNC_LABELS, labels);
|
|
290
|
+
const large = useLargeText();
|
|
291
|
+
showLabel = showLabel || large;
|
|
285
292
|
const { color, Icon } = STATE_STYLE[state];
|
|
286
293
|
const text =
|
|
287
294
|
state === "error" ? (error?.message?.trim() ? error.message : l.error) : l[state];
|
|
@@ -312,7 +319,11 @@ export function FieldSyncIndicator({
|
|
|
312
319
|
<button
|
|
313
320
|
type="button"
|
|
314
321
|
onClick={onRetry}
|
|
315
|
-
|
|
322
|
+
// The kit's focus frame (0.32, §5), stood off the word.
|
|
323
|
+
className={cn(
|
|
324
|
+
"rounded underline underline-offset-2 hover:no-underline focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-surface)]",
|
|
325
|
+
FOCUS_RING,
|
|
326
|
+
)}
|
|
316
327
|
style={{ color }}
|
|
317
328
|
>
|
|
318
329
|
{l.retry}
|
|
@@ -461,7 +472,10 @@ export function FieldSyncRow<T>({
|
|
|
461
472
|
type="button"
|
|
462
473
|
onClick={retry}
|
|
463
474
|
aria-label={l.retry}
|
|
464
|
-
className=
|
|
475
|
+
className={cn(
|
|
476
|
+
"pointer-events-auto flex rounded-full text-[var(--status-error)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-surface)]",
|
|
477
|
+
FOCUS_RING,
|
|
478
|
+
)}
|
|
465
479
|
>
|
|
466
480
|
<AlertCircle aria-hidden className="size-4" />
|
|
467
481
|
</button>
|
package/src/components/field.tsx
CHANGED
|
@@ -177,12 +177,12 @@ export function Field({
|
|
|
177
177
|
? children(control, { labelId: label !== undefined ? labelId : undefined })
|
|
178
178
|
: children}
|
|
179
179
|
{hasHint && (
|
|
180
|
-
<p id={hintId} className="text-
|
|
180
|
+
<p id={hintId} className="text-caption leading-tight text-[var(--text-muted)]">
|
|
181
181
|
{hint}
|
|
182
182
|
</p>
|
|
183
183
|
)}
|
|
184
184
|
{hasError && (
|
|
185
|
-
<p id={errorId} className="text-
|
|
185
|
+
<p id={errorId} className="text-caption leading-tight text-[var(--danger)]">
|
|
186
186
|
{error}
|
|
187
187
|
</p>
|
|
188
188
|
)}
|
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
import { X } from "lucide-react";
|
|
15
15
|
|
|
16
16
|
import { cn } from "../lib/cn";
|
|
17
|
+
import { FOCUS_RING } from "./focus-ring";
|
|
17
18
|
import { dirOf, type Direction } from "../lib/direction";
|
|
18
19
|
import { registerFloating } from "../lib/floating-stack";
|
|
19
20
|
import { useKitLabels, useKitLink } from "../i18n/kit-labels";
|
|
@@ -243,7 +244,8 @@ export function FloatingActionButton({
|
|
|
243
244
|
"bg-[var(--bg-surface)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] hover:text-[var(--text-primary)]",
|
|
244
245
|
pressed === true &&
|
|
245
246
|
"border-[var(--brand)] bg-[var(--brand-bg)] text-[var(--brand)] hover:bg-[var(--brand-bg-hover)]",
|
|
246
|
-
"outline-none focus-visible:ring-
|
|
247
|
+
"outline-none focus-visible:ring-offset-2",
|
|
248
|
+
FOCUS_RING,
|
|
247
249
|
className,
|
|
248
250
|
)}
|
|
249
251
|
>
|
|
@@ -505,7 +507,7 @@ export function FloatingPanel({
|
|
|
505
507
|
setOpen(false);
|
|
506
508
|
}}
|
|
507
509
|
aria-label={labels.close}
|
|
508
|
-
className="-me-1.5 shrink-0 rounded p-1.5 text-[var(--text-muted)] outline-none hover:bg-[var(--bg-hover)] hover:text-[var(--text-secondary)]
|
|
510
|
+
className={cn("-me-1.5 shrink-0 rounded p-1.5 text-[var(--text-muted)] outline-none hover:bg-[var(--bg-hover)] hover:text-[var(--text-secondary)]", FOCUS_RING)}
|
|
509
511
|
>
|
|
510
512
|
<X aria-hidden className="size-5" />
|
|
511
513
|
</button>
|
|
@@ -687,7 +689,8 @@ export function FloatingAction({
|
|
|
687
689
|
const isLink = href !== undefined;
|
|
688
690
|
const look = cn(
|
|
689
691
|
"relative flex size-12 items-center justify-center transition-colors",
|
|
690
|
-
"outline-none focus-visible:ring-
|
|
692
|
+
"outline-none focus-visible:ring-inset",
|
|
693
|
+
FOCUS_RING,
|
|
691
694
|
"disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:size-5",
|
|
692
695
|
variant === "primary"
|
|
693
696
|
? "bg-[var(--brand)] text-[var(--brand-contrast)] hover:bg-[var(--brand-hover)]"
|
|
@@ -704,7 +707,7 @@ export function FloatingAction({
|
|
|
704
707
|
aria-hidden
|
|
705
708
|
data-badge=""
|
|
706
709
|
className={cn(
|
|
707
|
-
"pointer-events-none absolute end-1 top-1 h-4 min-w-4 rounded-full px-1 text-center text-
|
|
710
|
+
"pointer-events-none absolute end-1 top-1 h-4 min-w-4 rounded-full px-1 text-center text-micro leading-4 font-semibold",
|
|
708
711
|
BADGE_TONE[badgeTone],
|
|
709
712
|
)}
|
|
710
713
|
>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kit's focus frame (§5): a brand ring `--focus-ring-width` wide — 2 px, 3 px under
|
|
3
|
+
* More contrast (tokens.css) — on keyboard focus only. ONE frame instead of the hundred
|
|
4
|
+
* spelled-out `focus-visible:ring-2` copies, so the contrast setting can thicken all of
|
|
5
|
+
* them at once. Compose with `ring-inset` or `ring-offset-*` where a component needs it.
|
|
6
|
+
*/
|
|
7
|
+
export const FOCUS_RING =
|
|
8
|
+
"focus-visible:outline-none focus-visible:ring-[length:var(--focus-ring-width)] focus-visible:ring-[var(--brand)]";
|
|
9
|
+
|
|
10
|
+
/** Just the width of {@link FOCUS_RING}, for a ring in another colour (a danger control's,
|
|
11
|
+
* `--brand-contrast` on a filled button): `cn(FOCUS_RING_WIDTH, "focus-visible:ring-[var(--danger)]")`. */
|
|
12
|
+
export const FOCUS_RING_WIDTH = "focus-visible:ring-[length:var(--focus-ring-width)]";
|
|
@@ -3,7 +3,8 @@ import type { ComponentPropsWithoutRef, ReactNode, Ref } from "react";
|
|
|
3
3
|
import type { LucideIcon } from "lucide-react";
|
|
4
4
|
import { cn } from "../lib/cn";
|
|
5
5
|
import { useKitLabels } from "../i18n/kit-labels";
|
|
6
|
-
import {
|
|
6
|
+
import { useBreakpoint, usePhoneLayout } from "../hooks/use-breakpoint";
|
|
7
|
+
import { useLargeText } from "../hooks/use-large-text";
|
|
7
8
|
import { isApplePlatform } from "../hooks/use-hotkey";
|
|
8
9
|
import { Button, Spinner, type ButtonProps, type ButtonSize, type ButtonVariant } from "./ui";
|
|
9
10
|
import { useWriteLock } from "./write-lock";
|
|
@@ -43,11 +44,29 @@ export type FormActionsAlign = "start" | "center" | "end" | "between";
|
|
|
43
44
|
*/
|
|
44
45
|
export type FormActionsPlacement = "inline" | "sticky" | "dialog";
|
|
45
46
|
|
|
47
|
+
/**
|
|
48
|
+
* When the row's buttons STACK, one per line at the row's full width (0.32,
|
|
49
|
+
* docs/text-size-harmonization.md §4 "FormActions stack full width on a phone layout"):
|
|
50
|
+
*
|
|
51
|
+
* - `"auto"` (default): on the phone layout (`usePhoneLayout()`, `max-md:` at the text
|
|
52
|
+
* size in force) at Large and Extra large. There a phone is 312 or 260 px of text
|
|
53
|
+
* wide, and Cancel and a "Save changes" side by side wrap into a ragged pair with
|
|
54
|
+
* one 48 px target squeezed against the other. Normal keeps the row the apps tuned.
|
|
55
|
+
* - `"phone"`: on the phone layout at every text size.
|
|
56
|
+
* - `"never"`: always the row.
|
|
57
|
+
*
|
|
58
|
+
* Stacked, the order is the DOM's — the start group (the destructive action), the extra
|
|
59
|
+
* actions, Cancel, then Save at the bottom, under the thumb — so the visual order and
|
|
60
|
+
* the tab order stay one.
|
|
61
|
+
*/
|
|
62
|
+
export type FormActionsStack = "auto" | "phone" | "never";
|
|
63
|
+
|
|
46
64
|
/**
|
|
47
65
|
* A placement per breakpoint, mobile first — `{ base: "sticky", md: "inline" }` is a
|
|
48
66
|
* Save row stuck to the bottom of a phone's long form and in the flow under the last
|
|
49
|
-
* field from 768px up, where the form fits. The breakpoints are
|
|
50
|
-
* md 768, lg 1024, xl 1280px
|
|
67
|
+
* field from 768px up, where the form fits. The breakpoints are the classes' (sm 640,
|
|
68
|
+
* md 768, lg 1024, xl 1280px at Normal text size, and 1.25 / 1.5 times that at Large /
|
|
69
|
+
* Extra large, as `md:` is since 0.32), as `BulkActionBar`'s `variant` breakpoints are, and
|
|
51
70
|
* resolved the same way, in JS: the sticky row is positioned by inline style, which a
|
|
52
71
|
* `md:` class cannot reach. keksdose switched `placement` on its own media query at
|
|
53
72
|
* every long form for want of this. The breakpoints are the VIEWPORT's, not the
|
|
@@ -61,12 +80,9 @@ export interface ResponsiveFormActionsPlacement {
|
|
|
61
80
|
xl?: FormActionsPlacement;
|
|
62
81
|
}
|
|
63
82
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
["md", "(min-width: 768px)"],
|
|
68
|
-
["sm", "(min-width: 640px)"],
|
|
69
|
-
] as const;
|
|
83
|
+
/** Widest first: the first that matches and names a value wins. Each is the class's own
|
|
84
|
+
* breakpoint at the text size in force (`useBreakpoint`), so `md` here is `md:` there. */
|
|
85
|
+
const BREAKPOINTS = ["xl", "lg", "md", "sm"] as const;
|
|
70
86
|
|
|
71
87
|
/** The placement in force: the widest breakpoint that matches AND names one, else
|
|
72
88
|
* `base`. The queries are subscribed unconditionally (hooks cannot be skipped); a
|
|
@@ -76,13 +92,13 @@ function useResolvedPlacement(
|
|
|
76
92
|
placement: FormActionsPlacement | ResponsiveFormActionsPlacement,
|
|
77
93
|
): FormActionsPlacement {
|
|
78
94
|
const matches = {
|
|
79
|
-
xl:
|
|
80
|
-
lg:
|
|
81
|
-
md:
|
|
82
|
-
sm:
|
|
95
|
+
xl: useBreakpoint("xl"),
|
|
96
|
+
lg: useBreakpoint("lg"),
|
|
97
|
+
md: useBreakpoint("md"),
|
|
98
|
+
sm: useBreakpoint("sm"),
|
|
83
99
|
};
|
|
84
100
|
if (typeof placement === "string") return placement;
|
|
85
|
-
for (const
|
|
101
|
+
for (const key of BREAKPOINTS) {
|
|
86
102
|
const p = placement[key];
|
|
87
103
|
if (matches[key] && p !== undefined) return p;
|
|
88
104
|
}
|
|
@@ -296,6 +312,9 @@ export interface FormActionsProps extends Omit<ComponentPropsWithoutRef<"div">,
|
|
|
296
312
|
* `form.submitShortcut` label), dimmed. Hidden on a touch-only device, which has no
|
|
297
313
|
* keyboard to press it on. Default `false`. */
|
|
298
314
|
submitShortcutHint?: boolean;
|
|
315
|
+
/** When the buttons stack full width — see {@link FormActionsStack}. Default `auto`:
|
|
316
|
+
* on the phone layout at Large and Extra large. */
|
|
317
|
+
stack?: FormActionsStack;
|
|
299
318
|
/** Extra actions, placed before Cancel. */
|
|
300
319
|
children?: ReactNode;
|
|
301
320
|
}
|
|
@@ -360,11 +379,18 @@ export function FormActions({
|
|
|
360
379
|
form,
|
|
361
380
|
submitShortcut,
|
|
362
381
|
submitShortcutHint = false,
|
|
382
|
+
stack = "auto",
|
|
363
383
|
children,
|
|
364
384
|
className,
|
|
365
385
|
style,
|
|
366
386
|
...rest
|
|
367
387
|
}: FormActionsProps) {
|
|
388
|
+
const phone = usePhoneLayout();
|
|
389
|
+
const large = useLargeText();
|
|
390
|
+
const stacked = stack !== "never" && phone && (stack === "phone" || large);
|
|
391
|
+
// Stacked, a button fills its line — also inside the reason line's wrapper, which the
|
|
392
|
+
// column stretches but which keeps its control at the control's own width.
|
|
393
|
+
const full = stacked ? "w-full" : undefined;
|
|
368
394
|
const labels = useKitLabels("form", DEFAULT_FORM_ACTIONS_LABELS);
|
|
369
395
|
const lock = useWriteLock();
|
|
370
396
|
const rootRef = useRef<HTMLDivElement>(null);
|
|
@@ -430,6 +456,7 @@ export function FormActions({
|
|
|
430
456
|
disabled={destructive.disabled}
|
|
431
457
|
disabledReason={destructive.disabledReason}
|
|
432
458
|
commit={commit}
|
|
459
|
+
className={full}
|
|
433
460
|
>
|
|
434
461
|
{destructive.label}
|
|
435
462
|
</Button>
|
|
@@ -467,18 +494,27 @@ export function FormActions({
|
|
|
467
494
|
}
|
|
468
495
|
: style
|
|
469
496
|
}
|
|
470
|
-
|
|
497
|
+
data-stacked={stacked || undefined}
|
|
498
|
+
className={cn(
|
|
499
|
+
stacked ? "flex flex-col items-stretch gap-2" : cn("flex flex-wrap items-center gap-2", ALIGN_CLASS[justify]),
|
|
500
|
+
PLACEMENT_CLASS[placement],
|
|
501
|
+
className,
|
|
502
|
+
)}
|
|
471
503
|
>
|
|
472
504
|
{(hasDestructive || hasStart) && (
|
|
473
|
-
<div
|
|
505
|
+
<div
|
|
506
|
+
className={
|
|
507
|
+
stacked ? "flex min-w-0 flex-col items-stretch gap-2" : "me-auto flex min-w-0 flex-wrap items-center gap-2"
|
|
508
|
+
}
|
|
509
|
+
>
|
|
474
510
|
{destructiveNode}
|
|
475
511
|
{hasStart && startSlot}
|
|
476
512
|
</div>
|
|
477
513
|
)}
|
|
478
|
-
<div className="flex flex-wrap items-center gap-2">
|
|
514
|
+
<div className={stacked ? "flex flex-col items-stretch gap-2" : "flex flex-wrap items-center gap-2"}>
|
|
479
515
|
{children}
|
|
480
516
|
{onCancel && (
|
|
481
|
-
<Button type="button" variant={cancelVariant} size={size} onClick={onCancel}>
|
|
517
|
+
<Button type="button" variant={cancelVariant} size={size} onClick={onCancel} className={full}>
|
|
482
518
|
{cancelLabel ?? labels.cancel}
|
|
483
519
|
</Button>
|
|
484
520
|
)}
|
|
@@ -502,6 +538,7 @@ export function FormActions({
|
|
|
502
538
|
// spinner would say it had not.
|
|
503
539
|
commit={commit && !pending}
|
|
504
540
|
aria-busy={pending || undefined}
|
|
541
|
+
className={cn(submitProps?.className, full)}
|
|
505
542
|
>
|
|
506
543
|
{pending ? (
|
|
507
544
|
<Spinner label={null} className={glyphClass} />
|
|
@@ -10,6 +10,17 @@ import { useOverlayHistory } from "../hooks/use-overlay-history";
|
|
|
10
10
|
import { useCloseTransition } from "../hooks/use-close-transition";
|
|
11
11
|
import { useFocusTrap } from "../hooks/use-focus-trap";
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* The padding around the dialog's scrolling body, as a CSS length (0.32,
|
|
15
|
+
* docs/text-size-harmonization.md §10.11). Exported because a caller's sticky footer has
|
|
16
|
+
* to reach across it: Chrome resolves a sticky offset against the scrollport's CONTENT
|
|
17
|
+
* box, so a pinned row sits this far short of the panel's edge unless it cancels it
|
|
18
|
+
* (keksdose's editor footer). In rem, so it grows with the text size — keksdose's px
|
|
19
|
+
* copy (`SCROLLER_GUTTER_PX = 12`) was 3–6 px off at 125/150 %. Use it in `calc()`:
|
|
20
|
+
* `bottom: calc(${inset}px - ${DIALOG_GUTTER})`.
|
|
21
|
+
*/
|
|
22
|
+
export const DIALOG_GUTTER = "0.75rem";
|
|
23
|
+
|
|
13
24
|
/**
|
|
14
25
|
* Named and exported, because `ComponentProps<typeof FullBleedDialog>` was the only way
|
|
15
26
|
* to say "the props of this" and five call sites across keksdose and kastlan had already
|
|
@@ -246,12 +257,15 @@ export function FullBleedDialog({
|
|
|
246
257
|
<X className="size-5" />
|
|
247
258
|
</button>
|
|
248
259
|
</div>
|
|
249
|
-
{/* px-3, not px-4: every pixel of
|
|
250
|
-
on a phone (feedback #32). The
|
|
251
|
-
header stays put and the page
|
|
260
|
+
{/* DIALOG_GUTTER (0.75rem, the px-3 py-3 it was), not px-4: every pixel of
|
|
261
|
+
chrome here is width the form fields lose on a phone (feedback #32). The
|
|
262
|
+
body is the only thing that scrolls, so the header stays put and the page
|
|
263
|
+
underneath cannot move at all. */}
|
|
252
264
|
{/* `min-h-0` so it is the BODY that gives way to a footer, not the footer that
|
|
253
265
|
is pushed off the bottom edge. */}
|
|
254
|
-
<div className="min-h-0 flex-1 overflow-y-auto overscroll-contain
|
|
266
|
+
<div className="min-h-0 flex-1 overflow-y-auto overscroll-contain" style={{ padding: DIALOG_GUTTER }}>
|
|
267
|
+
{children}
|
|
268
|
+
</div>
|
|
255
269
|
{footer !== undefined && footer !== null && footer !== false && (
|
|
256
270
|
<div
|
|
257
271
|
data-full-bleed-footer=""
|
|
@@ -139,7 +139,7 @@ export function ImageGrid({
|
|
|
139
139
|
onClick={() => (onOpen ? onOpen(i) : setOpenIndex(i))}
|
|
140
140
|
className={cn(
|
|
141
141
|
"block w-full overflow-hidden rounded-md border border-[var(--border)] bg-[var(--bg-hover)]",
|
|
142
|
-
"focus-visible:outline-
|
|
142
|
+
"focus-visible:outline-[length:var(--focus-ring-width)] focus-visible:outline-offset-2 focus-visible:outline-[var(--brand)]",
|
|
143
143
|
ASPECT_CLASS[aspect],
|
|
144
144
|
)}
|
|
145
145
|
>
|