@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
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { currencyMinorDigits, formatMoney } from "../lib/format";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Money and periods of the plan catalogue (docs/billing-harmonization.md §3.1, §4, §12.17).
|
|
5
|
+
*
|
|
6
|
+
* Money crosses the wire as INTEGER MINOR UNITS plus an ISO currency, never as a float
|
|
7
|
+
* (§4): 4900 CHF is CHF 49.00. The kit turns it into the reader's notation with
|
|
8
|
+
* `formatMoney`, so no app divides by 100 by hand.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** A billing period: the provider charges per month or per year. */
|
|
12
|
+
export type BillingInterval = "month" | "year";
|
|
13
|
+
|
|
14
|
+
/** The two currencies every app sells in (§2.6). */
|
|
15
|
+
export type BillingCurrency = "CHF" | "EUR";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The periods in the order the picker offers them — YEARLY FIRST (§12.17): a Merchant of
|
|
19
|
+
* Record takes about 5 % + 0.50 per transaction, so a small monthly price loses a fifth
|
|
20
|
+
* of itself (CHF 3 a month loses about 22 %). The page leads with the yearly price.
|
|
21
|
+
*/
|
|
22
|
+
export const BILLING_INTERVALS: readonly BillingInterval[] = Object.freeze(["year", "month"]);
|
|
23
|
+
|
|
24
|
+
/** One currency's prices, in minor units, per period. A period left out is not offered. */
|
|
25
|
+
export type PlanIntervalPrices = Partial<Record<BillingInterval, number>>;
|
|
26
|
+
|
|
27
|
+
/** A plan's prices as server-kit's `PlanSpec.prices` sends them: currency → period →
|
|
28
|
+
* minor units, GROSS (§12.17). */
|
|
29
|
+
export type PlanPrices = Partial<Record<BillingCurrency, PlanIntervalPrices>>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* What one plan costs in one currency and period:
|
|
33
|
+
* - `price` — a gross amount in minor units;
|
|
34
|
+
* - `free` — a plan with no prices at all (keksdose's free plan), or a price of 0;
|
|
35
|
+
* - `not-offered` — a plan with prices, but none for this currency and period.
|
|
36
|
+
*/
|
|
37
|
+
export type PlanPriceAnswer =
|
|
38
|
+
| { kind: "price"; minor: number }
|
|
39
|
+
| { kind: "free" }
|
|
40
|
+
| { kind: "not-offered" };
|
|
41
|
+
|
|
42
|
+
/** Whether a price table holds any figure at all. */
|
|
43
|
+
function hasAnyPrice(prices: PlanPrices | null | undefined): boolean {
|
|
44
|
+
if (!prices) return false;
|
|
45
|
+
return Object.values(prices).some(
|
|
46
|
+
(byInterval) => byInterval && Object.values(byInterval).some((v) => typeof v === "number"),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** What `prices` says for `currency` and `interval` — see {@link PlanPriceAnswer}. */
|
|
51
|
+
export function planPrice(
|
|
52
|
+
prices: PlanPrices | null | undefined,
|
|
53
|
+
currency: BillingCurrency,
|
|
54
|
+
interval: BillingInterval,
|
|
55
|
+
): PlanPriceAnswer {
|
|
56
|
+
const minor = prices?.[currency]?.[interval];
|
|
57
|
+
if (typeof minor === "number" && Number.isFinite(minor)) {
|
|
58
|
+
return minor === 0 ? { kind: "free" } : { kind: "price", minor };
|
|
59
|
+
}
|
|
60
|
+
return hasAnyPrice(prices) ? { kind: "not-offered" } : { kind: "free" };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Minor units as the amount: 4900 CHF → 49, 1250 EUR → 12.5. The currency's minor unit
|
|
64
|
+
* comes from `Intl` (CHF and EUR have 2); a code `Intl` cannot read counts as 2. */
|
|
65
|
+
export function minorToMajor(minor: number, currency: string): number {
|
|
66
|
+
const digits = currencyMinorDigits(currency) ?? 2;
|
|
67
|
+
return minor / 10 ** digits;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A price in minor units, in the reader's notation: "CHF 49", "CHF 4.90", "49 €",
|
|
72
|
+
* "4,90 €". A whole amount drops its decimals — a price list reads "CHF 49" — and any
|
|
73
|
+
* other keeps all of them ("CHF 4.90", never "CHF 4.9").
|
|
74
|
+
*/
|
|
75
|
+
export function formatPlanPrice(minor: number, currency: string, options: { locale?: string } = {}): string {
|
|
76
|
+
const digits = currencyMinorDigits(currency) ?? 2;
|
|
77
|
+
const whole = Number.isInteger(minor) && minor % 10 ** digits === 0;
|
|
78
|
+
return formatMoney(minorToMajor(minor, currency), currency, {
|
|
79
|
+
locale: options.locale,
|
|
80
|
+
digits: whole ? 0 : digits,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The currency a payer starts with when the app stores none (§12.18): francs where the
|
|
86
|
+
* locale's region is Switzerland or Liechtenstein, euros everywhere else — "de-CH" and
|
|
87
|
+
* "fr-CH" CHF, "de" (Germany, once `Intl` fills the region in) and "it" EUR.
|
|
88
|
+
*
|
|
89
|
+
* Only the fallback: an account's stored currency comes first (keksdose's
|
|
90
|
+
* `reporting_currency` — a de-CH speaker living in Germany pays in euros), and the payer
|
|
91
|
+
* may switch in the picker either way; checkout takes the one they leave it on (§4).
|
|
92
|
+
*/
|
|
93
|
+
export function billingCurrencyFor(locale?: string): BillingCurrency {
|
|
94
|
+
if (!locale) return "EUR";
|
|
95
|
+
try {
|
|
96
|
+
const region = new Intl.Locale(locale).maximize().region;
|
|
97
|
+
return region === "CH" || region === "LI" ? "CHF" : "EUR";
|
|
98
|
+
} catch {
|
|
99
|
+
return "EUR";
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef } from "react";
|
|
2
|
+
|
|
3
|
+
import type { LabelOverride } from "../i18n/kit-labels";
|
|
4
|
+
import { cn } from "../lib/cn";
|
|
5
|
+
import { Button } from "../components/ui";
|
|
6
|
+
import { useBillingLabels } from "./billing-labels";
|
|
7
|
+
import type { BillingLabels } from "./billing-labels";
|
|
8
|
+
|
|
9
|
+
export interface SubscriptionActionsProps extends Omit<ComponentPropsWithoutRef<"div">, "children"> {
|
|
10
|
+
/** "Payment and invoices", as a link — or {@link onManage}. Without either, none. */
|
|
11
|
+
manageHref?: string;
|
|
12
|
+
/** "Payment and invoices", as the app's call: `POST /billing/portal`, then off to its
|
|
13
|
+
* `url` (§4). The kit sends no request. */
|
|
14
|
+
onManage?: () => void;
|
|
15
|
+
/** "Cancel subscription", as a link — or {@link onCancel}. Without either, none. */
|
|
16
|
+
cancelHref?: string;
|
|
17
|
+
/** "Cancel subscription", as the app's call — usually the portal again, where the
|
|
18
|
+
* provider's cancel and withdrawal functions are (§12.26). */
|
|
19
|
+
onCancel?: () => void;
|
|
20
|
+
/** Which of the two is under way: its spinner, no second press. */
|
|
21
|
+
pending?: "manage" | "cancel" | null;
|
|
22
|
+
/** Prop > `<UiKitProvider labels={{ billing }}>` > English. */
|
|
23
|
+
labels?: LabelOverride<BillingLabels>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The two ways to the provider's hosted portal on the subscription page
|
|
28
|
+
* (docs/billing-harmonization.md §2.8, §7, §12.26): "Payment and invoices" — the payment
|
|
29
|
+
* method and the invoices live there, never in the app — and a VISIBLE "Cancel
|
|
30
|
+
* subscription". Consumer law wants the second in plain sight: Germany's cancellation
|
|
31
|
+
* button (§312k BGB) and the EU withdrawal function (Directive (EU) 2023/2673, from
|
|
32
|
+
* 19 June 2026) are in the portal, and the app's page must not hide the way there behind
|
|
33
|
+
* "manage".
|
|
34
|
+
*
|
|
35
|
+
* Neither takes the write lock: a read-only payer must be able to pay, leave or cancel
|
|
36
|
+
* (§3.3).
|
|
37
|
+
*/
|
|
38
|
+
export function SubscriptionActions({
|
|
39
|
+
manageHref,
|
|
40
|
+
onManage,
|
|
41
|
+
cancelHref,
|
|
42
|
+
onCancel,
|
|
43
|
+
pending,
|
|
44
|
+
labels: labelsProp,
|
|
45
|
+
className,
|
|
46
|
+
...rest
|
|
47
|
+
}: SubscriptionActionsProps) {
|
|
48
|
+
const labels = useBillingLabels(labelsProp);
|
|
49
|
+
const manage =
|
|
50
|
+
manageHref !== undefined ? (
|
|
51
|
+
<Button href={manageHref} variant="secondary">
|
|
52
|
+
{labels.manage}
|
|
53
|
+
</Button>
|
|
54
|
+
) : onManage !== undefined ? (
|
|
55
|
+
<Button type="button" variant="secondary" onClick={onManage} pending={pending === "manage"}>
|
|
56
|
+
{labels.manage}
|
|
57
|
+
</Button>
|
|
58
|
+
) : null;
|
|
59
|
+
const cancel =
|
|
60
|
+
cancelHref !== undefined ? (
|
|
61
|
+
<Button href={cancelHref} variant="link" tone="danger">
|
|
62
|
+
{labels.cancel}
|
|
63
|
+
</Button>
|
|
64
|
+
) : onCancel !== undefined ? (
|
|
65
|
+
<Button type="button" variant="link" tone="danger" onClick={onCancel} pending={pending === "cancel"}>
|
|
66
|
+
{labels.cancel}
|
|
67
|
+
</Button>
|
|
68
|
+
) : null;
|
|
69
|
+
if (!manage && !cancel) return null;
|
|
70
|
+
return (
|
|
71
|
+
<div {...rest} className={cn("flex flex-wrap items-center gap-x-4 gap-y-2", className)}>
|
|
72
|
+
{manage}
|
|
73
|
+
{cancel}
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
import type { LabelOverride } from "../i18n/kit-labels";
|
|
4
|
+
import { Chip } from "../components/chip";
|
|
5
|
+
import type { ChipShape, ChipSize, ChipTone, ChipVariant } from "../components/chip";
|
|
6
|
+
import { useBillingLabels } from "./billing-labels";
|
|
7
|
+
import type { BillingLabels, SubscriptionStatus } from "./billing-labels";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The tone of each status (docs/billing-harmonization.md §3.2, §3.3). The tone follows
|
|
11
|
+
* the STANDING, so a roster reads at a glance who can write:
|
|
12
|
+
*
|
|
13
|
+
* - `active` green: paid, in good standing;
|
|
14
|
+
* - `trialing` blue (info): in good standing until `trial_ends_at`, nothing wrong;
|
|
15
|
+
* - `past_due` amber: a payment failed, still in good standing while the provider retries;
|
|
16
|
+
* - `expired` red: out of good standing — read-only until a plan is chosen;
|
|
17
|
+
* - `canceled` grey: the payer's own choice, nothing to warn about;
|
|
18
|
+
* - `comped` purple, a hue rather than a tone: free by grant — neither paid nor in trouble,
|
|
19
|
+
* only different from both.
|
|
20
|
+
*/
|
|
21
|
+
export const SUBSCRIPTION_STATUS_TONES: Readonly<Record<SubscriptionStatus, ChipTone>> = Object.freeze({
|
|
22
|
+
trialing: "info",
|
|
23
|
+
active: "success",
|
|
24
|
+
past_due: "warning",
|
|
25
|
+
canceled: "neutral",
|
|
26
|
+
expired: "danger",
|
|
27
|
+
comped: "purple",
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export interface SubscriptionStatusChipProps {
|
|
31
|
+
/**
|
|
32
|
+
* The row's `status` as the API sends it (§3.2). A value the kit does not know yet is
|
|
33
|
+
* shown as itself, in `neutral` — an unknown status is still a fact an operator should
|
|
34
|
+
* see. `null` / `undefined` renders nothing.
|
|
35
|
+
*/
|
|
36
|
+
status: SubscriptionStatus | (string & {}) | null | undefined;
|
|
37
|
+
/** Over {@link SUBSCRIPTION_STATUS_TONES}. */
|
|
38
|
+
tone?: ChipTone;
|
|
39
|
+
/** Over the status's word, for an app whose word is its own. */
|
|
40
|
+
children?: ReactNode;
|
|
41
|
+
/** Default `sm` (a roster's `extra` column, §6). */
|
|
42
|
+
size?: ChipSize;
|
|
43
|
+
/** Default `soft`. */
|
|
44
|
+
variant?: ChipVariant;
|
|
45
|
+
/** Default `square`, the status tag of `AccountStateChip`. */
|
|
46
|
+
shape?: ChipShape;
|
|
47
|
+
/** Default true, as `AccountStateChip`. */
|
|
48
|
+
caps?: boolean;
|
|
49
|
+
className?: string;
|
|
50
|
+
/** Prop > `<UiKitProvider labels={{ billing: { status } }}>` > English. */
|
|
51
|
+
labels?: LabelOverride<BillingLabels>;
|
|
52
|
+
[key: `data-${string}`]: string | number | boolean | undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Own keys only: `"toString" in {}` is true.
|
|
56
|
+
const isKnown = (value: string): value is SubscriptionStatus =>
|
|
57
|
+
Object.prototype.hasOwnProperty.call(SUBSCRIPTION_STATUS_TONES, value);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A subscription's status as a chip, in the kit's words and tones (§6: the operator's
|
|
61
|
+
* roster shows the plan and the standing; §7: the subscription page). ALWAYS A WORD, never
|
|
62
|
+
* colour alone: "Trial", "Active", "Payment overdue", "Cancelled", "Expired",
|
|
63
|
+
* "Complimentary" — the tone repeats what the word says. Carries `data-status` with the
|
|
64
|
+
* key, for a test or a style hook.
|
|
65
|
+
*/
|
|
66
|
+
export function SubscriptionStatusChip({
|
|
67
|
+
status,
|
|
68
|
+
tone,
|
|
69
|
+
children,
|
|
70
|
+
size = "sm",
|
|
71
|
+
variant,
|
|
72
|
+
shape = "square",
|
|
73
|
+
caps = true,
|
|
74
|
+
className,
|
|
75
|
+
labels: labelsProp,
|
|
76
|
+
...rest
|
|
77
|
+
}: SubscriptionStatusChipProps) {
|
|
78
|
+
const labels = useBillingLabels(labelsProp);
|
|
79
|
+
if (status === null || status === undefined || status === "") return null;
|
|
80
|
+
const known = isKnown(status);
|
|
81
|
+
return (
|
|
82
|
+
<Chip
|
|
83
|
+
{...rest}
|
|
84
|
+
data-status={status}
|
|
85
|
+
tone={tone ?? (known ? SUBSCRIPTION_STATUS_TONES[status] : "neutral")}
|
|
86
|
+
size={size}
|
|
87
|
+
variant={variant}
|
|
88
|
+
shape={shape}
|
|
89
|
+
caps={caps}
|
|
90
|
+
className={className}
|
|
91
|
+
>
|
|
92
|
+
{children ?? (known ? labels.status[status] : status)}
|
|
93
|
+
</Chip>
|
|
94
|
+
);
|
|
95
|
+
}
|
package/src/chart.ts
CHANGED
|
@@ -16,6 +16,8 @@ export * from "./components/treemap";
|
|
|
16
16
|
// lenkbank's zoomable series chart, its synced x-zoom, the toggle legend and the
|
|
17
17
|
// mirrored-pair axis geometry — moved here so the apps derive them from the package.
|
|
18
18
|
export * from "./components/series-chart";
|
|
19
|
+
// 0.32.1 (keksdose's 0.32 report): the height every chart takes, for an app's wrappers.
|
|
20
|
+
export type { ChartHeight } from "./components/chart-height";
|
|
19
21
|
export * from "./components/chart-zoom";
|
|
20
22
|
export * from "./components/toggle-legend";
|
|
21
23
|
export * from "./components/facing-pair";
|
|
@@ -7,7 +7,6 @@ import { useKitDateFormatter, useKitLabels, useKitLocale } from "../i18n/kit-lab
|
|
|
7
7
|
import { toLocalIso } from "../lib/dates";
|
|
8
8
|
import { Chip } from "./chip";
|
|
9
9
|
import type { ChipShape, ChipSize, ChipTone, ChipVariant } from "./chip";
|
|
10
|
-
import { Tooltip } from "./tooltip";
|
|
11
10
|
import type { DataTableColumn } from "./data-table";
|
|
12
11
|
|
|
13
12
|
/**
|
|
@@ -255,10 +254,18 @@ export interface DateMarkProps {
|
|
|
255
254
|
/**
|
|
256
255
|
* `"date"` (default): the date in `dateStyle` — "Created". `"relative"`: how long
|
|
257
256
|
* ago — "Last login", where the question is "recently?" — with the full date and
|
|
258
|
-
* time
|
|
257
|
+
* time beside it (keksdose's last-seen column; see `absolute`).
|
|
259
258
|
*/
|
|
260
259
|
display?: "date" | "relative";
|
|
261
|
-
/**
|
|
260
|
+
/**
|
|
261
|
+
* Where a `"relative"` mark puts the exact date and time (0.32,
|
|
262
|
+
* docs/text-size-harmonization.md §4: "relative dates show the absolute one beside
|
|
263
|
+
* them", at every size — a touch screen never opens the tooltip it used to live in):
|
|
264
|
+
* `"below"` (default), a muted second line under the words, so a table column keeps
|
|
265
|
+
* its width; `"inline"`, after them on the same line, for a sentence or a wide cell.
|
|
266
|
+
*/
|
|
267
|
+
absolute?: "below" | "inline";
|
|
268
|
+
/** Default `medium`. Under `"relative"`, the style of the exact date beside it (default
|
|
262
269
|
* `dateTime`) and of the date `relative.absoluteAfterDays` switches to. Given, it wins
|
|
263
270
|
* over the provider's `formatDate`. */
|
|
264
271
|
dateStyle?: FormatDateStyle | Intl.DateTimeFormatOptions;
|
|
@@ -288,6 +295,7 @@ export function DateMark({
|
|
|
288
295
|
display = "date",
|
|
289
296
|
dateStyle,
|
|
290
297
|
relative,
|
|
298
|
+
absolute = "below",
|
|
291
299
|
empty = EMPTY_FORMATTED_VALUE,
|
|
292
300
|
locale: localeProp,
|
|
293
301
|
className,
|
|
@@ -309,14 +317,32 @@ export function DateMark({
|
|
|
309
317
|
);
|
|
310
318
|
}
|
|
311
319
|
const text = formatRelativeTime(date, { ...relative, locale, absoluteStyle: dateStyle ?? "medium" });
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
320
|
+
const exact = formatDate(date, dateStyle ?? "dateTime", { locale });
|
|
321
|
+
// Past `absoluteAfterDays` the relative words already ARE the date; then the exact
|
|
322
|
+
// line alone, rather than the same day twice.
|
|
323
|
+
const sameDay = text === formatDate(date, dateStyle ?? "medium", { locale });
|
|
324
|
+
const iso = date.toISOString();
|
|
325
|
+
if (sameDay) {
|
|
326
|
+
return (
|
|
327
|
+
<time dateTime={iso} className={cls}>
|
|
328
|
+
{exact}
|
|
318
329
|
</time>
|
|
319
|
-
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
// The exact date and time in the layout, never only in a tooltip (§4). Still no tab
|
|
333
|
+
// stop: a roster of fifty rows would be fifty more of them.
|
|
334
|
+
return (
|
|
335
|
+
<time
|
|
336
|
+
dateTime={iso}
|
|
337
|
+
data-slot="date-mark"
|
|
338
|
+
className={cn(absolute === "below" ? "inline-flex flex-col leading-tight" : "inline", className)}
|
|
339
|
+
>
|
|
340
|
+
<span className="whitespace-nowrap tabular-nums">{text}</span>
|
|
341
|
+
{absolute === "inline" && " · "}
|
|
342
|
+
<span className={cn("whitespace-nowrap tabular-nums text-[var(--text-muted)]", absolute === "below" && "text-xs")}>
|
|
343
|
+
{exact}
|
|
344
|
+
</span>
|
|
345
|
+
</time>
|
|
320
346
|
);
|
|
321
347
|
}
|
|
322
348
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ComponentPropsWithoutRef, MouseEvent, ReactNode } from "react";
|
|
2
2
|
import { AlertTriangle, CheckCircle2, ChevronRight, Info, X } from "lucide-react";
|
|
3
3
|
import { cn } from "../lib/cn";
|
|
4
|
+
import { FOCUS_RING } from "./focus-ring";
|
|
4
5
|
import { DEFAULT_COMMON_LABELS, useKitLabels } from "../i18n/kit-labels";
|
|
5
6
|
|
|
6
7
|
/** `info` (0.8.0) is the sky family, for news that is neither good nor bad: keksdose's
|
|
@@ -60,16 +61,21 @@ export function toneFrameClass(tone: AlertTone): string {
|
|
|
60
61
|
|
|
61
62
|
/** Single source for the warning-callout frame (feedback #277): the tone's border
|
|
62
63
|
* and surface plus this component's own radius and padding, the latter
|
|
63
|
-
* compensating the 2px colored border so toggling tones never shifts layout.
|
|
64
|
+
* compensating the 2px colored border so toggling tones never shifts layout.
|
|
65
|
+
*
|
|
66
|
+
* The compensation is `calc(<the neutral padding in rem> - 1px)`, not a px figure
|
|
67
|
+
* (0.32, docs/text-size-harmonization.md §3.2): the padding grows with the text size,
|
|
68
|
+
* the 1px it gives back to the border does not — an 11 px padding stopped matching `p-3`
|
|
69
|
+
* at 125 %, and toggling the tone shifted the layout again. */
|
|
64
70
|
export function alertFrameClass(tone: AlertTone, size: AlertSize = "md"): string {
|
|
65
71
|
const box =
|
|
66
72
|
size === "sm"
|
|
67
73
|
? tone === "neutral"
|
|
68
74
|
? "rounded-md px-2.5 py-1.5"
|
|
69
|
-
: "rounded-md px-[
|
|
75
|
+
: "rounded-md px-[calc(0.625rem-1px)] py-[calc(0.375rem-1px)]"
|
|
70
76
|
: tone === "neutral"
|
|
71
77
|
? "rounded-md p-3"
|
|
72
|
-
: "rounded-md p-[
|
|
78
|
+
: "rounded-md p-[calc(0.75rem-1px)]";
|
|
73
79
|
return `${box} ${TONE_FRAME[tone]}`;
|
|
74
80
|
}
|
|
75
81
|
|
|
@@ -293,8 +299,7 @@ export function AlertBanner({
|
|
|
293
299
|
strip ? stripFrameClass(tone, size) : alertFrameClass(tone, size),
|
|
294
300
|
elevated && cn(ELEVATED, TONE_ELEVATED[tone]),
|
|
295
301
|
);
|
|
296
|
-
const focusRing =
|
|
297
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand)] focus-visible:ring-offset-1 focus-visible:ring-offset-[var(--bg-surface)]";
|
|
302
|
+
const focusRing = cn(FOCUS_RING, "focus-visible:ring-offset-1 focus-visible:ring-offset-[var(--bg-surface)]");
|
|
298
303
|
|
|
299
304
|
const content = (
|
|
300
305
|
<>
|
|
@@ -331,11 +336,15 @@ export function AlertBanner({
|
|
|
331
336
|
) : null;
|
|
332
337
|
|
|
333
338
|
// `relative z-10` so it stays clickable over a whole-row banner's stretched target.
|
|
339
|
+
// `max-w-full flex-wrap`: on a line of its own, two actions side by side ran 57 px
|
|
340
|
+
// past a 360 px phone at Extra large (the demo strip's "Request access" and "Sign in",
|
|
341
|
+
// 0.32.1); held to the line, they wrap there instead. Where they fit in one row,
|
|
342
|
+
// nothing changes.
|
|
334
343
|
const trailing =
|
|
335
344
|
action !== undefined && action !== null ? (
|
|
336
345
|
<div
|
|
337
346
|
className={cn(
|
|
338
|
-
"relative z-10 flex shrink-0 items-center gap-2",
|
|
347
|
+
"relative z-10 flex max-w-full shrink-0 flex-wrap items-center gap-2",
|
|
339
348
|
!strip && !inlineRow && "self-center",
|
|
340
349
|
strip && "ms-auto",
|
|
341
350
|
// Last, on a line of its own, lined up with the message (past the glyph).
|
|
@@ -376,7 +385,7 @@ export function AlertBanner({
|
|
|
376
385
|
inlineRow || strip ? "items-center" : "items-start",
|
|
377
386
|
"outline-none after:absolute after:inset-0 after:content-['']",
|
|
378
387
|
strip ? "after:rounded-none" : "after:rounded-md",
|
|
379
|
-
"focus-visible:after:ring-
|
|
388
|
+
"focus-visible:after:ring-[length:var(--focus-ring-width)] focus-visible:after:ring-[var(--brand)]",
|
|
380
389
|
)
|
|
381
390
|
: cn(row, !inlineRow && "w-full", frame, TONE_TEXT[tone], hover, focusRing, className);
|
|
382
391
|
// The div's attributes are the row element's: an `id`, a test id or an
|
|
@@ -2,10 +2,10 @@ import { forwardRef, useCallback, useId, useMemo, useRef, useState } from "react
|
|
|
2
2
|
import { ChevronDown } from "lucide-react";
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
4
|
import { CURRENCIES, CurrencyFlag, currencyName, getCurrency } from "./currency-select";
|
|
5
|
-
import { FIELD_BASE, FIELD_DISPLAY, FIELD_INVALID, FLOATING_INPUT_CLASS, FloatingField
|
|
5
|
+
import { FIELD_BASE, FIELD_DISPLAY, FIELD_INVALID, FLOATING_INPUT_CLASS, FloatingField } from "./ui";
|
|
6
6
|
import { cn } from "../lib/cn";
|
|
7
7
|
import { currencyMinorDigits } from "../lib/format";
|
|
8
|
-
import {
|
|
8
|
+
import { usePhoneLayout } from "../hooks/use-breakpoint";
|
|
9
9
|
import { CalculatorButton, type CalculatorButtonLabels } from "./calculator";
|
|
10
10
|
import { NumberPadSheet, type NumberPadSheetLabels } from "./numpad-sheet";
|
|
11
11
|
import { DropdownPanel, DropdownSearchHeader, useDropdownSearch } from "./dropdown";
|
|
@@ -274,7 +274,7 @@ function settleAmount(text: string, digits: number | undefined, min?: number, ma
|
|
|
274
274
|
|
|
275
275
|
// The error line under a field — the type of `ui.tsx`'s (module-private) one, so an
|
|
276
276
|
// AmountInput's message is indistinguishable from an Input's.
|
|
277
|
-
const FIELD_ERROR_CLASS = "mt-1 text-
|
|
277
|
+
const FIELD_ERROR_CLASS = "mt-1 text-caption leading-tight text-[var(--danger)]";
|
|
278
278
|
|
|
279
279
|
// The consuming app's ONE money palette (`--money-expense` / `--money-income`),
|
|
280
280
|
// not a bespoke rose/emerald pairing: a figure being typed has to wear the same
|
|
@@ -332,7 +332,7 @@ export const AmountInput = forwardRef<HTMLInputElement, AmountInputProps>(
|
|
|
332
332
|
// On phones we suppress the OS keyboard (inputMode="none" below) and show our
|
|
333
333
|
// own calculator numpad, so the desktop popover trigger is hidden. The
|
|
334
334
|
// end padding keys off showCalc, so it tightens up automatically.
|
|
335
|
-
const isMobile =
|
|
335
|
+
const isMobile = usePhoneLayout();
|
|
336
336
|
const showCalc = calculator && !disabled && !isMobile;
|
|
337
337
|
const [focused, setFocused] = useState(false);
|
|
338
338
|
// On mobile, focusing the field opens the numpad bottom sheet in place of the
|
|
@@ -678,7 +678,7 @@ export const AmountInput = forwardRef<HTMLInputElement, AmountInputProps>(
|
|
|
678
678
|
{/* Outside the relative box, as NumberInput's caption is: the trailing
|
|
679
679
|
controls are `inset-y-1` in it and would stretch down over a second line. */}
|
|
680
680
|
{textHint && (
|
|
681
|
-
<p id={hintId} className="mt-1 text-
|
|
681
|
+
<p id={hintId} className="mt-1 text-caption leading-tight text-[var(--text-muted)]">
|
|
682
682
|
{hint}
|
|
683
683
|
</p>
|
|
684
684
|
)}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useKitLabels } from "../i18n/kit-labels";
|
|
2
|
+
import type { ContrastMode } from "../theme/contrast";
|
|
3
|
+
import type { TextSize } from "../theme/text-size";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The `appearance` namespace (0.32, docs/text-size-harmonization.md §6): the words of the
|
|
7
|
+
* two new settings in the core `appearance` group — `TextSizeSetting` and
|
|
8
|
+
* `ContrastSetting` — and of any quick switch an app builds from the same vocabulary (the
|
|
9
|
+
* showcase's top bar). Like every kit label: prop > `<UiKitProvider labels={{ appearance
|
|
10
|
+
* }}>` > English.
|
|
11
|
+
*/
|
|
12
|
+
export interface AppearanceLabels {
|
|
13
|
+
/** The text-size setting's name. */
|
|
14
|
+
textSize: string;
|
|
15
|
+
/** One line under it: what changes, so "Large" is not mistaken for zoom. */
|
|
16
|
+
textSizeHelp: string;
|
|
17
|
+
/** The three steps, in {@link TEXT_SIZES} order. */
|
|
18
|
+
textSizes: Record<TextSize, string>;
|
|
19
|
+
/** The contrast setting's name. */
|
|
20
|
+
contrast: string;
|
|
21
|
+
/** One line under it. */
|
|
22
|
+
contrastHelp: string;
|
|
23
|
+
/** The three choices, in {@link CONTRAST_MODES} order. */
|
|
24
|
+
contrastModes: Record<ContrastMode, string>;
|
|
25
|
+
/**
|
|
26
|
+
* The account could not keep the pick (`useAccountAppearance`'s `pickTextSize` /
|
|
27
|
+
* `pickContrast` rejected): this device keeps it, the account doesn't. For the app's
|
|
28
|
+
* toast or the line under the setting (0.32.1, keksdose's 0.32 report).
|
|
29
|
+
*/
|
|
30
|
+
saveFailed: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const DEFAULT_APPEARANCE_LABELS: AppearanceLabels = {
|
|
34
|
+
textSize: "Text size",
|
|
35
|
+
textSizeHelp: "Larger letters, and a layout that makes room for them.",
|
|
36
|
+
textSizes: { normal: "Normal", large: "Large", xlarge: "Extra large" },
|
|
37
|
+
contrast: "Contrast",
|
|
38
|
+
contrastHelp: "More contrast darkens quiet text and lines, and thickens focus frames. System follows this device.",
|
|
39
|
+
contrastModes: { system: "System", standard: "Standard", more: "More" },
|
|
40
|
+
saveFailed: "Couldn't save this to your account. It still applies on this device.",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** The `appearance` namespace, resolved — English, then the provider, then `labels`. For
|
|
44
|
+
* an app's catalogue entries and quick switches, without restating the defaults. */
|
|
45
|
+
export function useAppearanceLabels(labels?: Partial<AppearanceLabels>): AppearanceLabels {
|
|
46
|
+
return useKitLabels("appearance", DEFAULT_APPEARANCE_LABELS, labels);
|
|
47
|
+
}
|
|
@@ -500,7 +500,7 @@ function AutocompleteInner<V extends string | number = string>(
|
|
|
500
500
|
{startsGroup && (
|
|
501
501
|
<li
|
|
502
502
|
role="presentation"
|
|
503
|
-
className="px-3 pb-0.5 pt-2 text-
|
|
503
|
+
className="px-3 pb-0.5 pt-2 text-caption font-semibold uppercase tracking-wide text-[var(--text-muted)] first:pt-1"
|
|
504
504
|
>
|
|
505
505
|
{o.group}
|
|
506
506
|
</li>
|
|
@@ -546,7 +546,7 @@ function AutocompleteInner<V extends string | number = string>(
|
|
|
546
546
|
<span
|
|
547
547
|
className={cn(
|
|
548
548
|
"block truncate text-[var(--text-placeholder)]",
|
|
549
|
-
small ? "text-
|
|
549
|
+
small ? "text-caption" : "text-xs",
|
|
550
550
|
)}
|
|
551
551
|
>
|
|
552
552
|
{o.sublabel}
|
|
@@ -2,6 +2,7 @@ import { Fragment, useEffect, useRef, useState } from "react";
|
|
|
2
2
|
import type { ComponentPropsWithoutRef, ReactElement, ReactNode } from "react";
|
|
3
3
|
import { ChevronRight, MoreHorizontal } from "lucide-react";
|
|
4
4
|
import { cn } from "../lib/cn";
|
|
5
|
+
import { FOCUS_RING } from "./focus-ring";
|
|
5
6
|
import { useKitLabels, useKitLink } from "../i18n/kit-labels";
|
|
6
7
|
import { pickLinkRenderer, RenderedKitLink } from "./text-link";
|
|
7
8
|
|
|
@@ -106,8 +107,7 @@ export function Breadcrumbs({
|
|
|
106
107
|
{separator ?? <ChevronRight className="size-3.5 rtl:-scale-x-100" />}
|
|
107
108
|
</span>
|
|
108
109
|
);
|
|
109
|
-
const linkClass =
|
|
110
|
-
"block max-w-[14rem] truncate rounded-sm hover:text-[var(--text-primary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand)]";
|
|
110
|
+
const linkClass = cn("block max-w-[14rem] truncate rounded-sm hover:text-[var(--text-primary)]", FOCUS_RING);
|
|
111
111
|
|
|
112
112
|
return (
|
|
113
113
|
<nav {...rest} aria-label={ariaLabel ?? labels.label} className={cn("min-w-0 text-sm", className)}>
|
|
@@ -150,7 +150,7 @@ export function Breadcrumbs({
|
|
|
150
150
|
}}
|
|
151
151
|
aria-label={labels.showAll}
|
|
152
152
|
aria-expanded={false}
|
|
153
|
-
className="flex items-center rounded-sm px-0.5 hover:text-[var(--text-primary)]
|
|
153
|
+
className={cn("flex items-center rounded-sm px-0.5 hover:text-[var(--text-primary)]", FOCUS_RING)}
|
|
154
154
|
>
|
|
155
155
|
<MoreHorizontal className="size-4" aria-hidden />
|
|
156
156
|
</button>
|
|
@@ -6,7 +6,7 @@ import { cn } from "../lib/cn";
|
|
|
6
6
|
import { horizontalStep } from "../lib/direction";
|
|
7
7
|
import { useKitLabels } from "../i18n/kit-labels";
|
|
8
8
|
import { useAnnounce } from "../hooks/use-announce";
|
|
9
|
-
import {
|
|
9
|
+
import { useBreakpoint } from "../hooks/use-breakpoint";
|
|
10
10
|
import { OVERLAY_EXIT_MS, prefersReducedMotion } from "../hooks/use-close-transition";
|
|
11
11
|
import { Button, IconButton } from "./ui";
|
|
12
12
|
|
|
@@ -38,8 +38,8 @@ export type BulkActionBarVariant = "floating" | "sticky" | "inline";
|
|
|
38
38
|
/**
|
|
39
39
|
* A variant per breakpoint, mobile first — `{ base: "floating", md: "sticky" }` is the
|
|
40
40
|
* phone's floating card below 768px and the desktop's sticky bar from there up. The
|
|
41
|
-
* breakpoints are
|
|
42
|
-
*
|
|
41
|
+
* breakpoints are the ones the kit's classes use (sm 640, md 768, lg 1024, xl 1280px
|
|
42
|
+
* at Normal text size; since 0.32 they move with the text size, as `md:` does). keksdose's payees selection bar (payees-selection-bar.tsx)
|
|
43
43
|
* computes exactly this with its own `useMediaQuery("(min-width: 768px)")`; every bar
|
|
44
44
|
* that is a card on a phone and a strip on a desktop would repeat it.
|
|
45
45
|
*
|
|
@@ -55,12 +55,9 @@ export interface ResponsiveBulkActionBarVariant {
|
|
|
55
55
|
xl?: BulkActionBarVariant;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
["md", "(min-width: 768px)"],
|
|
62
|
-
["sm", "(min-width: 640px)"],
|
|
63
|
-
] as const;
|
|
58
|
+
/** Widest first: the first that matches and names a value wins. Each is the class's own
|
|
59
|
+
* breakpoint at the text size in force (`useBreakpoint`), so `md` here is `md:` there. */
|
|
60
|
+
const BREAKPOINTS = ["xl", "lg", "md", "sm"] as const;
|
|
64
61
|
|
|
65
62
|
/** The variant in force: the widest breakpoint that matches AND names one, else
|
|
66
63
|
* `base`. The four queries are subscribed unconditionally — hooks cannot be skipped —
|
|
@@ -68,13 +65,13 @@ const BREAKPOINTS = [
|
|
|
68
65
|
* every query is false, so the bar renders its `base`, the phone's, first. */
|
|
69
66
|
function useResolvedVariant(variant: BulkActionBarVariant | ResponsiveBulkActionBarVariant): BulkActionBarVariant {
|
|
70
67
|
const matches = {
|
|
71
|
-
xl:
|
|
72
|
-
lg:
|
|
73
|
-
md:
|
|
74
|
-
sm:
|
|
68
|
+
xl: useBreakpoint("xl"),
|
|
69
|
+
lg: useBreakpoint("lg"),
|
|
70
|
+
md: useBreakpoint("md"),
|
|
71
|
+
sm: useBreakpoint("sm"),
|
|
75
72
|
};
|
|
76
73
|
if (typeof variant === "string") return variant;
|
|
77
|
-
for (const
|
|
74
|
+
for (const key of BREAKPOINTS) {
|
|
78
75
|
const v = variant[key];
|
|
79
76
|
if (matches[key] && v !== undefined) return v;
|
|
80
77
|
}
|
|
@@ -26,6 +26,26 @@ const JOINED_COMMON = cn(
|
|
|
26
26
|
"[&>*]:relative [&>*:focus-within]:z-10",
|
|
27
27
|
);
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* A joined row at Large and Extra large wraps rather than run past its container (0.32.1,
|
|
31
|
+
* the 360 px Extra-large sweep; docs/text-size-harmonization.md §4 "nothing
|
|
32
|
+
* overflows"): "Buttons | Chips | Feedback" was 329 px at 150 %, 67 px past a 360 px
|
|
33
|
+
* phone's card. A wrapped row cannot keep one frame with dividers between members — the
|
|
34
|
+
* second line's first member would carry a divider against the frame and no line would
|
|
35
|
+
* part the rows — so at Large the frame is drawn by the members: each its own 1px
|
|
36
|
+
* border, overlapping its neighbours by a pixel on both axes (the container's `ps-px
|
|
37
|
+
* pt-px` takes the overlap back at the edges). On one row that draws the same frame and
|
|
38
|
+
* dividers as Normal; wrapped, every line and every member is parted by one hairline,
|
|
39
|
+
* and the members share out each line (`grow`), so the lines make one block. A group
|
|
40
|
+
* that fits is only as wide as its members, so nothing grows there. A `large:` class,
|
|
41
|
+
* so Normal keeps the frame it has, and it costs no render.
|
|
42
|
+
*/
|
|
43
|
+
const JOINED_WRAP_AT_LARGE = cn(
|
|
44
|
+
"large:max-w-full large:flex-wrap large:border-0 large:ps-px large:pt-px",
|
|
45
|
+
"large:[&>*]:border large:[&>*]:-ms-px large:[&>*]:-mt-px",
|
|
46
|
+
"large:[&>*]:grow large:[&>*>button]:grow large:[&>*>a]:grow",
|
|
47
|
+
);
|
|
48
|
+
|
|
29
49
|
const JOINED: Record<"horizontal" | "vertical", string> = {
|
|
30
50
|
// Logical edges and corners throughout (`border-s`, `rounded-s-*`), so in RTL the
|
|
31
51
|
// first member sits on the right with the right-hand corners rounded — the physical
|
|
@@ -37,6 +57,7 @@ const JOINED: Record<"horizontal" | "vertical", string> = {
|
|
|
37
57
|
"[&>:first-child]:rounded-s-md [&>:last-child]:rounded-e-md",
|
|
38
58
|
"[&>:first-child>button]:rounded-s-md [&>:last-child>button]:rounded-e-md",
|
|
39
59
|
"[&>:first-child>a]:rounded-s-md [&>:last-child>a]:rounded-e-md",
|
|
60
|
+
JOINED_WRAP_AT_LARGE,
|
|
40
61
|
),
|
|
41
62
|
// The block axis is top-to-bottom in both reading directions, so top/bottom are
|
|
42
63
|
// already the logical edges here.
|