@eifi1/ui-kit 0.54.0 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -76
- package/dist/admin/plan-change.js +2 -2
- package/dist/admin/plan-change.js.map +1 -1
- package/dist/admin/user-roster.d.ts +6 -0
- package/dist/admin/user-roster.js +4 -0
- package/dist/admin/user-roster.js.map +1 -1
- package/dist/billing/billing-labels.d.ts +26 -0
- package/dist/billing/billing-labels.js +9 -0
- package/dist/billing/billing-labels.js.map +1 -1
- package/dist/billing/subscription-standing.d.ts +61 -0
- package/dist/billing/subscription-standing.js +51 -0
- package/dist/billing/subscription-standing.js.map +1 -0
- package/dist/billing/usage-meter.d.ts +52 -0
- package/dist/billing/usage-meter.js +52 -0
- package/dist/billing/usage-meter.js.map +1 -0
- package/dist/chart.d.ts +1 -0
- package/dist/chart.js +4 -0
- package/dist/chart.js.map +1 -1
- package/dist/components/alert-banner.js +2 -3
- package/dist/components/alert-banner.js.map +1 -1
- package/dist/components/amount-input.js +3 -15
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.js +2 -2
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/bulk-action-bar.js +2 -1
- package/dist/components/bulk-action-bar.js.map +1 -1
- package/dist/components/button.d.ts +35 -1
- package/dist/components/button.js +5 -9
- package/dist/components/button.js.map +1 -1
- package/dist/components/calendar-heatmap.js +2 -2
- package/dist/components/calendar-heatmap.js.map +1 -1
- package/dist/components/camera-button.d.ts +89 -0
- package/dist/components/camera-button.js +122 -0
- package/dist/components/camera-button.js.map +1 -0
- package/dist/components/camera-capture.d.ts +66 -0
- package/dist/components/camera-capture.js +190 -0
- package/dist/components/camera-capture.js.map +1 -0
- package/dist/components/camera-labels.d.ts +20 -0
- package/dist/components/camera-labels.js +15 -0
- package/dist/components/camera-labels.js.map +1 -0
- package/dist/components/chart-edge.d.ts +9 -0
- package/dist/components/chart-edge.js +14 -3
- package/dist/components/chart-edge.js.map +1 -1
- package/dist/components/chart-zoom-core.js +34 -29
- package/dist/components/chart-zoom-core.js.map +1 -1
- package/dist/components/checkbox-group.js +1 -1
- package/dist/components/checkbox-group.js.map +1 -1
- package/dist/components/combobox-core.js +3 -2
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.js +2 -2
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/consent-again-notice-labels.d.ts +25 -0
- package/dist/components/consent-again-notice-labels.js +15 -0
- package/dist/components/consent-again-notice-labels.js.map +1 -0
- package/dist/components/consent-again-notice.d.ts +85 -0
- package/dist/components/consent-again-notice.js +94 -0
- package/dist/components/consent-again-notice.js.map +1 -0
- package/dist/components/country-select.js +2 -7
- package/dist/components/country-select.js.map +1 -1
- package/dist/components/currency-select.js +2 -2
- package/dist/components/currency-select.js.map +1 -1
- package/dist/components/danger-confirm.js +2 -2
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/data-table-column-settings.js +2 -2
- package/dist/components/data-table-column-settings.js.map +1 -1
- package/dist/components/data-table-fit.js.map +1 -1
- package/dist/components/data-table-virtual.js +13 -3
- package/dist/components/data-table-virtual.js.map +1 -1
- package/dist/components/date-field.js +2 -2
- package/dist/components/date-field.js.map +1 -1
- package/dist/components/date-picker.js +2 -2
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/date-range-picker.js +2 -6
- package/dist/components/date-range-picker.js.map +1 -1
- package/dist/components/dialog-frame.d.ts +3 -1
- package/dist/components/dialog-frame.js.map +1 -1
- package/dist/components/dropdown.js +7 -3
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/entity-combobox.js +2 -2
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/field-parts.d.ts +108 -6
- package/dist/components/field-parts.js +59 -6
- package/dist/components/field-parts.js.map +1 -1
- package/dist/components/field-suggestion-labels.d.ts +2 -0
- package/dist/components/field-suggestion-labels.js +10 -0
- package/dist/components/field-suggestion-labels.js.map +1 -0
- package/dist/components/field.js +1 -1
- package/dist/components/field.js.map +1 -1
- package/dist/components/file-button.d.ts +1 -1
- package/dist/components/file-button.js.map +1 -1
- package/dist/components/floating-panel.d.ts +7 -6
- package/dist/components/floating-panel.js +3 -17
- package/dist/components/floating-panel.js.map +1 -1
- package/dist/components/form-actions.d.ts +3 -2
- package/dist/components/form-actions.js.map +1 -1
- package/dist/components/hover-menu.js +3 -2
- package/dist/components/hover-menu.js.map +1 -1
- package/dist/components/icon-button.d.ts +23 -5
- package/dist/components/icon-button.js +6 -8
- package/dist/components/icon-button.js.map +1 -1
- package/dist/components/inline-confirm.js +2 -1
- package/dist/components/inline-confirm.js.map +1 -1
- package/dist/components/inline-entity-combobox.js +2 -2
- package/dist/components/inline-entity-combobox.js.map +1 -1
- package/dist/components/input.js +2 -2
- package/dist/components/input.js.map +1 -1
- package/dist/components/jump-calendar.js +3 -3
- package/dist/components/jump-calendar.js.map +1 -1
- package/dist/components/legal.d.ts +13 -1
- package/dist/components/legal.js +12 -0
- package/dist/components/legal.js.map +1 -1
- package/dist/components/legended-series-chart.d.ts +80 -0
- package/dist/components/legended-series-chart.js +70 -0
- package/dist/components/legended-series-chart.js.map +1 -0
- package/dist/components/lightbox.js +2 -1
- package/dist/components/lightbox.js.map +1 -1
- package/dist/components/mini-calendar.js +13 -5
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/modal.d.ts +23 -2
- package/dist/components/modal.js +24 -6
- package/dist/components/modal.js.map +1 -1
- package/dist/components/month-picker.d.ts +1 -1
- package/dist/components/month-picker.js +6 -6
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.js +2 -2
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/multi-select.js +2 -6
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/number-input.js +2 -2
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/page-header-layout.d.ts +18 -0
- package/dist/components/page-header-layout.js +23 -0
- package/dist/components/page-header-layout.js.map +1 -0
- package/dist/components/page-header-skeleton.d.ts +41 -0
- package/dist/components/page-header-skeleton.js +52 -0
- package/dist/components/page-header-skeleton.js.map +1 -0
- package/dist/components/page-header.js +4 -17
- package/dist/components/page-header.js.map +1 -1
- package/dist/components/popover.js +7 -2
- package/dist/components/popover.js.map +1 -1
- package/dist/components/release-notes-labels.d.ts +16 -0
- package/dist/components/release-notes-labels.js +18 -0
- package/dist/components/release-notes-labels.js.map +1 -0
- package/dist/components/release-notes.d.ts +65 -0
- package/dist/components/release-notes.js +65 -0
- package/dist/components/release-notes.js.map +1 -0
- package/dist/components/select.js +2 -2
- package/dist/components/select.js.map +1 -1
- package/dist/components/series-chart-labels.d.ts +9 -0
- package/dist/components/series-chart-labels.js +3 -1
- package/dist/components/series-chart-labels.js.map +1 -1
- package/dist/components/series-chart.d.ts +5 -0
- package/dist/components/series-chart.js +89 -36
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/toggle-group.js +3 -2
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/treemap-layout.js.map +1 -1
- package/dist/components/treemap.d.ts +17 -15
- package/dist/components/treemap.js +167 -85
- package/dist/components/treemap.js.map +1 -1
- package/dist/eslint/index.js +1 -1
- package/dist/eslint/role-utilities.d.ts +2 -2
- package/dist/eslint/role-utilities.js.map +1 -1
- package/dist/feedback/feedback-inbox-page.d.ts +260 -0
- package/dist/feedback/feedback-inbox-page.js +207 -0
- package/dist/feedback/feedback-inbox-page.js.map +1 -0
- package/dist/feedback/feedback-vocabulary.js +2 -2
- package/dist/feedback/feedback-vocabulary.js.map +1 -1
- package/dist/feedback.d.ts +1 -0
- package/dist/feedback.js +6 -0
- package/dist/feedback.js.map +1 -1
- package/dist/hooks/use-debounce.d.ts +32 -5
- package/dist/hooks/use-debounce.js +6 -5
- package/dist/hooks/use-debounce.js.map +1 -1
- package/dist/hooks/use-file-picker.d.ts +3 -1
- package/dist/hooks/use-file-picker.js.map +1 -1
- package/dist/hooks/use-focus-trap.d.ts +19 -3
- package/dist/hooks/use-focus-trap.js +15 -5
- package/dist/hooks/use-focus-trap.js.map +1 -1
- package/dist/hooks/use-has-camera.d.ts +36 -0
- package/dist/hooks/use-has-camera.js +53 -0
- package/dist/hooks/use-has-camera.js.map +1 -0
- package/dist/hooks/use-hotkey.js +1 -10
- package/dist/hooks/use-hotkey.js.map +1 -1
- package/dist/hooks/use-overlay-history.d.ts +6 -1
- package/dist/hooks/use-overlay-history.js +10 -2
- package/dist/hooks/use-overlay-history.js.map +1 -1
- package/dist/i18n/defaults.js +11 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.js +75 -3
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +20 -0
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/en.js +92 -4
- package/dist/i18n/locales/en.js.map +3 -3
- package/dist/i18n/locales/es.js +71 -3
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.js +72 -2
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.js +74 -3
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.js +74 -3
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.js +71 -3
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.js +22 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +24 -5
- package/dist/index.js +35 -1
- package/dist/index.js.map +1 -1
- package/dist/landing/landing-labels.d.ts +8 -0
- package/dist/landing/landing-labels.js +2 -1
- package/dist/landing/landing-labels.js.map +1 -1
- package/dist/lib/changelog.d.ts +130 -0
- package/dist/lib/changelog.js +137 -0
- package/dist/lib/changelog.js.map +1 -0
- package/dist/lib/clipboard-minus.js +2 -2
- package/dist/lib/clipboard-minus.js.map +1 -1
- package/dist/lib/dates.d.ts +29 -3
- package/dist/lib/dates.js +41 -12
- package/dist/lib/dates.js.map +1 -1
- package/dist/lib/editable-content.d.ts +33 -0
- package/dist/lib/editable-content.js +15 -0
- package/dist/lib/editable-content.js.map +1 -0
- package/dist/lib/focus-left.d.ts +47 -1
- package/dist/lib/focus-left.js +11 -2
- package/dist/lib/focus-left.js.map +1 -1
- package/dist/lib/server-wake.d.ts +49 -9
- package/dist/lib/server-wake.js +25 -14
- package/dist/lib/server-wake.js.map +1 -1
- package/dist/lib/session-refresh.d.ts +53 -0
- package/dist/lib/session-refresh.js +27 -1
- package/dist/lib/session-refresh.js.map +1 -1
- package/dist/rhf/fields.js +3 -3
- package/dist/rhf/fields.js.map +1 -1
- package/dist/shell/app-shell.d.ts +25 -1
- package/dist/shell/app-shell.js +3 -1
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/dev-menu.d.ts +3 -0
- package/dist/shell/dev-menu.js +4 -2
- package/dist/shell/dev-menu.js.map +1 -1
- package/dist/shell/held-changes-banner-labels.d.ts +23 -0
- package/dist/shell/held-changes-banner-labels.js +14 -0
- package/dist/shell/held-changes-banner-labels.js.map +1 -0
- package/dist/shell/held-changes-banner.d.ts +75 -0
- package/dist/shell/held-changes-banner.js +106 -0
- package/dist/shell/held-changes-banner.js.map +1 -0
- package/dist/shell/sync-status-indicator.d.ts +27 -12
- package/dist/shell/sync-status-indicator.js +13 -4
- package/dist/shell/sync-status-indicator.js.map +1 -1
- package/dist/shell/top-bar-parts-labels.d.ts +5 -0
- package/dist/shell/top-bar-parts-labels.js +3 -1
- package/dist/shell/top-bar-parts-labels.js.map +1 -1
- package/dist/shell.d.ts +2 -0
- package/dist/shell.js +3 -0
- package/dist/shell.js.map +1 -1
- package/dist/sync/engine.d.ts +11 -2
- package/dist/sync/engine.js +13 -5
- package/dist/sync/engine.js.map +1 -1
- package/dist/sync/hooks.d.ts +3 -2
- package/dist/sync/hooks.js +4 -2
- package/dist/sync/hooks.js.map +1 -1
- package/dist/testing/css-variables.generated.d.ts +2 -2
- package/dist/testing/css-variables.generated.js +1 -1
- package/dist/testing/css-variables.generated.js.map +1 -1
- package/dist/theme/chart-palette.d.ts +18 -0
- package/dist/theme/chart-palette.js +17 -1
- package/dist/theme/chart-palette.js.map +1 -1
- package/dist/theme/contrast-tokens.d.ts +3 -3
- package/dist/theme/contrast-tokens.js.map +1 -1
- package/dist/theme/contrast.d.ts +4 -4
- package/dist/theme/contrast.js.map +1 -1
- package/dist/tour/tour-overlay.js +2 -1
- package/dist/tour/tour-overlay.js.map +1 -1
- package/package.json +5 -9
- package/tokens.css +19 -54
- package/src/account/account-parts.ts +0 -47
- package/src/account/account-settings-labels.ts +0 -240
- package/src/account/account-settings.tsx +0 -698
- package/src/account/data-export-setting-labels.ts +0 -20
- package/src/account/data-export-setting.tsx +0 -200
- package/src/account/delete-account-setting-labels.ts +0 -33
- package/src/account/delete-account-setting.tsx +0 -342
- package/src/account/email-change-setting-labels.ts +0 -31
- package/src/account/email-change-setting.tsx +0 -443
- package/src/account/passkeys-setting.tsx +0 -445
- package/src/account/sessions-setting-labels.ts +0 -24
- package/src/account/sessions-setting.tsx +0 -283
- package/src/admin/admin-action-confirm-labels.ts +0 -19
- package/src/admin/admin-action-confirm.tsx +0 -509
- package/src/admin/admin-action-log-labels.ts +0 -83
- package/src/admin/admin-action-log.tsx +0 -464
- package/src/admin/admin-area-labels.ts +0 -114
- package/src/admin/admin-forbidden.tsx +0 -75
- package/src/admin/admin-overview.tsx +0 -258
- package/src/admin/admin-parts.ts +0 -68
- package/src/admin/admin-sections.tsx +0 -208
- package/src/admin/admin-tool-links.tsx +0 -90
- package/src/admin/invitations-panel-labels.ts +0 -31
- package/src/admin/invitations-panel.tsx +0 -516
- package/src/admin/mail-test-card-labels.ts +0 -19
- package/src/admin/mail-test-card.tsx +0 -189
- package/src/admin/plan-change-labels.ts +0 -5
- package/src/admin/plan-change.tsx +0 -474
- package/src/admin/reviewer-scope-editor-labels.ts +0 -16
- package/src/admin/reviewer-scope-editor.tsx +0 -224
- package/src/admin/role-select-labels.ts +0 -16
- package/src/admin/role-select.tsx +0 -282
- package/src/admin/transfer-ownership-dialog-labels.ts +0 -20
- package/src/admin/transfer-ownership-dialog.tsx +0 -162
- package/src/admin/user-roster-labels.ts +0 -17
- package/src/admin/user-roster.tsx +0 -559
- package/src/auth/accept-invitation-labels.ts +0 -21
- package/src/auth/accept-invitation.tsx +0 -210
- package/src/auth/auth-errors-labels.ts +0 -23
- package/src/auth/auth-errors.ts +0 -439
- package/src/auth/complete-name-dialog-labels.ts +0 -16
- package/src/auth/complete-name-dialog.tsx +0 -253
- package/src/auth/email-tag.ts +0 -75
- package/src/auth/forgot-password-form-labels.ts +0 -20
- package/src/auth/forgot-password-form.tsx +0 -221
- package/src/auth/form-rules.ts +0 -40
- package/src/auth/new-password-fields.tsx +0 -85
- package/src/auth/not-found-page-labels.ts +0 -12
- package/src/auth/not-found-page.tsx +0 -95
- package/src/auth/register-form-labels.ts +0 -31
- package/src/auth/register-form.tsx +0 -456
- package/src/auth/reset-password-form-labels.ts +0 -27
- package/src/auth/reset-password-form.tsx +0 -341
- package/src/auth/sign-in-form-labels.ts +0 -44
- package/src/auth/sign-in-form.tsx +0 -858
- package/src/auth/status-parts.tsx +0 -132
- package/src/auth/verify-email-labels.ts +0 -26
- package/src/auth/verify-email.tsx +0 -445
- package/src/billing/billing-banner.tsx +0 -258
- package/src/billing/billing-labels.ts +0 -381
- package/src/billing/billing-lock.ts +0 -108
- package/src/billing/billing-overview.ts +0 -157
- package/src/billing/billing-standing.ts +0 -80
- package/src/billing/cancel-request.ts +0 -97
- package/src/billing/cancel-subscription.tsx +0 -98
- package/src/billing/checkout-processing.ts +0 -394
- package/src/billing/checkout-return.ts +0 -90
- package/src/billing/pay-page.ts +0 -330
- package/src/billing/plan-card.tsx +0 -562
- package/src/billing/plan-change-labels.ts +0 -66
- package/src/billing/plan-limit-notice.tsx +0 -148
- package/src/billing/plan-limit-toast.tsx +0 -90
- package/src/billing/plan-limit.ts +0 -52
- package/src/billing/plan-price.ts +0 -98
- package/src/billing/plan-switch.tsx +0 -216
- package/src/billing/provider-page.ts +0 -84
- package/src/billing/subscription-actions.tsx +0 -247
- package/src/billing/subscription-status-chip.tsx +0 -95
- package/src/chart.ts +0 -103
- package/src/components/account-chips-labels.ts +0 -16
- package/src/components/account-chips.tsx +0 -474
- package/src/components/alert-banner.tsx +0 -670
- package/src/components/amount-input.tsx +0 -816
- package/src/components/appearance-labels.ts +0 -63
- package/src/components/authed-image-labels.ts +0 -11
- package/src/components/authed-image.tsx +0 -209
- package/src/components/autocomplete.tsx +0 -645
- package/src/components/breadcrumbs-labels.ts +0 -10
- package/src/components/breadcrumbs.tsx +0 -205
- package/src/components/bulk-action-bar-labels.ts +0 -11
- package/src/components/bulk-action-bar.tsx +0 -443
- package/src/components/button-group.tsx +0 -223
- package/src/components/button-look.ts +0 -256
- package/src/components/button.tsx +0 -339
- package/src/components/calculator.tsx +0 -341
- package/src/components/calendar-heatmap-labels.ts +0 -15
- package/src/components/calendar-heatmap.tsx +0 -600
- package/src/components/card.tsx +0 -377
- package/src/components/chart-edge.ts +0 -106
- package/src/components/chart-figure.tsx +0 -35
- package/src/components/chart-height.ts +0 -30
- package/src/components/chart-zoom-core.tsx +0 -627
- package/src/components/chart-zoom.tsx +0 -22
- package/src/components/chart.tsx +0 -554
- package/src/components/checkbox-group.tsx +0 -247
- package/src/components/checkbox.tsx +0 -346
- package/src/components/chip-input.tsx +0 -370
- package/src/components/chip-labels.ts +0 -13
- package/src/components/chip.tsx +0 -843
- package/src/components/choice-card.tsx +0 -544
- package/src/components/column-mapper-labels.ts +0 -38
- package/src/components/column-mapper.tsx +0 -655
- package/src/components/combobox-core.tsx +0 -1321
- package/src/components/combobox-suggestions.tsx +0 -131
- package/src/components/combobox.tsx +0 -716
- package/src/components/confirm-context.ts +0 -7
- package/src/components/confirm-dialog-labels.ts +0 -13
- package/src/components/confirm-dialog.tsx +0 -341
- package/src/components/copy-button-labels.ts +0 -13
- package/src/components/copy-button.tsx +0 -192
- package/src/components/country-select-labels.ts +0 -11
- package/src/components/country-select.tsx +0 -539
- package/src/components/currency-option-list.tsx +0 -188
- package/src/components/currency-select.tsx +0 -343
- package/src/components/danger-confirm-labels.ts +0 -20
- package/src/components/danger-confirm.tsx +0 -987
- package/src/components/data-table-cells.tsx +0 -118
- package/src/components/data-table-column-settings.tsx +0 -198
- package/src/components/data-table-filter-popover.tsx +0 -289
- package/src/components/data-table-filters.ts +0 -315
- package/src/components/data-table-fit.ts +0 -301
- package/src/components/data-table-groups.tsx +0 -288
- package/src/components/data-table-head.tsx +0 -280
- package/src/components/data-table-labels.ts +0 -198
- package/src/components/data-table-leading-row.tsx +0 -58
- package/src/components/data-table-mobile.tsx +0 -1117
- package/src/components/data-table-pagination.tsx +0 -202
- package/src/components/data-table-resize.ts +0 -188
- package/src/components/data-table-row-actions.tsx +0 -302
- package/src/components/data-table-row.tsx +0 -496
- package/src/components/data-table-selection.ts +0 -71
- package/src/components/data-table-shared.tsx +0 -287
- package/src/components/data-table-sort.ts +0 -163
- package/src/components/data-table-virtual.ts +0 -576
- package/src/components/data-table.tsx +0 -2598
- package/src/components/date-field.tsx +0 -684
- package/src/components/date-format-setting.tsx +0 -64
- package/src/components/date-picker.tsx +0 -404
- package/src/components/date-range-picker.tsx +0 -518
- package/src/components/description-list-labels.ts +0 -9
- package/src/components/description-list.tsx +0 -386
- package/src/components/dialog-frame-labels.ts +0 -7
- package/src/components/dialog-frame.tsx +0 -284
- package/src/components/disclosure.tsx +0 -476
- package/src/components/dropdown.tsx +0 -461
- package/src/components/empty-state.tsx +0 -136
- package/src/components/entity-combobox.tsx +0 -422
- package/src/components/error-boundary-labels.ts +0 -20
- package/src/components/error-boundary.tsx +0 -675
- package/src/components/facing-pair.ts +0 -93
- package/src/components/field-base-labels.ts +0 -20
- package/src/components/field-base.tsx +0 -656
- package/src/components/field-parts.tsx +0 -825
- package/src/components/field-strip.tsx +0 -129
- package/src/components/field.tsx +0 -206
- package/src/components/file-button.tsx +0 -295
- package/src/components/file-dropzone.tsx +0 -559
- package/src/components/floating-panel-labels.ts +0 -10
- package/src/components/floating-panel.tsx +0 -828
- package/src/components/focus-ring.ts +0 -16
- package/src/components/form-actions-labels.ts +0 -11
- package/src/components/form-actions.tsx +0 -578
- package/src/components/full-bleed-dialog.tsx +0 -294
- package/src/components/grouped-picker.tsx +0 -184
- package/src/components/help-popover.tsx +0 -117
- package/src/components/hover-menu.tsx +0 -343
- package/src/components/iban-input-labels.ts +0 -14
- package/src/components/iban-input.tsx +0 -236
- package/src/components/icon-button.tsx +0 -959
- package/src/components/icon-picker-labels.ts +0 -13
- package/src/components/icon-picker.tsx +0 -232
- package/src/components/image-grid-labels.ts +0 -11
- package/src/components/image-grid.tsx +0 -202
- package/src/components/inline-confirm.tsx +0 -116
- package/src/components/inline-edit-field-labels.ts +0 -11
- package/src/components/inline-edit-field.tsx +0 -552
- package/src/components/inline-entity-combobox.tsx +0 -849
- package/src/components/input.tsx +0 -394
- package/src/components/jump-calendar.tsx +0 -265
- package/src/components/language-select.tsx +0 -93
- package/src/components/legal-labels.ts +0 -105
- package/src/components/legal-page.tsx +0 -711
- package/src/components/legal.tsx +0 -668
- package/src/components/lightbox-labels.ts +0 -18
- package/src/components/lightbox.tsx +0 -399
- package/src/components/line-items-labels.ts +0 -14
- package/src/components/line-items.tsx +0 -602
- package/src/components/list-labels.ts +0 -12
- package/src/components/list.tsx +0 -870
- package/src/components/loading-state.tsx +0 -78
- package/src/components/measured-grid-labels.ts +0 -25
- package/src/components/measured-grid.tsx +0 -837
- package/src/components/menu-item.tsx +0 -241
- package/src/components/mini-calendar-labels.ts +0 -17
- package/src/components/mini-calendar.tsx +0 -792
- package/src/components/modal.tsx +0 -534
- package/src/components/money-draft.ts +0 -83
- package/src/components/money-field.tsx +0 -76
- package/src/components/month-grid.tsx +0 -229
- package/src/components/month-picker-labels.ts +0 -22
- package/src/components/month-picker.tsx +0 -1087
- package/src/components/multi-entity-combobox.tsx +0 -369
- package/src/components/multi-select.tsx +0 -376
- package/src/components/nav-pills.tsx +0 -198
- package/src/components/number-field.tsx +0 -327
- package/src/components/number-input.tsx +0 -559
- package/src/components/numeric-field.ts +0 -169
- package/src/components/numpad-sheet.tsx +0 -285
- package/src/components/one-time-code-input.tsx +0 -270
- package/src/components/page-contents-labels.ts +0 -9
- package/src/components/page-contents.tsx +0 -282
- package/src/components/page-header-context.ts +0 -8
- package/src/components/page-header.tsx +0 -298
- package/src/components/password-strength-labels.ts +0 -22
- package/src/components/password-strength.tsx +0 -241
- package/src/components/phone-input-labels.ts +0 -10
- package/src/components/phone-input.tsx +0 -282
- package/src/components/picker-sheet.tsx +0 -330
- package/src/components/pie-chart-labels.ts +0 -40
- package/src/components/pie-chart.tsx +0 -480
- package/src/components/popover-labels.ts +0 -14
- package/src/components/popover.tsx +0 -268
- package/src/components/progress-bar-labels.ts +0 -10
- package/src/components/progress-bar.tsx +0 -479
- package/src/components/qr-code.tsx +0 -76
- package/src/components/reauth-dialog-labels.ts +0 -13
- package/src/components/reauth-dialog.tsx +0 -265
- package/src/components/row-actions-labels.ts +0 -12
- package/src/components/row-actions.tsx +0 -795
- package/src/components/scroll-area.tsx +0 -123
- package/src/components/search-field.tsx +0 -192
- package/src/components/select.tsx +0 -294
- package/src/components/separator.tsx +0 -33
- package/src/components/series-chart-axes.ts +0 -342
- package/src/components/series-chart-budget.ts +0 -150
- package/src/components/series-chart-labels.ts +0 -33
- package/src/components/series-chart-thin.ts +0 -180
- package/src/components/series-chart-ticks.ts +0 -194
- package/src/components/series-chart.tsx +0 -1906
- package/src/components/server-wake-labels.ts +0 -11
- package/src/components/server-wake.tsx +0 -129
- package/src/components/settings-fields.tsx +0 -237
- package/src/components/share-card-labels.ts +0 -30
- package/src/components/share-card.tsx +0 -675
- package/src/components/signature-pad-labels.ts +0 -24
- package/src/components/signature-pad.tsx +0 -747
- package/src/components/signed-amount-labels.ts +0 -10
- package/src/components/signed-amount.tsx +0 -336
- package/src/components/skeleton.tsx +0 -80
- package/src/components/slider.tsx +0 -338
- package/src/components/sparkline-labels.ts +0 -14
- package/src/components/sparkline.tsx +0 -322
- package/src/components/spinner.tsx +0 -81
- package/src/components/stat-tile-labels.ts +0 -15
- package/src/components/stat-tile.tsx +0 -754
- package/src/components/status-dot.tsx +0 -170
- package/src/components/swatch-picker-labels.ts +0 -10
- package/src/components/swatch-picker.tsx +0 -283
- package/src/components/swipeable-row.tsx +0 -386
- package/src/components/switch.tsx +0 -273
- package/src/components/table-skeleton.tsx +0 -136
- package/src/components/table.tsx +0 -647
- package/src/components/tabs-labels.ts +0 -13
- package/src/components/tabs.tsx +0 -693
- package/src/components/text-link.tsx +0 -359
- package/src/components/text.tsx +0 -150
- package/src/components/textarea.tsx +0 -330
- package/src/components/tile-radio.tsx +0 -332
- package/src/components/time-input.tsx +0 -121
- package/src/components/toast-labels.ts +0 -12
- package/src/components/toast.tsx +0 -519
- package/src/components/toggle-group.tsx +0 -752
- package/src/components/toggle-legend.tsx +0 -394
- package/src/components/tooltip.tsx +0 -1149
- package/src/components/translation-review-editor.tsx +0 -290
- package/src/components/translation-review-labels.ts +0 -181
- package/src/components/translation-review-parts.tsx +0 -272
- package/src/components/translation-review.tsx +0 -1240
- package/src/components/tree-view.tsx +0 -589
- package/src/components/treemap-labels.ts +0 -47
- package/src/components/treemap-layout.ts +0 -210
- package/src/components/treemap.tsx +0 -1184
- package/src/components/trigger-aria.ts +0 -44
- package/src/components/use-anchor-dir.ts +0 -20
- package/src/components/use-mobile-reveal.ts +0 -62
- package/src/components/use-table-state.ts +0 -753
- package/src/components/user-avatar.tsx +0 -116
- package/src/components/wizard-stepper.tsx +0 -42
- package/src/components/write-lock-labels.ts +0 -10
- package/src/components/write-lock.tsx +0 -253
- package/src/currencies.ts +0 -90
- package/src/data-table.ts +0 -42
- package/src/demo/demo-banner.tsx +0 -153
- package/src/demo/demo-countdown.ts +0 -136
- package/src/demo/demo-ended.tsx +0 -90
- package/src/demo/demo-labels.ts +0 -78
- package/src/demo/demo-session.ts +0 -32
- package/src/demo/demo-start.tsx +0 -156
- package/src/eslint/index.ts +0 -161
- package/src/eslint/role-utilities.generated.ts +0 -146
- package/src/eslint/role-utilities.ts +0 -233
- package/src/feedback/feedback-attachment-download.tsx +0 -77
- package/src/feedback/feedback-attachment-labels.ts +0 -37
- package/src/feedback/feedback-attachment.tsx +0 -1239
- package/src/feedback/feedback-capture.ts +0 -287
- package/src/feedback/feedback-comment-thread.tsx +0 -353
- package/src/feedback/feedback-context-labels.ts +0 -11
- package/src/feedback/feedback-context.tsx +0 -245
- package/src/feedback/feedback-crash.ts +0 -547
- package/src/feedback/feedback-diagnostics.tsx +0 -41
- package/src/feedback/feedback-dialog-labels.ts +0 -29
- package/src/feedback/feedback-dialog.tsx +0 -452
- package/src/feedback/feedback-entry-file.tsx +0 -150
- package/src/feedback/feedback-inbox.tsx +0 -552
- package/src/feedback/feedback-labels.ts +0 -144
- package/src/feedback/feedback-menu-labels.ts +0 -12
- package/src/feedback/feedback-menu.tsx +0 -177
- package/src/feedback/feedback-mutation.ts +0 -20
- package/src/feedback/feedback-page-link.ts +0 -90
- package/src/feedback/feedback-public-labels.ts +0 -81
- package/src/feedback/feedback-public-list.tsx +0 -524
- package/src/feedback/feedback-public-switch.tsx +0 -102
- package/src/feedback/feedback-public-types.ts +0 -101
- package/src/feedback/feedback-record.ts +0 -428
- package/src/feedback/feedback-replies-context.ts +0 -9
- package/src/feedback/feedback-replies.tsx +0 -343
- package/src/feedback/feedback-rework-entry-chip.tsx +0 -18
- package/src/feedback/feedback-row-detail-labels.ts +0 -31
- package/src/feedback/feedback-row-detail.tsx +0 -871
- package/src/feedback/feedback-status-undo.ts +0 -109
- package/src/feedback/feedback-submit-dialog.tsx +0 -131
- package/src/feedback/feedback-submit.tsx +0 -270
- package/src/feedback/feedback-swipe.tsx +0 -192
- package/src/feedback/feedback-table-labels.ts +0 -27
- package/src/feedback/feedback-table.tsx +0 -912
- package/src/feedback/feedback-thread-labels.ts +0 -22
- package/src/feedback/feedback-thread-parts-labels.ts +0 -41
- package/src/feedback/feedback-thread.tsx +0 -905
- package/src/feedback/feedback-vocabulary.ts +0 -263
- package/src/feedback/feedback-vote-button.tsx +0 -124
- package/src/feedback.ts +0 -116
- package/src/hooks/use-anchored-panel.ts +0 -396
- package/src/hooks/use-anchored-rect.ts +0 -77
- package/src/hooks/use-announce.ts +0 -85
- package/src/hooks/use-authed-src.ts +0 -167
- package/src/hooks/use-body-scroll-lock.ts +0 -119
- package/src/hooks/use-breakpoint.ts +0 -133
- package/src/hooks/use-close-transition.ts +0 -107
- package/src/hooks/use-copy-to-clipboard.ts +0 -122
- package/src/hooks/use-debounce.ts +0 -114
- package/src/hooks/use-dismiss.ts +0 -371
- package/src/hooks/use-document-title.ts +0 -33
- package/src/hooks/use-file-drop.ts +0 -121
- package/src/hooks/use-file-picker-labels.ts +0 -28
- package/src/hooks/use-file-picker.tsx +0 -359
- package/src/hooks/use-focus-trap.ts +0 -199
- package/src/hooks/use-hotkey.ts +0 -212
- package/src/hooks/use-large-text.ts +0 -41
- package/src/hooks/use-long-press.ts +0 -140
- package/src/hooks/use-media-query.ts +0 -39
- package/src/hooks/use-mounted.ts +0 -39
- package/src/hooks/use-noindex.ts +0 -37
- package/src/hooks/use-overlay-history.ts +0 -714
- package/src/hooks/use-row-swipe.ts +0 -207
- package/src/hooks/use-search-param-state.ts +0 -434
- package/src/hooks/use-windowed-rows.ts +0 -225
- package/src/i18n/defaults.ts +0 -267
- package/src/i18n/german.ts +0 -2059
- package/src/i18n/kit-labels.tsx +0 -1003
- package/src/i18n/languages.ts +0 -349
- package/src/i18n/locales/de-CH.ts +0 -24
- package/src/i18n/locales/en.ts +0 -267
- package/src/i18n/locales/es.ts +0 -1999
- package/src/i18n/locales/fr.ts +0 -2037
- package/src/i18n/locales/hu.ts +0 -2004
- package/src/i18n/locales/it.ts +0 -2014
- package/src/i18n/locales/zh.ts +0 -1912
- package/src/i18n/plurals.ts +0 -86
- package/src/i18n/review.ts +0 -475
- package/src/i18n/shared-labels.ts +0 -138
- package/src/i18n/swiss.ts +0 -29
- package/src/index.ts +0 -1191
- package/src/landing/access.ts +0 -93
- package/src/landing/landing-actions.tsx +0 -97
- package/src/landing/landing-labels.ts +0 -59
- package/src/landing/landing-sections.tsx +0 -341
- package/src/landing/page-seo.ts +0 -261
- package/src/landing/public-header.tsx +0 -121
- package/src/landing/public-page.tsx +0 -106
- package/src/landing/routing.tsx +0 -225
- package/src/lib/broadcast.ts +0 -52
- package/src/lib/calc.ts +0 -323
- package/src/lib/chip-edge-snap.ts +0 -212
- package/src/lib/clipboard-minus.ts +0 -107
- package/src/lib/clipping.ts +0 -34
- package/src/lib/cn.ts +0 -28
- package/src/lib/column-mapping.ts +0 -234
- package/src/lib/countries.ts +0 -91
- package/src/lib/data-attributes.ts +0 -14
- package/src/lib/date-format.ts +0 -227
- package/src/lib/dates.ts +0 -288
- package/src/lib/day-format.ts +0 -96
- package/src/lib/decimal-marks.ts +0 -108
- package/src/lib/describe-failure.ts +0 -18
- package/src/lib/device-settings.ts +0 -147
- package/src/lib/direction.ts +0 -74
- package/src/lib/document-navigation.ts +0 -17
- package/src/lib/document-title.ts +0 -41
- package/src/lib/download.ts +0 -172
- package/src/lib/float-clearance.ts +0 -70
- package/src/lib/floating-stack.ts +0 -70
- package/src/lib/focus-left.ts +0 -156
- package/src/lib/format.ts +0 -585
- package/src/lib/http-status.ts +0 -38
- package/src/lib/iban.ts +0 -251
- package/src/lib/ime.ts +0 -24
- package/src/lib/intl-cache.ts +0 -27
- package/src/lib/iso-day.ts +0 -13
- package/src/lib/lazy-with-fallback.ts +0 -82
- package/src/lib/logger.ts +0 -69
- package/src/lib/minus.ts +0 -50
- package/src/lib/path-pattern.ts +0 -55
- package/src/lib/person-name.ts +0 -155
- package/src/lib/phone.ts +0 -208
- package/src/lib/plain-text.ts +0 -22
- package/src/lib/presence.ts +0 -18
- package/src/lib/qr-encode.ts +0 -444
- package/src/lib/quiet-focus.ts +0 -32
- package/src/lib/reduced-motion.ts +0 -22
- package/src/lib/refs.ts +0 -22
- package/src/lib/round.ts +0 -43
- package/src/lib/safe-storage.ts +0 -119
- package/src/lib/server-wake.ts +0 -315
- package/src/lib/session-refresh.ts +0 -472
- package/src/lib/share-format.ts +0 -18
- package/src/lib/status-tone.ts +0 -43
- package/src/lib/strip-fade.ts +0 -287
- package/src/lib/table-text.ts +0 -554
- package/src/lib/text-case.ts +0 -19
- package/src/lib/text-match.ts +0 -169
- package/src/lib/thenable.ts +0 -19
- package/src/lib/translation-review.ts +0 -769
- package/src/notifications/device-zone-report.ts +0 -67
- package/src/notifications/feedback-notification-types-labels.ts +0 -33
- package/src/notifications/feedback-notification-types.ts +0 -71
- package/src/notifications/notification-bell.tsx +0 -119
- package/src/notifications/notification-inbox.tsx +0 -309
- package/src/notifications/notification-parts.tsx +0 -81
- package/src/notifications/notification-types-setting.tsx +0 -406
- package/src/notifications/notification-types.ts +0 -89
- package/src/notifications/notifications-labels.ts +0 -287
- package/src/notifications/push-device-setting.tsx +0 -230
- package/src/notifications/push-devices-setting.tsx +0 -374
- package/src/notifications/push-worker.ts +0 -168
- package/src/notifications/quiet-hours-setting.tsx +0 -238
- package/src/notifications/unsubscribe-panel.tsx +0 -200
- package/src/notifications/use-push-device.ts +0 -448
- package/src/offline/local-first.ts +0 -100
- package/src/offline/pwa-update-prompt-labels.ts +0 -9
- package/src/offline/pwa-update-prompt.tsx +0 -78
- package/src/offline/query-persistence.ts +0 -391
- package/src/offline/service-worker-updates.ts +0 -81
- package/src/offline/shared-computer-labels.ts +0 -8
- package/src/offline/shared-computer.tsx +0 -87
- package/src/offline/sign-out-pending-dialog-labels.ts +0 -21
- package/src/offline/sign-out-pending-dialog.tsx +0 -135
- package/src/offline.ts +0 -37
- package/src/push-worker.ts +0 -25
- package/src/rhf/fields.tsx +0 -2187
- package/src/rhf/form-core.tsx +0 -324
- package/src/rhf/form.tsx +0 -12
- package/src/rhf/line-items.tsx +0 -135
- package/src/rhf/use-rhf-wizard-step.ts +0 -104
- package/src/rhf.ts +0 -21
- package/src/search/command-palette-labels.ts +0 -16
- package/src/search/command-palette.tsx +0 -624
- package/src/search/global-search-labels.ts +0 -13
- package/src/search/global-search.tsx +0 -660
- package/src/search/search-index.ts +0 -283
- package/src/search/use-command-key.ts +0 -23
- package/src/search.ts +0 -14
- package/src/settings/device-reset-setting-labels.ts +0 -20
- package/src/settings/device-reset-setting.tsx +0 -116
- package/src/settings/settings-card-classes.ts +0 -11
- package/src/settings/settings-catalogue.ts +0 -150
- package/src/settings/settings-context.ts +0 -33
- package/src/settings/settings-heading.tsx +0 -67
- package/src/settings/settings-labels.ts +0 -87
- package/src/settings/settings-layout.tsx +0 -471
- package/src/settings/settings-section.tsx +0 -108
- package/src/settings/use-account-appearance.ts +0 -148
- package/src/settings/use-account-language.ts +0 -146
- package/src/settings/use-settings-focus.ts +0 -128
- package/src/settings/use-settings-route.ts +0 -258
- package/src/shell/account-menu-language.tsx +0 -130
- package/src/shell/account-menu-text-size.tsx +0 -80
- package/src/shell/admin-menu.tsx +0 -183
- package/src/shell/app-shell-labels.ts +0 -11
- package/src/shell/app-shell.tsx +0 -1560
- package/src/shell/auth-layout.tsx +0 -186
- package/src/shell/company-switcher-labels.ts +0 -13
- package/src/shell/company-switcher.tsx +0 -136
- package/src/shell/dev-menu.tsx +0 -257
- package/src/shell/fill-height.tsx +0 -45
- package/src/shell/language-code.ts +0 -5
- package/src/shell/option-switcher-menu.tsx +0 -84
- package/src/shell/sync-status-indicator.tsx +0 -303
- package/src/shell/top-bar-actions.tsx +0 -87
- package/src/shell/top-bar-brand.tsx +0 -78
- package/src/shell/top-bar-parts-labels.ts +0 -148
- package/src/shell/top-bar.tsx +0 -40
- package/src/shell/topbar-action-menu.tsx +0 -567
- package/src/shell/topbar-controls.tsx +0 -269
- package/src/shell/tour-menu.tsx +0 -187
- package/src/shell.ts +0 -108
- package/src/sync/db.ts +0 -129
- package/src/sync/engine.ts +0 -1011
- package/src/sync/hooks.ts +0 -98
- package/src/sync/testing.ts +0 -73
- package/src/sync/wire.ts +0 -61
- package/src/sync.ts +0 -37
- package/src/table-text.ts +0 -8
- package/src/testing/css-variables.generated.ts +0 -112
- package/src/testing/css-variables.ts +0 -189
- package/src/testing/index.ts +0 -29
- package/src/testing/react.ts +0 -58
- package/src/testing/tour.ts +0 -41
- package/src/testing/viewport.ts +0 -357
- package/src/theme/chart-palette.ts +0 -232
- package/src/theme/color.ts +0 -272
- package/src/theme/contrast-tokens.ts +0 -268
- package/src/theme/contrast.ts +0 -250
- package/src/theme/palette-derive.ts +0 -825
- package/src/theme/palette-presets.ts +0 -544
- package/src/theme/palette-store.ts +0 -108
- package/src/theme/text-size.ts +0 -289
- package/src/theme/theme-store.ts +0 -157
- package/src/tour/tour-catalogue-labels.ts +0 -75
- package/src/tour/tour-catalogue.tsx +0 -335
- package/src/tour/tour-dock.ts +0 -134
- package/src/tour/tour-engine.ts +0 -37
- package/src/tour/tour-gates.ts +0 -218
- package/src/tour/tour-guide-button.tsx +0 -64
- package/src/tour/tour-guide-labels.ts +0 -15
- package/src/tour/tour-info.ts +0 -144
- package/src/tour/tour-labels.ts +0 -23
- package/src/tour/tour-overlay.tsx +0 -1170
- package/src/tour/tour.tsx +0 -750
- package/src/tour/use-tour-progress.ts +0 -671
- package/src/tour/use-tour-url-sync.ts +0 -266
- package/src/tour.ts +0 -21
- package/src/vite-env.d.ts +0 -23
- package/src/wizard/stepper-nav.tsx +0 -360
- package/src/wizard/types.ts +0 -275
- package/src/wizard/use-wizard.ts +0 -560
- package/src/wizard/validation.ts +0 -39
- package/src/wizard/wizard-context.tsx +0 -74
- package/src/wizard/wizard-labels.ts +0 -29
- package/src/wizard/wizard-step.tsx +0 -76
- package/src/wizard/wizard-summary.tsx +0 -84
- package/src/wizard.ts +0 -15
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import type { ComponentPropsWithRef } from "react";
|
|
2
|
-
|
|
3
|
-
import { useKitLocale } from "../i18n/kit-labels";
|
|
4
|
-
import type { LabelOverride } from "../i18n/kit-labels";
|
|
5
|
-
import { formatNumber } from "../lib/format";
|
|
6
|
-
import { AlertBanner } from "../components/alert-banner";
|
|
7
|
-
import type { AlertTone } from "../components/alert-banner";
|
|
8
|
-
import { ProgressBar } from "../components/progress-bar";
|
|
9
|
-
import { Button } from "../components/button";
|
|
10
|
-
import { useBillingLabels } from "./billing-labels";
|
|
11
|
-
import type { BillingLabels } from "./billing-labels";
|
|
12
|
-
|
|
13
|
-
/** RFC 3986 percent-encoding, `!'()*` too — a mail client that splits on `'` is the one
|
|
14
|
-
* that breaks "Plan limit: Ada's plots" (landing/access.ts keeps the same rule). */
|
|
15
|
-
function encodeStrict(value: string): string {
|
|
16
|
-
return encodeURIComponent(value).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** The `contact` mode's mail: to support, its subject naming the dimension. */
|
|
20
|
-
export function planLimitMailto(email: string, subject: string): string {
|
|
21
|
-
const to = encodeStrict(email).replace(/%40/g, "@");
|
|
22
|
-
return `mailto:${to}?subject=${encodeStrict(subject)}`;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** A `div`'s props, `ref` included since 0.35 (round 0.35 R4, the follow-up to API-2): they
|
|
26
|
-
* go on to the {@link AlertBanner}, so the ref is the notice's `<div>` — its `href` is the
|
|
27
|
-
* action button's, never the banner's, so the frame is never a link. */
|
|
28
|
-
interface PlanLimitNoticeBaseProps extends Omit<ComponentPropsWithRef<"div">, "children" | "onClick"> {
|
|
29
|
-
/** The dimension as the refusal names it (`"budgets"`, `"seats"`) — `isPlanLimit(err)`'s
|
|
30
|
-
* `dimension`. Carried as `data-dimension`. */
|
|
31
|
-
dimension: string;
|
|
32
|
-
/** The app's name for it, in the reader's language: "Budgets". Default: the key. */
|
|
33
|
-
dimensionLabel?: string;
|
|
34
|
-
/** How many there are. Left out (keksdose's legacy `plan_budget_limit` body has no
|
|
35
|
-
* `used`), it is read as `limit`: the create was refused for being at it. */
|
|
36
|
-
used?: number;
|
|
37
|
-
/** The plan's limit for the dimension. Left out — a body without one — the notice says
|
|
38
|
-
* its words and draws no meter. */
|
|
39
|
-
limit?: number;
|
|
40
|
-
/** The payer's plan code, as `isPlanLimit` reads it — carried as `data-plan`, so the
|
|
41
|
-
* refusal can be spread in whole: `<PlanLimitNotice {...isPlanLimit(err)} …/>`. */
|
|
42
|
-
plan?: string;
|
|
43
|
-
/** How a figure is written — kastlan's storage limit is bytes (`formatFileSize`).
|
|
44
|
-
* Default: a number in the kit's locale. */
|
|
45
|
-
formatValue?: (value: number) => string;
|
|
46
|
-
/** Over the provider's locale, for the default figures. */
|
|
47
|
-
locale?: string;
|
|
48
|
-
/** Default `warning`. */
|
|
49
|
-
tone?: AlertTone;
|
|
50
|
-
/** Prop > `<UiKitProvider labels={{ billing }}>` > English. */
|
|
51
|
-
labels?: LabelOverride<BillingLabels>;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export type PlanLimitNoticeProps = PlanLimitNoticeBaseProps &
|
|
55
|
-
(
|
|
56
|
-
| {
|
|
57
|
-
/** Plans are bought: "Choose a plan" → the app's subscription page. */
|
|
58
|
-
mode: "upgrade";
|
|
59
|
-
/** The subscription page. */
|
|
60
|
-
href: string;
|
|
61
|
-
email?: never;
|
|
62
|
-
}
|
|
63
|
-
| {
|
|
64
|
-
/** The operator grants plans by hand (keksdose's today): "Ask for more" → a mail. */
|
|
65
|
-
mode: "contact";
|
|
66
|
-
/** The support address: `support@` the app's domain. */
|
|
67
|
-
email: string;
|
|
68
|
-
href?: never;
|
|
69
|
-
}
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* A create refused at the plan's limit (docs/billing-harmonization.md §3.4): "Plan limit
|
|
74
|
-
* reached", what to do, the dimension's meter ("Budgets — 3 of 3") and the app's way to
|
|
75
|
-
* more — `upgrade`, a link to the subscription page, or `contact`, a mail to support.
|
|
76
|
-
*
|
|
77
|
-
* A limit gates CREATION only: a downgrade never deletes or hides what is over the new
|
|
78
|
-
* limit (§3.4), so `used` may be past `limit`; the meter then fills and turns red. Feed it
|
|
79
|
-
* the refusal: `const hit = isPlanLimit(err); hit && <PlanLimitNotice {...hit} …/>`. The
|
|
80
|
-
* kit sends nothing — the mail opens the reader's own client.
|
|
81
|
-
*/
|
|
82
|
-
export function PlanLimitNotice(props: PlanLimitNoticeProps) {
|
|
83
|
-
const {
|
|
84
|
-
dimension,
|
|
85
|
-
dimensionLabel,
|
|
86
|
-
used: usedProp,
|
|
87
|
-
limit,
|
|
88
|
-
plan,
|
|
89
|
-
formatValue,
|
|
90
|
-
locale: localeProp,
|
|
91
|
-
tone = "warning",
|
|
92
|
-
labels: labelsProp,
|
|
93
|
-
mode,
|
|
94
|
-
href,
|
|
95
|
-
email,
|
|
96
|
-
className,
|
|
97
|
-
...rest
|
|
98
|
-
} = props;
|
|
99
|
-
const labels = useBillingLabels(labelsProp);
|
|
100
|
-
const locale = useKitLocale(localeProp);
|
|
101
|
-
const used = usedProp ?? limit ?? 0;
|
|
102
|
-
const name = dimensionLabel ?? dimension;
|
|
103
|
-
const figure = (value: number) => (formatValue ? formatValue(value) : formatNumber(value, { locale }));
|
|
104
|
-
|
|
105
|
-
const action =
|
|
106
|
-
mode === "upgrade" ? (
|
|
107
|
-
<Button href={href} variant="secondary" size="sm">
|
|
108
|
-
{labels.choosePlan}
|
|
109
|
-
</Button>
|
|
110
|
-
) : (
|
|
111
|
-
<Button href={planLimitMailto(email, labels.contactSubject(name))} variant="secondary" size="sm">
|
|
112
|
-
{labels.askForMore}
|
|
113
|
-
</Button>
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
return (
|
|
117
|
-
<AlertBanner
|
|
118
|
-
{...rest}
|
|
119
|
-
tone={tone}
|
|
120
|
-
action={action}
|
|
121
|
-
data-plan-limit-mode={mode}
|
|
122
|
-
data-dimension={dimension}
|
|
123
|
-
data-plan={plan}
|
|
124
|
-
className={className}
|
|
125
|
-
>
|
|
126
|
-
<span className="block font-medium">{labels.limitReached}</span>
|
|
127
|
-
<span className="block">{mode === "upgrade" ? labels.limitUpgrade : labels.limitContact}</span>
|
|
128
|
-
{limit !== undefined && (
|
|
129
|
-
<ProgressBar
|
|
130
|
-
as="span"
|
|
131
|
-
variant="meter"
|
|
132
|
-
size="slim"
|
|
133
|
-
value={used}
|
|
134
|
-
max={limit}
|
|
135
|
-
label={name}
|
|
136
|
-
showValue
|
|
137
|
-
// The bar is clamped at `max` and hands its formatter the clamped value; the
|
|
138
|
-
// figures are the real ones, so "5 of 3" after a downgrade says what the bar
|
|
139
|
-
// cannot draw.
|
|
140
|
-
formatValue={() => labels.usage(figure(used), figure(limit))}
|
|
141
|
-
tone={used > limit ? "danger" : "warning"}
|
|
142
|
-
className="mt-2"
|
|
143
|
-
locale={locale}
|
|
144
|
-
/>
|
|
145
|
-
)}
|
|
146
|
-
</AlertBanner>
|
|
147
|
-
);
|
|
148
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { useCallback } from "react";
|
|
2
|
-
|
|
3
|
-
import { useKitLocale } from "../i18n/kit-labels";
|
|
4
|
-
import type { LabelOverride } from "../i18n/kit-labels";
|
|
5
|
-
import { documentNavigation } from "../lib/document-navigation";
|
|
6
|
-
import { formatNumber } from "../lib/format";
|
|
7
|
-
import { toast } from "../components/toast";
|
|
8
|
-
import type { ToastAction, ToastId } from "../components/toast";
|
|
9
|
-
import { useBillingLabels } from "./billing-labels";
|
|
10
|
-
import type { BillingLabels } from "./billing-labels";
|
|
11
|
-
import type { PlanLimitRefusal } from "./plan-limit";
|
|
12
|
-
import { planLimitMailto } from "./plan-limit-notice";
|
|
13
|
-
|
|
14
|
-
export interface PlanLimitToastOptions {
|
|
15
|
-
/** `upgrade`: plans are bought — "Choose a plan". `contact`: the operator grants them
|
|
16
|
-
* by hand — "Ask for more", a mail to support. */
|
|
17
|
-
mode: "upgrade" | "contact";
|
|
18
|
-
/** `upgrade`: the app's navigation to its subscription page (the kit has no router).
|
|
19
|
-
* Left out, the toast has no action. */
|
|
20
|
-
onChoosePlan?: () => void;
|
|
21
|
-
/** `contact`: support@ the app's domain, opened as `planLimitMailto(email,
|
|
22
|
-
* contactSubject(name))`. Left out, the toast has no action. */
|
|
23
|
-
email?: string;
|
|
24
|
-
/** The app's word per dimension: `{ budgets: "Budgets", scans: "Scans this month" }`.
|
|
25
|
-
* A dimension without one is named by its key. */
|
|
26
|
-
dimensionLabels?: Readonly<Record<string, string>>;
|
|
27
|
-
/** How a figure is written — kastlan's storage limit is bytes. Default: a number in
|
|
28
|
-
* the kit's locale. */
|
|
29
|
-
formatValue?: (dimension: string, value: number) => string;
|
|
30
|
-
/** Prop > `<UiKitProvider labels={{ billing }}>` > English. */
|
|
31
|
-
labels?: LabelOverride<BillingLabels>;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* `PlanLimitNotice`'s words as a toast (docs/billing-harmonization.md §14.11), for a
|
|
36
|
-
* refused create with no room for the notice — a row's button, a share target: "Plan
|
|
37
|
-
* limit reached", what to do, the figure when the refusal has one ("Budgets: 3 of 3"),
|
|
38
|
-
* and the mode's action.
|
|
39
|
-
*
|
|
40
|
-
* const showLimit = usePlanLimitToast({
|
|
41
|
-
* mode: "upgrade",
|
|
42
|
-
* onChoosePlan: () => navigate("/settings/subscription"),
|
|
43
|
-
* dimensionLabels: { budgets: t("billing.dim_budgets") },
|
|
44
|
-
* });
|
|
45
|
-
* catch (err) { const hit = isPlanLimit(err); if (hit) showLimit(hit); }
|
|
46
|
-
*
|
|
47
|
-
* One toast per dimension: its id is `plan-limit:<dimension>`, so a repeat replaces it
|
|
48
|
-
* in place instead of stacking a second (keksdose's own hook stacked). Called with no
|
|
49
|
-
* hit, it says the words without a figure, under `plan-limit`. No `limit` in the
|
|
50
|
-
* refusal, no figure line; keksdose's legacy `plan_budget_limit` reads as `budgets`
|
|
51
|
-
* (`isPlanLimit`, §12.16). Returns the toast's id.
|
|
52
|
-
*/
|
|
53
|
-
export function usePlanLimitToast(options: PlanLimitToastOptions): (hit?: PlanLimitRefusal) => ToastId {
|
|
54
|
-
const { mode, onChoosePlan, email, dimensionLabels, formatValue, labels: labelsProp } = options;
|
|
55
|
-
const labels = useBillingLabels(labelsProp);
|
|
56
|
-
const locale = useKitLocale();
|
|
57
|
-
return useCallback(
|
|
58
|
-
(hit?: PlanLimitRefusal) => {
|
|
59
|
-
const dimension = hit?.dimension ?? "";
|
|
60
|
-
const name = dimensionLabels?.[dimension] ?? dimension;
|
|
61
|
-
const figure = (value: number) => (formatValue ? formatValue(dimension, value) : formatNumber(value, { locale }));
|
|
62
|
-
// A body without `used` was refused for being AT the limit (PlanLimitNotice's rule).
|
|
63
|
-
const usage =
|
|
64
|
-
hit?.limit !== undefined
|
|
65
|
-
? labels.limitUsageLine(name, figure(hit.used ?? hit.limit), figure(hit.limit))
|
|
66
|
-
: undefined;
|
|
67
|
-
const action: ToastAction | undefined =
|
|
68
|
-
mode === "upgrade"
|
|
69
|
-
? onChoosePlan && { label: labels.choosePlan, onClick: () => onChoosePlan() }
|
|
70
|
-
: email
|
|
71
|
-
? {
|
|
72
|
-
label: labels.askForMore,
|
|
73
|
-
// A mailto: hands the address to the reader's mail client; the page stays.
|
|
74
|
-
onClick: () => documentNavigation.replace(planLimitMailto(email, labels.contactSubject(name))),
|
|
75
|
-
}
|
|
76
|
-
: undefined;
|
|
77
|
-
return toast.warning(labels.limitReached, {
|
|
78
|
-
id: dimension ? `plan-limit:${dimension}` : "plan-limit",
|
|
79
|
-
description: (
|
|
80
|
-
<span data-plan-limit-mode={mode} data-dimension={dimension || undefined}>
|
|
81
|
-
<span className="block">{mode === "upgrade" ? labels.limitUpgrade : labels.limitContact}</span>
|
|
82
|
-
{usage !== undefined && <span className="block tabular-nums">{usage}</span>}
|
|
83
|
-
</span>
|
|
84
|
-
),
|
|
85
|
-
action,
|
|
86
|
-
});
|
|
87
|
-
},
|
|
88
|
-
[mode, onChoosePlan, email, dimensionLabels, formatValue, labels, locale],
|
|
89
|
-
);
|
|
90
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { errorBodyWithCode } from "../auth/auth-errors";
|
|
2
|
-
|
|
3
|
-
/** What {@link isPlanLimit} reads off a `plan_limit` refusal (docs/billing-harmonization.md
|
|
4
|
-
* §3.4): `402 {detail, code: "plan_limit", dimension, plan, limit, used}`. */
|
|
5
|
-
export interface PlanLimitRefusal {
|
|
6
|
-
/** The limited dimension, as the app's catalogue names it: `"budgets"`, `"seats"`. */
|
|
7
|
-
dimension: string;
|
|
8
|
-
/** The payer's plan code, lowercased (§12.16: reads compare without case, and
|
|
9
|
-
* keksdose's legacy body still says `"FREE"`). `undefined` when the body has none. */
|
|
10
|
-
plan: string | undefined;
|
|
11
|
-
/** The plan's limit for the dimension. `undefined` when the body has none. */
|
|
12
|
-
limit: number | undefined;
|
|
13
|
-
/** How many there are. `undefined` when the body has none — keksdose's legacy
|
|
14
|
-
* `plan_budget_limit` body never had it. */
|
|
15
|
-
used: number | undefined;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/** keksdose's code before §3.4: `402 {detail, code: "plan_budget_limit", plan, limit}`. */
|
|
19
|
-
const LEGACY_BUDGET_LIMIT = "plan_budget_limit";
|
|
20
|
-
|
|
21
|
-
const text = (value: unknown): string | undefined => (typeof value === "string" && value !== "" ? value : undefined);
|
|
22
|
-
const count = (value: unknown): number | undefined =>
|
|
23
|
-
typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* The plan-limit refusal `err` carries — `{dimension, plan, limit, used}` — or
|
|
27
|
-
* `undefined` when it is not one (docs/billing-harmonization.md §3.4):
|
|
28
|
-
*
|
|
29
|
-
* catch (err) {
|
|
30
|
-
* const hit = isPlanLimit(err);
|
|
31
|
-
* if (hit) return setLimit(hit); // → <PlanLimitNotice {...hit} mode="upgrade" href="/settings/subscription" />
|
|
32
|
-
* }
|
|
33
|
-
*
|
|
34
|
-
* The body is found where `authErrorCode` finds a code — axios' `err.response.data`,
|
|
35
|
-
* ofetch's `err.data`, a generated client's `err.body`, or `err` itself — and FastAPI's
|
|
36
|
-
* nested `{detail: {code, …}}` too; the extra fields are read beside the code.
|
|
37
|
-
*
|
|
38
|
-
* keksdose's old code, `plan_budget_limit`, is read as `dimension: "budgets"` (§12.16):
|
|
39
|
-
* its frontend accepts both codes for a release, because installed PWAs run the previous
|
|
40
|
-
* bundle while the server switches.
|
|
41
|
-
*/
|
|
42
|
-
export function isPlanLimit(err: unknown): PlanLimitRefusal | undefined {
|
|
43
|
-
const body = errorBodyWithCode(err, (code) => code === "plan_limit" || code === LEGACY_BUDGET_LIMIT);
|
|
44
|
-
if (!body) return undefined;
|
|
45
|
-
const legacy = body.code === LEGACY_BUDGET_LIMIT;
|
|
46
|
-
return {
|
|
47
|
-
dimension: text(body.dimension) ?? (legacy ? "budgets" : ""),
|
|
48
|
-
plan: text(body.plan)?.toLowerCase(),
|
|
49
|
-
limit: count(body.limit),
|
|
50
|
-
used: count(body.used),
|
|
51
|
-
};
|
|
52
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
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 = { kind: "price"; minor: number } | { kind: "free" } | { kind: "not-offered" };
|
|
38
|
-
|
|
39
|
-
/** Whether a price table holds any figure at all. */
|
|
40
|
-
function hasAnyPrice(prices: PlanPrices | null | undefined): boolean {
|
|
41
|
-
if (!prices) return false;
|
|
42
|
-
return Object.values(prices).some(
|
|
43
|
-
(byInterval) => byInterval && Object.values(byInterval).some((v) => typeof v === "number"),
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** What `prices` says for `currency` and `interval` — see {@link PlanPriceAnswer}. */
|
|
48
|
-
export function planPrice(
|
|
49
|
-
prices: PlanPrices | null | undefined,
|
|
50
|
-
currency: BillingCurrency,
|
|
51
|
-
interval: BillingInterval,
|
|
52
|
-
): PlanPriceAnswer {
|
|
53
|
-
const minor = prices?.[currency]?.[interval];
|
|
54
|
-
if (typeof minor === "number" && Number.isFinite(minor)) {
|
|
55
|
-
return minor === 0 ? { kind: "free" } : { kind: "price", minor };
|
|
56
|
-
}
|
|
57
|
-
return hasAnyPrice(prices) ? { kind: "not-offered" } : { kind: "free" };
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** Minor units as the amount: 4900 CHF → 49, 1250 EUR → 12.5. The currency's minor unit
|
|
61
|
-
* comes from `Intl` (CHF and EUR have 2); a code `Intl` cannot read counts as 2. */
|
|
62
|
-
export function minorToMajor(minor: number, currency: string): number {
|
|
63
|
-
const digits = currencyMinorDigits(currency) ?? 2;
|
|
64
|
-
return minor / 10 ** digits;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* A price in minor units, in the reader's notation: "CHF 49", "CHF 4.90", "49 €",
|
|
69
|
-
* "4,90 €". A whole amount drops its decimals — a price list reads "CHF 49" — and any
|
|
70
|
-
* other keeps all of them ("CHF 4.90", never "CHF 4.9").
|
|
71
|
-
*/
|
|
72
|
-
export function formatPlanPrice(minor: number, currency: string, options: { locale?: string } = {}): string {
|
|
73
|
-
const digits = currencyMinorDigits(currency) ?? 2;
|
|
74
|
-
const whole = Number.isInteger(minor) && minor % 10 ** digits === 0;
|
|
75
|
-
return formatMoney(minorToMajor(minor, currency), currency, {
|
|
76
|
-
locale: options.locale,
|
|
77
|
-
digits: whole ? 0 : digits,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* The currency a payer starts with when the app stores none (§12.18): francs where the
|
|
83
|
-
* locale's region is Switzerland or Liechtenstein, euros everywhere else — "de-CH" and
|
|
84
|
-
* "fr-CH" CHF, "de" (Germany, once `Intl` fills the region in) and "it" EUR.
|
|
85
|
-
*
|
|
86
|
-
* Only the fallback: an account's stored currency comes first (keksdose's
|
|
87
|
-
* `reporting_currency` — a de-CH speaker living in Germany pays in euros), and the payer
|
|
88
|
-
* may switch in the picker either way; checkout takes the one they leave it on (§4).
|
|
89
|
-
*/
|
|
90
|
-
export function billingCurrencyFor(locale?: string): BillingCurrency {
|
|
91
|
-
if (!locale) return "EUR";
|
|
92
|
-
try {
|
|
93
|
-
const region = new Intl.Locale(locale).maximize().region;
|
|
94
|
-
return region === "CH" || region === "LI" ? "CHF" : "EUR";
|
|
95
|
-
} catch {
|
|
96
|
-
return "EUR";
|
|
97
|
-
}
|
|
98
|
-
}
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { useKitLabels, useKitLocale } from "../i18n/kit-labels";
|
|
2
|
-
import type { LabelOverride } from "../i18n/kit-labels";
|
|
3
|
-
import { DEFAULT_COMMON_LABELS } from "../i18n/shared-labels";
|
|
4
|
-
import { pluralForm } from "../i18n/plurals";
|
|
5
|
-
import type { PluralForms } from "../i18n/plurals";
|
|
6
|
-
import { useDayFormatter } from "../lib/day-format";
|
|
7
|
-
import { formatMoney, formatNumber } from "../lib/format";
|
|
8
|
-
import { AlertBanner } from "../components/alert-banner";
|
|
9
|
-
import { Button } from "../components/button";
|
|
10
|
-
import { DialogFrame } from "../components/dialog-frame";
|
|
11
|
-
import { Spinner } from "../components/spinner";
|
|
12
|
-
import { COMMIT_EXCEPT_BILLING } from "../components/write-lock";
|
|
13
|
-
import { DEFAULT_PLAN_CHANGE_LABELS } from "./plan-change-labels";
|
|
14
|
-
import { useBillingLabels } from "./billing-labels";
|
|
15
|
-
import type { BillingLabels } from "./billing-labels";
|
|
16
|
-
import type { PlanSwitchPreview } from "./billing-overview";
|
|
17
|
-
import { minorToMajor } from "./plan-price";
|
|
18
|
-
import type { BillingInterval } from "./plan-price";
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* The payer's plan switch (docs/billing-harmonization.md §15.2.10, ui-kit 0.39): built
|
|
22
|
-
* once in the kits and used by all three apps, instead of Paddle's portal. While a
|
|
23
|
-
* provider subscription runs, the app sends a `PlanPicker` pick to
|
|
24
|
-
* `POST /billing/plan/preview` and opens this dialog with the answer; Confirm is the
|
|
25
|
-
* app's `POST /billing/plan`. Otherwise the pick goes to the checkout, as before.
|
|
26
|
-
*
|
|
27
|
-
* The switch is immediate and prorated: an upgrade charges the difference now, a
|
|
28
|
-
* downgrade credits the unused part to the customer's balance, which Paddle takes off
|
|
29
|
-
* the next charges. So the payer agrees to a figure — Paddle's preview — and sees the
|
|
30
|
-
* dimensions over the new plan's limit before agreeing (§3.4: a limit gates creation
|
|
31
|
-
* only, so the switch is allowed).
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
/** One side of a switch: a plan code and its billing period. */
|
|
35
|
-
export interface PlanSwitchSide {
|
|
36
|
-
plan: string;
|
|
37
|
-
interval: BillingInterval;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface PlanSwitchConfirmProps {
|
|
41
|
-
open: boolean;
|
|
42
|
-
/** The payer dismissed it — Cancel, Escape, the backdrop. Confirm leaves it open: close
|
|
43
|
-
* it once the switch answers. 0.52: every other kit dialog's `onClose` (CONTRIBUTING
|
|
44
|
-
* §4; refactor audit 2026-10-30, API-5); required since 0.53 removed `onOpenChange`
|
|
45
|
-
* (deprecated in 0.52). */
|
|
46
|
-
onClose: () => void;
|
|
47
|
-
/** What the payer pays now: the overview's `paid`. */
|
|
48
|
-
from: PlanSwitchSide;
|
|
49
|
-
/** The pick. */
|
|
50
|
-
to: PlanSwitchSide;
|
|
51
|
-
/** `POST /billing/plan/preview`'s answer. Undefined while it loads: a spinner, and
|
|
52
|
-
* Confirm is held. */
|
|
53
|
-
preview?: PlanSwitchPreview;
|
|
54
|
-
/** `POST /billing/plan` is under way: Confirm's spinner, no second press, and neither
|
|
55
|
-
* Escape, the backdrop nor Back closes it. */
|
|
56
|
-
pending?: boolean;
|
|
57
|
-
/** The plan's display name, the app's (§3.1). Default: the code. */
|
|
58
|
-
planName?: (code: string) => string;
|
|
59
|
-
/**
|
|
60
|
-
* The app's word per dimension, for the over-limit lines. A heading's word ("Budgets")
|
|
61
|
-
* reads "Budgets: 7 of 5" (`billing.limitUsageLine`); its plural forms
|
|
62
|
-
* (`{ one: "budget", other: "budgets" }`) read "7 of 5 budgets" (`planChange.usageOf`,
|
|
63
|
-
* the form the limit takes). A dimension without one is named by its key.
|
|
64
|
-
*/
|
|
65
|
-
dimensionLabels?: Readonly<Record<string, string | PluralForms>>;
|
|
66
|
-
/** How a usage or limit figure is written. Default: a number in the locale. */
|
|
67
|
-
formatLimit?: (dimension: string, value: number) => string;
|
|
68
|
-
/** Confirm: the app's `POST /billing/plan` with `{plan, interval}` of `to`. */
|
|
69
|
-
onConfirm: () => void;
|
|
70
|
-
/** The figures' and the date's locale. Default: the provider's. The next charge's date
|
|
71
|
-
* is written by the `<UiKitProvider formatDate>` when the app set one (0.52). */
|
|
72
|
-
locale?: string;
|
|
73
|
-
/**
|
|
74
|
-
* 0.42 (§16.2 decision 5, §16.8 B): the payer's free grant runs without an end —
|
|
75
|
-
* `isPermanentGrant(overview)`. The switch changes the PAID plan, not the applied one
|
|
76
|
-
* (§12.11), so the dialog says so above its figures (`grantWarningTitle`,
|
|
77
|
-
* `grantWarningBody`) before the payer agrees. Confirm stays Confirm: the warning is
|
|
78
|
-
* this dialog's own, and `PlanPicker` — told `switching` — shows none of its own on
|
|
79
|
-
* the way here, so the payer reads it once.
|
|
80
|
-
*/
|
|
81
|
-
permanentGrant?: boolean;
|
|
82
|
-
/** Prop > `<UiKitProvider labels={{ billing }}>` > English. */
|
|
83
|
-
labels?: LabelOverride<BillingLabels>;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* The confirm for a plan switch (§15.2.10): from → to, each with its billing period;
|
|
88
|
-
* Paddle's preview — "Charged now" (an upgrade) or "Credited towards your next charges"
|
|
89
|
-
* (a downgrade), and the next charge with its date — in the subscription's currency;
|
|
90
|
-
* the dimensions over the new plan's limit; and Confirm.
|
|
91
|
-
*
|
|
92
|
-
* const preview = useMutation({ mutationFn: api.previewPlanSwitch });
|
|
93
|
-
* <PlanSwitchConfirm
|
|
94
|
-
* open={pick !== null}
|
|
95
|
-
* onClose={() => setPick(null)}
|
|
96
|
-
* from={overview.paid}
|
|
97
|
-
* to={pick}
|
|
98
|
-
* preview={preview.data}
|
|
99
|
-
* pending={switching.isPending}
|
|
100
|
-
* planName={planName}
|
|
101
|
-
* onConfirm={() => switching.mutate(pick)}
|
|
102
|
-
* />
|
|
103
|
-
*
|
|
104
|
-
* It takes no billing lock (`COMMIT_EXCEPT_BILLING` built in): a read-only payer may
|
|
105
|
-
* change plan, as they may pay. A demo lock still holds it, as the server's demo guard
|
|
106
|
-
* does. The kit sends no request.
|
|
107
|
-
*/
|
|
108
|
-
export function PlanSwitchConfirm({
|
|
109
|
-
open,
|
|
110
|
-
onClose,
|
|
111
|
-
from,
|
|
112
|
-
to,
|
|
113
|
-
preview,
|
|
114
|
-
pending = false,
|
|
115
|
-
planName = (code) => code,
|
|
116
|
-
dimensionLabels,
|
|
117
|
-
formatLimit,
|
|
118
|
-
onConfirm,
|
|
119
|
-
locale: localeProp,
|
|
120
|
-
permanentGrant = false,
|
|
121
|
-
labels: labelsProp,
|
|
122
|
-
}: PlanSwitchConfirmProps) {
|
|
123
|
-
const labels = useBillingLabels(labelsProp);
|
|
124
|
-
const planChange = useKitLabels("planChange", DEFAULT_PLAN_CHANGE_LABELS);
|
|
125
|
-
const common = useKitLabels("common", DEFAULT_COMMON_LABELS);
|
|
126
|
-
const locale = useKitLocale(localeProp);
|
|
127
|
-
const day = useDayFormatter(undefined, localeProp);
|
|
128
|
-
|
|
129
|
-
const period = (interval: BillingInterval) => (interval === "year" ? labels.yearly : labels.monthly);
|
|
130
|
-
const side = (s: PlanSwitchSide) => `${planName(s.plan.toLowerCase())} (${period(s.interval)})`;
|
|
131
|
-
const money = (minor: number, currency: string) => formatMoney(minorToMajor(minor, currency), currency, { locale });
|
|
132
|
-
const figure = (dimension: string, value: number) =>
|
|
133
|
-
formatLimit ? formatLimit(dimension, value) : formatNumber(value, { locale });
|
|
134
|
-
|
|
135
|
-
/** One line per dimension over the new limit, in the word's own sentence. */
|
|
136
|
-
const overLimit = (p: PlanSwitchPreview): string[] =>
|
|
137
|
-
(p.over_limit ?? []).flatMap((dimension) => {
|
|
138
|
-
const limit = p.limits?.[dimension];
|
|
139
|
-
const used = p.usage?.[dimension];
|
|
140
|
-
if (limit === null || limit === undefined || used === undefined) return [];
|
|
141
|
-
const word = dimensionLabels?.[dimension] ?? dimension;
|
|
142
|
-
return [
|
|
143
|
-
typeof word === "string"
|
|
144
|
-
? labels.limitUsageLine(word, figure(dimension, used), figure(dimension, limit))
|
|
145
|
-
: planChange.usageOf(figure(dimension, used), figure(dimension, limit), pluralForm(limit, word, locale)),
|
|
146
|
-
];
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
const credit = preview !== undefined && preview.now_minor < 0;
|
|
150
|
-
const lines = preview ? overLimit(preview) : [];
|
|
151
|
-
|
|
152
|
-
return (
|
|
153
|
-
<DialogFrame
|
|
154
|
-
open={open}
|
|
155
|
-
title={labels.switchTitle}
|
|
156
|
-
description={labels.switchFromTo(side(from), side(to))}
|
|
157
|
-
onClose={onClose}
|
|
158
|
-
busy={pending}
|
|
159
|
-
// A preview that loads is busy too, but holds nothing: Cancel stays a way out.
|
|
160
|
-
aria-busy={preview === undefined || undefined}
|
|
161
|
-
actions={(close) => (
|
|
162
|
-
<>
|
|
163
|
-
<Button variant="secondary" onClick={close} disabled={pending}>
|
|
164
|
-
{common.cancel}
|
|
165
|
-
</Button>
|
|
166
|
-
<Button
|
|
167
|
-
commit={COMMIT_EXCEPT_BILLING}
|
|
168
|
-
pending={pending}
|
|
169
|
-
disabled={preview === undefined}
|
|
170
|
-
onClick={() => {
|
|
171
|
-
if (preview !== undefined && !pending) onConfirm();
|
|
172
|
-
}}
|
|
173
|
-
>
|
|
174
|
-
{labels.switchConfirm}
|
|
175
|
-
</Button>
|
|
176
|
-
</>
|
|
177
|
-
)}
|
|
178
|
-
>
|
|
179
|
-
{permanentGrant && (
|
|
180
|
-
<AlertBanner tone="warning" size="sm" data-grant-warning="">
|
|
181
|
-
<strong className="block font-medium">{labels.grantWarningTitle}</strong> {labels.grantWarningBody}
|
|
182
|
-
</AlertBanner>
|
|
183
|
-
)}
|
|
184
|
-
{preview === undefined ? (
|
|
185
|
-
<div className="flex justify-center py-4">
|
|
186
|
-
<Spinner showLabel />
|
|
187
|
-
</div>
|
|
188
|
-
) : (
|
|
189
|
-
<>
|
|
190
|
-
<dl className="grid grid-cols-[minmax(0,1fr)_auto] gap-x-4 gap-y-1 text-sm" data-plan-switch-preview>
|
|
191
|
-
<dt className="text-secondary">{credit ? labels.switchCredited : labels.switchChargedNow}</dt>
|
|
192
|
-
<dd className="text-right font-medium tabular-nums" data-now={credit ? "credit" : "charge"}>
|
|
193
|
-
{money(Math.abs(preview.now_minor), preview.currency)}
|
|
194
|
-
</dd>
|
|
195
|
-
{preview.next_billed_at && preview.next_minor != null && (
|
|
196
|
-
<>
|
|
197
|
-
<dt className="text-secondary">{labels.switchNextCharge(day(preview.next_billed_at))}</dt>
|
|
198
|
-
<dd className="text-right tabular-nums">{money(preview.next_minor, preview.currency)}</dd>
|
|
199
|
-
</>
|
|
200
|
-
)}
|
|
201
|
-
</dl>
|
|
202
|
-
{lines.length > 0 && (
|
|
203
|
-
<div className="space-y-1 text-sm" data-plan-switch-over-limit>
|
|
204
|
-
<p>{planChange.overLimit}</p>
|
|
205
|
-
<ul className="list-disc space-y-0.5 ps-5 text-secondary">
|
|
206
|
-
{lines.map((line) => (
|
|
207
|
-
<li key={line}>{line}</li>
|
|
208
|
-
))}
|
|
209
|
-
</ul>
|
|
210
|
-
</div>
|
|
211
|
-
)}
|
|
212
|
-
</>
|
|
213
|
-
)}
|
|
214
|
-
</DialogFrame>
|
|
215
|
-
);
|
|
216
|
-
}
|