@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,108 +0,0 @@
|
|
|
1
|
-
import type { ComponentPropsWithRef, ReactNode } from "react";
|
|
2
|
-
import { Card } from "../components/card";
|
|
3
|
-
import type { CardTone } from "../components/card";
|
|
4
|
-
import { cn } from "../lib/cn";
|
|
5
|
-
import { CARD_DESCRIPTION_CLASS, CARD_TITLE_CLASS } from "./settings-card-classes";
|
|
6
|
-
import { SettingsHeading, useSettingsHeadingLevel } from "./settings-heading";
|
|
7
|
-
import { useSettingsLayout } from "./settings-context";
|
|
8
|
-
|
|
9
|
-
export interface SettingsSectionProps extends Omit<ComponentPropsWithRef<"div">, "title" | "id"> {
|
|
10
|
-
/** The card's DOM id — the catalogue entry's `anchor`, the `?focus=` target. */
|
|
11
|
-
anchor: string;
|
|
12
|
-
/** The card's name: a heading at the layout's level (`h3` by default). */
|
|
13
|
-
title: ReactNode;
|
|
14
|
-
/**
|
|
15
|
-
* `false` keeps the title for screen readers only — for a card alone in a group named
|
|
16
|
-
* after it, so the page does not print the same heading twice (§3.7, keksdose's admin,
|
|
17
|
-
* dev#490/#493/#494). The heading is still there: the outline and `?focus=` need it.
|
|
18
|
-
* Default `true`.
|
|
19
|
-
*/
|
|
20
|
-
titleVisible?: boolean;
|
|
21
|
-
/** One muted line under the title. */
|
|
22
|
-
description?: ReactNode;
|
|
23
|
-
/** `danger` for the destructive cards at the end of "data" (§3.7). */
|
|
24
|
-
tone?: CardTone;
|
|
25
|
-
/** A control at the title's end — a refresh, a toggle. It drops under the title when
|
|
26
|
-
* the card is too narrow for both. */
|
|
27
|
-
action?: ReactNode;
|
|
28
|
-
children?: ReactNode;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Is this a development build? The consumer's bundler makes `import.meta.env.DEV` false in
|
|
33
|
-
* production, so the check below is dead code there. Unlike the kit's warnings it stays
|
|
34
|
-
* on under vitest: a card that cannot be found is a bug a test should fail on.
|
|
35
|
-
* Optional-chained: `import.meta.env` is a Vite injection, absent under plain Node.
|
|
36
|
-
*/
|
|
37
|
-
function devChecks(): boolean {
|
|
38
|
-
return Boolean(import.meta.env?.DEV);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* An app's own settings card (docs/settings-harmonization.md §3.7, §7.1): a kit `Card` at
|
|
43
|
-
* the settings type scale — the title `text-sm font-medium`, the description `text-xs`
|
|
44
|
-
* muted, as the kit's own setting cards — with the catalogue anchor as its id, the title
|
|
45
|
-
* as a heading under the group's, and the `?focus=` ring landing on it.
|
|
46
|
-
*
|
|
47
|
-
* **A card without a catalogue entry throws in development** (keksdose's `section()`
|
|
48
|
-
* guard). A card search cannot find breaks the rule that every setting is findable
|
|
49
|
-
* (§4.1), and the old failure was silent: a hit that scrolled nowhere. The check runs
|
|
50
|
-
* inside a {@link SettingsLayout}, which holds the catalogue; outside one there is
|
|
51
|
-
* nothing to check against.
|
|
52
|
-
*/
|
|
53
|
-
export function SettingsSection({
|
|
54
|
-
anchor,
|
|
55
|
-
title,
|
|
56
|
-
titleVisible = true,
|
|
57
|
-
description,
|
|
58
|
-
tone,
|
|
59
|
-
action,
|
|
60
|
-
children,
|
|
61
|
-
className,
|
|
62
|
-
...rest
|
|
63
|
-
}: SettingsSectionProps) {
|
|
64
|
-
const layout = useSettingsLayout();
|
|
65
|
-
const level = useSettingsHeadingLevel() ?? "h3";
|
|
66
|
-
if (layout && devChecks() && !layout.hasAnchor(anchor)) {
|
|
67
|
-
throw new Error(
|
|
68
|
-
`SettingsSection "${anchor}" has no catalogue entry: add a SettingsEntry with anchor "${anchor}" so search and ?focus= can reach it.`,
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
const heading = (
|
|
72
|
-
<SettingsHeading
|
|
73
|
-
as={level}
|
|
74
|
-
// Focusable from script only: `?focus=` moves focus here (§3.5).
|
|
75
|
-
tabIndex={-1}
|
|
76
|
-
data-settings-heading=""
|
|
77
|
-
className={cn(CARD_TITLE_CLASS, "outline-none", !titleVisible && "sr-only-fixed")}
|
|
78
|
-
>
|
|
79
|
-
{title}
|
|
80
|
-
</SettingsHeading>
|
|
81
|
-
);
|
|
82
|
-
const header =
|
|
83
|
-
titleVisible || description != null || action != null ? (
|
|
84
|
-
<div className="flex flex-wrap items-start justify-between gap-x-3 gap-y-2">
|
|
85
|
-
<div className="min-w-0 flex-1 basis-48">
|
|
86
|
-
{heading}
|
|
87
|
-
{description != null && <div className={CARD_DESCRIPTION_CLASS}>{description}</div>}
|
|
88
|
-
</div>
|
|
89
|
-
{action != null && <div className="flex shrink-0 items-center gap-2">{action}</div>}
|
|
90
|
-
</div>
|
|
91
|
-
) : (
|
|
92
|
-
heading
|
|
93
|
-
);
|
|
94
|
-
return (
|
|
95
|
-
<Card
|
|
96
|
-
{...rest}
|
|
97
|
-
id={anchor}
|
|
98
|
-
tone={tone}
|
|
99
|
-
// A column with a gap, not `space-y-3`: a hidden title is `position: fixed` and so
|
|
100
|
-
// out of the flow, and a gap is only drawn between items in it — `space-y` would
|
|
101
|
-
// still push the first card part down by a gap for the title nobody sees.
|
|
102
|
-
className={cn("flex flex-col gap-3 p-4 transition-shadow motion-reduce:transition-none", className)}
|
|
103
|
-
>
|
|
104
|
-
{header}
|
|
105
|
-
{children}
|
|
106
|
-
</Card>
|
|
107
|
-
);
|
|
108
|
-
}
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { useCallback, useMemo } from "react";
|
|
2
|
-
import { isTextSize, resolveTextSize } from "../theme/text-size";
|
|
3
|
-
import type { TextSize } from "../theme/text-size";
|
|
4
|
-
import { isContrastMode, resolveContrastMode } from "../theme/contrast";
|
|
5
|
-
import type { ContrastMode } from "../theme/contrast";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* The text size and contrast follow the account like the language does
|
|
9
|
-
* (docs/text-size-harmonization.md §2.2, §2.6, §6; settings contract §6.2) — the same
|
|
10
|
-
* rule as {@link useAccountLanguage}, for two values at once.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/** Where a value in force came from, in the order they are asked. */
|
|
14
|
-
export type AppearanceSource = "device" | "account" | "default";
|
|
15
|
-
|
|
16
|
-
/** The two fields of an `/auth/me` answer this reads — server-kit 0.6's `UserResponse`,
|
|
17
|
-
* both nullable (null = never chosen). */
|
|
18
|
-
export interface AccountAppearanceFields {
|
|
19
|
-
text_size?: string | null;
|
|
20
|
-
contrast?: string | null;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/** This device's own choices — the text-size and contrast stores' values, `null` where
|
|
24
|
-
* this device never chose. */
|
|
25
|
-
export interface DeviceAppearance {
|
|
26
|
-
textSize?: string | null;
|
|
27
|
-
contrast?: string | null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** The body of `PATCH /auth/me` for a pick: one field, as server-kit's `ProfileUpdate`
|
|
31
|
-
* spells it. */
|
|
32
|
-
export type AccountAppearancePatch = { text_size: TextSize } | { contrast: ContrastMode };
|
|
33
|
-
|
|
34
|
-
export interface ResolvedAccountAppearance {
|
|
35
|
-
textSize: TextSize;
|
|
36
|
-
/** The stored MODE — "system" included — not whether more contrast is on now. */
|
|
37
|
-
contrast: ContrastMode;
|
|
38
|
-
sources: { textSize: AppearanceSource; contrast: AppearanceSource };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function source(device: boolean, account: boolean): AppearanceSource {
|
|
42
|
-
return device ? "device" : account ? "account" : "default";
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* The values on a device (§2.6): **its own choice → the account's → the default**
|
|
47
|
-
* (Normal; "system" for contrast), each taken only when it is a known value. Pure.
|
|
48
|
-
*/
|
|
49
|
-
export function resolveAccountAppearance(
|
|
50
|
-
device: DeviceAppearance,
|
|
51
|
-
account: AccountAppearanceFields | null | undefined,
|
|
52
|
-
): ResolvedAccountAppearance {
|
|
53
|
-
return {
|
|
54
|
-
textSize: resolveTextSize(device.textSize, account?.text_size),
|
|
55
|
-
contrast: resolveContrastMode(device.contrast, account?.contrast),
|
|
56
|
-
sources: {
|
|
57
|
-
textSize: source(isTextSize(device.textSize), isTextSize(account?.text_size)),
|
|
58
|
-
contrast: source(isContrastMode(device.contrast), isContrastMode(account?.contrast)),
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export interface UseAccountAppearanceOptions {
|
|
64
|
-
/** The signed-in account (`/auth/me`), or `null` / `undefined` while signed out or not
|
|
65
|
-
* loaded yet — then nothing is saved to it. */
|
|
66
|
-
account: AccountAppearanceFields | null | undefined;
|
|
67
|
-
/** This device's own choices: `useTextSizeStore((s) => s.size)` and
|
|
68
|
-
* `useContrastStore((s) => s.contrast)`. */
|
|
69
|
-
device: DeviceAppearance;
|
|
70
|
-
/** Store a device choice: `(patch) => { if (patch.textSize) setSize(patch.textSize);
|
|
71
|
-
* if (patch.contrast) setContrast(patch.contrast); }`. */
|
|
72
|
-
setDevice: (patch: { textSize?: TextSize; contrast?: ContrastMode }) => void;
|
|
73
|
-
/** Write the account: `PATCH /auth/me` with the patch as its body. Return its promise. */
|
|
74
|
-
save: (patch: AccountAppearancePatch) => unknown;
|
|
75
|
-
/** A demo session: a pick stays on the device, the account is never written (§6). */
|
|
76
|
-
isDemo?: boolean;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export interface AccountAppearance extends ResolvedAccountAppearance {
|
|
80
|
-
/** The user picked a size: it becomes the device's choice and — signed in, and not a
|
|
81
|
-
* demo — the account's. The promise is `save`'s; the device keeps the pick if it
|
|
82
|
-
* fails, and the app says so (`appearance.saveFailed`, 0.32.1). */
|
|
83
|
-
pickTextSize: (size: TextSize) => Promise<unknown>;
|
|
84
|
-
/** As {@link pickTextSize}, for the contrast mode. */
|
|
85
|
-
pickContrast: (mode: ContrastMode) => Promise<unknown>;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* The account's text size and contrast on this device (§6): the order of
|
|
90
|
-
* {@link resolveAccountAppearance}, and the writes.
|
|
91
|
-
*
|
|
92
|
-
* - **Nothing writes the account on its own.** Rendering, signing in and adopting the
|
|
93
|
-
* account's values call neither `save` nor `setDevice`, so a new device adopts the
|
|
94
|
-
* account instead of overwriting it.
|
|
95
|
-
* - **A pick** writes the device's choice, then `save` — except in a demo session or
|
|
96
|
-
* signed out.
|
|
97
|
-
*
|
|
98
|
-
* The hook only answers. The values are put in force by the stores' apply hooks, which
|
|
99
|
-
* resolve the same order from the same inputs:
|
|
100
|
-
*
|
|
101
|
-
* ```tsx
|
|
102
|
-
* useApplyTextSize({ account: me?.text_size });
|
|
103
|
-
* useApplyContrast({ account: me?.contrast });
|
|
104
|
-
* ```
|
|
105
|
-
*/
|
|
106
|
-
export function useAccountAppearance(options: UseAccountAppearanceOptions): AccountAppearance {
|
|
107
|
-
const { account, device, setDevice, save, isDemo = false } = options;
|
|
108
|
-
const deviceTextSize = device.textSize;
|
|
109
|
-
const deviceContrast = device.contrast;
|
|
110
|
-
const accountTextSize = account?.text_size;
|
|
111
|
-
const accountContrast = account?.contrast;
|
|
112
|
-
const signedIn = account !== null && account !== undefined;
|
|
113
|
-
// By value, so a fresh `/auth/me` object with the same two fields changes nothing.
|
|
114
|
-
const resolved = useMemo(
|
|
115
|
-
() =>
|
|
116
|
-
resolveAccountAppearance(
|
|
117
|
-
{ textSize: deviceTextSize, contrast: deviceContrast },
|
|
118
|
-
signedIn ? { text_size: accountTextSize, contrast: accountContrast } : undefined,
|
|
119
|
-
),
|
|
120
|
-
[deviceTextSize, deviceContrast, signedIn, accountTextSize, accountContrast],
|
|
121
|
-
);
|
|
122
|
-
const write = useCallback(
|
|
123
|
-
(patch: AccountAppearancePatch) => {
|
|
124
|
-
if (isDemo || !signedIn) return Promise.resolve();
|
|
125
|
-
try {
|
|
126
|
-
return Promise.resolve(save(patch));
|
|
127
|
-
} catch (error) {
|
|
128
|
-
return Promise.reject(error);
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
[save, isDemo, signedIn],
|
|
132
|
-
);
|
|
133
|
-
const pickTextSize = useCallback(
|
|
134
|
-
(size: TextSize) => {
|
|
135
|
-
setDevice({ textSize: size });
|
|
136
|
-
return write({ text_size: size });
|
|
137
|
-
},
|
|
138
|
-
[setDevice, write],
|
|
139
|
-
);
|
|
140
|
-
const pickContrast = useCallback(
|
|
141
|
-
(mode: ContrastMode) => {
|
|
142
|
-
setDevice({ contrast: mode });
|
|
143
|
-
return write({ contrast: mode });
|
|
144
|
-
},
|
|
145
|
-
[setDevice, write],
|
|
146
|
-
);
|
|
147
|
-
return { ...resolved, pickTextSize, pickContrast };
|
|
148
|
-
}
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { useCallback, useMemo } from "react";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Where the language on screen came from (docs/settings-harmonization.md §6.2), in the
|
|
5
|
-
* order they are asked.
|
|
6
|
-
*/
|
|
7
|
-
export type AccountLanguageSource = "device" | "account" | "browser" | "default";
|
|
8
|
-
|
|
9
|
-
/** `de_ch`, `DE-ch` → `de-CH`: the case and separator a BCP 47 tag is written in. */
|
|
10
|
-
function canonicalTag(tag: string): string {
|
|
11
|
-
const parts = tag.trim().replace(/_/g, "-").split("-").filter(Boolean);
|
|
12
|
-
return parts
|
|
13
|
-
.map((part, i) => {
|
|
14
|
-
if (i === 0) return part.toLowerCase();
|
|
15
|
-
if (part.length === 2) return part.toUpperCase();
|
|
16
|
-
if (part.length === 4) return part[0].toUpperCase() + part.slice(1).toLowerCase();
|
|
17
|
-
return part.toLowerCase();
|
|
18
|
-
})
|
|
19
|
-
.join("-");
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* The offered language a tag means, or `null` — the client's half of server-kit's
|
|
24
|
-
* `canonical_locale(tag, offered)` (§6.2): case and `_` normalised; an offered tag matches
|
|
25
|
-
* exactly; otherwise the first offered tag of the same language (`de`, `de-DE` → `de-CH`
|
|
26
|
-
* where `de-CH` is what the app offers); anything else is no match.
|
|
27
|
-
*/
|
|
28
|
-
export function matchOfferedLanguage(tag: string | null | undefined, offered: readonly string[]): string | null {
|
|
29
|
-
if (!tag || !tag.trim()) return null;
|
|
30
|
-
const wanted = canonicalTag(tag);
|
|
31
|
-
const exact = offered.find((code) => canonicalTag(code) === wanted);
|
|
32
|
-
if (exact !== undefined) return exact;
|
|
33
|
-
const language = wanted.split("-")[0];
|
|
34
|
-
return offered.find((code) => canonicalTag(code).split("-")[0] === language) ?? null;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface ResolveAccountLanguageInput {
|
|
38
|
-
/** This device's own choice — made on this device, stored only when the user picks. */
|
|
39
|
-
device: string | null | undefined;
|
|
40
|
-
/** The signed-in account's `locale`; `undefined` while signed out. */
|
|
41
|
-
account: string | null | undefined;
|
|
42
|
-
/** The browser's languages, most wanted first (`navigator.languages`). */
|
|
43
|
-
browser?: readonly string[];
|
|
44
|
-
/** The languages the app offers. */
|
|
45
|
-
offered: readonly string[];
|
|
46
|
-
/** The app's default, when nothing else matches. */
|
|
47
|
-
fallback: string;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface ResolvedAccountLanguage {
|
|
51
|
-
language: string;
|
|
52
|
-
source: AccountLanguageSource;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* The language on a device (§6.2): **its own choice → the account's locale → the
|
|
57
|
-
* browser's language → the app's default**, each taken only when it names a language the
|
|
58
|
-
* app offers. Pure: the order, without the storage.
|
|
59
|
-
*
|
|
60
|
-
* "At sign-in the account applies unless the device has its own choice" is this order and
|
|
61
|
-
* nothing more: once the account's locale arrives it outranks the browser, never the
|
|
62
|
-
* device's pick.
|
|
63
|
-
*/
|
|
64
|
-
export function resolveAccountLanguage(input: ResolveAccountLanguageInput): ResolvedAccountLanguage {
|
|
65
|
-
const { device, account, browser = [], offered, fallback } = input;
|
|
66
|
-
const fromDevice = matchOfferedLanguage(device, offered);
|
|
67
|
-
if (fromDevice) return { language: fromDevice, source: "device" };
|
|
68
|
-
const fromAccount = matchOfferedLanguage(account, offered);
|
|
69
|
-
if (fromAccount) return { language: fromAccount, source: "account" };
|
|
70
|
-
for (const tag of browser) {
|
|
71
|
-
const fromBrowser = matchOfferedLanguage(tag, offered);
|
|
72
|
-
if (fromBrowser) return { language: fromBrowser, source: "browser" };
|
|
73
|
-
}
|
|
74
|
-
return { language: fallback, source: "default" };
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface UseAccountLanguageOptions {
|
|
78
|
-
/** The signed-in account's `locale` (`/auth/me`). `undefined` while signed out or not
|
|
79
|
-
* loaded yet; `null` for an account with no language set. */
|
|
80
|
-
account: string | null | undefined;
|
|
81
|
-
/** This device's own choice — `<app>-lang` — or `null` when it was never picked here.
|
|
82
|
-
* Detection must not fill it (i18next's detector with `caches: []`, §6.2). */
|
|
83
|
-
device: string | null | undefined;
|
|
84
|
-
/** Store the device's own choice (`<app>-lang`). */
|
|
85
|
-
setDevice: (code: string) => void;
|
|
86
|
-
/** Write the account's locale: `PATCH /auth/me {locale}`. Return its promise. */
|
|
87
|
-
save: (code: string) => unknown;
|
|
88
|
-
/** A demo session: a pick stays on the device, the account is never written (§6.2). */
|
|
89
|
-
isDemo?: boolean;
|
|
90
|
-
/** The languages the app offers, as it writes them. */
|
|
91
|
-
offered: readonly string[];
|
|
92
|
-
/** The app's default language. */
|
|
93
|
-
fallback: string;
|
|
94
|
-
/** The browser's languages. Default: `navigator.languages`. */
|
|
95
|
-
browser?: readonly string[];
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export interface AccountLanguage extends ResolvedAccountLanguage {
|
|
99
|
-
/**
|
|
100
|
-
* The user picked `code` (the language card, the top bar's quick switch): it becomes the
|
|
101
|
-
* device's own choice and — signed in, and not a demo — the account's locale. The
|
|
102
|
-
* promise is `save`'s; the device keeps the pick if it fails, and the app says so.
|
|
103
|
-
*/
|
|
104
|
-
pick: (code: string) => Promise<unknown>;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function navigatorLanguages(): readonly string[] {
|
|
108
|
-
if (typeof navigator === "undefined") return [];
|
|
109
|
-
return navigator.languages?.length ? navigator.languages : navigator.language ? [navigator.language] : [];
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* The account's language on this device (§6.2, §10.8): the order of
|
|
114
|
-
* {@link resolveAccountLanguage}, and the writes — so the three apps' copies go.
|
|
115
|
-
*
|
|
116
|
-
* - **Nothing writes the account on its own.** Rendering, signing in and adopting the
|
|
117
|
-
* account's locale call neither `save` nor `setDevice`; keksdose's
|
|
118
|
-
* `useSyncLanguageToAccount` (a PATCH on every session start) overwrote the account
|
|
119
|
-
* from a new device before that device could adopt it.
|
|
120
|
-
* - **A pick** writes the device's choice, then `save` — except in a demo session, whose
|
|
121
|
-
* throwaway account needs no language (and model R refuses the write).
|
|
122
|
-
*
|
|
123
|
-
* The hook only answers; the app applies `language` (`i18n.changeLanguage`) where it
|
|
124
|
-
* applies languages today.
|
|
125
|
-
*/
|
|
126
|
-
export function useAccountLanguage(options: UseAccountLanguageOptions): AccountLanguage {
|
|
127
|
-
const { account, device, setDevice, save, isDemo = false, offered, fallback, browser } = options;
|
|
128
|
-
const resolved = useMemo(
|
|
129
|
-
() => resolveAccountLanguage({ device, account, browser: browser ?? navigatorLanguages(), offered, fallback }),
|
|
130
|
-
[device, account, browser, offered, fallback],
|
|
131
|
-
);
|
|
132
|
-
const signedIn = account !== undefined;
|
|
133
|
-
const pick = useCallback(
|
|
134
|
-
(code: string) => {
|
|
135
|
-
setDevice(code);
|
|
136
|
-
if (isDemo || !signedIn) return Promise.resolve();
|
|
137
|
-
try {
|
|
138
|
-
return Promise.resolve(save(code));
|
|
139
|
-
} catch (error) {
|
|
140
|
-
return Promise.reject(error);
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
[setDevice, save, isDemo, signedIn],
|
|
144
|
-
);
|
|
145
|
-
return { ...resolved, pick };
|
|
146
|
-
}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef } from "react";
|
|
2
|
-
import { useLocation, useNavigate } from "react-router";
|
|
3
|
-
import { prefersReducedMotion } from "../lib/reduced-motion";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* The ring a `?focus=` target wears for {@link SETTINGS_FOCUS_MS} — keksdose's
|
|
7
|
-
* `HIGHLIGHT`, in tokens: `--brand` for the ring and the page's own surface for the gap,
|
|
8
|
-
* where keksdose named a slate for the dark theme. A ring rather than a background
|
|
9
|
-
* flash: the destructive cards already own a background tint, and a ring reads the same
|
|
10
|
-
* on every card.
|
|
11
|
-
*/
|
|
12
|
-
export const SETTINGS_FOCUS_RING = ["ring-2", "ring-brand", "ring-offset-2", "ring-offset-page"];
|
|
13
|
-
|
|
14
|
-
/** How long the ring stays (§3.5). */
|
|
15
|
-
export const SETTINGS_FOCUS_MS = 1800;
|
|
16
|
-
|
|
17
|
-
/** How long a target that is not on the page yet (a lazy card, a card waiting for its
|
|
18
|
-
* data) is waited for before the hook gives up on it. */
|
|
19
|
-
const WAIT_MS = 5000;
|
|
20
|
-
|
|
21
|
-
const HEADING = "[data-settings-heading], h1, h2, h3, h4, h5, h6";
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* `?focus=<anchor>` (docs/settings-harmonization.md §3.5): scroll the card into view, ring
|
|
25
|
-
* it for 1.8 s, move focus to its heading for a screen reader, then remove `focus` — and
|
|
26
|
-
* ONLY `focus` — with a replace, so a reload does not ring it again. Every other
|
|
27
|
-
* parameter stays: a tour's `tour` / `tourStep`, the admin roster's filters (dropping URL
|
|
28
|
-
* parts broke keksdose's tours once, dev#495). The hash and `location.state` stay too.
|
|
29
|
-
*
|
|
30
|
-
* A search hit, ⌘K, a tour and a mail link all arrive this way. `SettingsLayout` calls it
|
|
31
|
-
* for its own page; an app's own page can call it with no argument to act on its URL.
|
|
32
|
-
*
|
|
33
|
-
* `anchor`:
|
|
34
|
-
* - left out: the URL's `focus` parameter;
|
|
35
|
-
* - a string: that anchor (the layout passes the URL's, once its route is canonical);
|
|
36
|
-
* - `null`: nothing to do yet — the layout passes it while the address is about to be
|
|
37
|
-
* replaced, so a removal here cannot undo a redirect there.
|
|
38
|
-
*
|
|
39
|
-
* "Once its group has rendered": the effect runs after the commit that mounted the
|
|
40
|
-
* group's cards, so the card is there; a card that mounts later (lazy, or behind its
|
|
41
|
-
* data) is waited for, for a few seconds, before the hook gives up and leaves the URL
|
|
42
|
-
* as it is.
|
|
43
|
-
*/
|
|
44
|
-
export function useSettingsFocus(anchor?: string | null): void {
|
|
45
|
-
const location = useLocation();
|
|
46
|
-
const navigate = useNavigate();
|
|
47
|
-
const target = anchor === undefined ? new URLSearchParams(location.search).get("focus") : anchor;
|
|
48
|
-
// The ring outlives the effect that drew it: removing `focus` from the URL re-runs the
|
|
49
|
-
// effect (and cleans it up) at once, and the ring must still stay its 1.8 s.
|
|
50
|
-
const ring = useRef<{ el: HTMLElement; timer: number } | null>(null);
|
|
51
|
-
|
|
52
|
-
useEffect(() => {
|
|
53
|
-
if (!target) return;
|
|
54
|
-
const { pathname, search, hash, state } = location;
|
|
55
|
-
|
|
56
|
-
const land = (el: HTMLElement) => {
|
|
57
|
-
el.scrollIntoView?.({ behavior: prefersReducedMotion() ? "auto" : "smooth", block: "center" });
|
|
58
|
-
|
|
59
|
-
if (ring.current) {
|
|
60
|
-
window.clearTimeout(ring.current.timer);
|
|
61
|
-
ring.current.el.classList.remove(...SETTINGS_FOCUS_RING);
|
|
62
|
-
// The mark goes with the ring, as the timer's own end takes both: left behind, the
|
|
63
|
-
// first card stayed "focused" for good (keksdose's matching-tab test reads it).
|
|
64
|
-
ring.current.el.removeAttribute("data-settings-focus");
|
|
65
|
-
}
|
|
66
|
-
el.classList.add(...SETTINGS_FOCUS_RING);
|
|
67
|
-
el.setAttribute("data-settings-focus", "");
|
|
68
|
-
const timer = window.setTimeout(() => {
|
|
69
|
-
el.classList.remove(...SETTINGS_FOCUS_RING);
|
|
70
|
-
el.removeAttribute("data-settings-focus");
|
|
71
|
-
if (ring.current?.el === el) ring.current = null;
|
|
72
|
-
}, SETTINGS_FOCUS_MS);
|
|
73
|
-
ring.current = { el, timer };
|
|
74
|
-
|
|
75
|
-
// The heading, so a screen reader starts at the card's name; the card itself when
|
|
76
|
-
// it has none. `preventScroll`: the smooth scroll above is already on its way.
|
|
77
|
-
const heading = el.querySelector<HTMLElement>(HEADING) ?? el;
|
|
78
|
-
if (!heading.hasAttribute("tabindex")) heading.setAttribute("tabindex", "-1");
|
|
79
|
-
heading.focus({ preventScroll: true });
|
|
80
|
-
|
|
81
|
-
const params = new URLSearchParams(search);
|
|
82
|
-
if (params.get("focus") !== target) return;
|
|
83
|
-
params.delete("focus");
|
|
84
|
-
const rest = params.toString();
|
|
85
|
-
navigate({ pathname, search: rest ? `?${rest}` : "", hash }, { replace: true, state });
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const found = document.getElementById(target);
|
|
89
|
-
if (found) {
|
|
90
|
-
land(found);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
const observer = new MutationObserver(() => {
|
|
94
|
-
const el = document.getElementById(target);
|
|
95
|
-
if (!el) return;
|
|
96
|
-
observer.disconnect();
|
|
97
|
-
window.clearTimeout(giveUp);
|
|
98
|
-
land(el);
|
|
99
|
-
});
|
|
100
|
-
observer.observe(document.body, { childList: true, subtree: true });
|
|
101
|
-
const giveUp = window.setTimeout(() => observer.disconnect(), WAIT_MS);
|
|
102
|
-
return () => {
|
|
103
|
-
observer.disconnect();
|
|
104
|
-
window.clearTimeout(giveUp);
|
|
105
|
-
};
|
|
106
|
-
// `location`, a new object per navigation: the same hit picked twice is two
|
|
107
|
-
// navigations, and rings twice.
|
|
108
|
-
}, [target, location, navigate]);
|
|
109
|
-
|
|
110
|
-
useEffect(
|
|
111
|
-
() => () => {
|
|
112
|
-
const current = ring.current;
|
|
113
|
-
if (!current) return;
|
|
114
|
-
window.clearTimeout(current.timer);
|
|
115
|
-
current.el.classList.remove(...SETTINGS_FOCUS_RING);
|
|
116
|
-
current.el.removeAttribute("data-settings-focus");
|
|
117
|
-
},
|
|
118
|
-
[],
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* {@link useSettingsFocus} under a name for any page (0.51.4, keksdose run 89): the hook
|
|
124
|
-
* was always allowed on an app's own pages (keksdose's /reports/matching lands
|
|
125
|
-
* `?focus=matching-unmatched` on a card), but its name said Settings at every such call
|
|
126
|
-
* site. The same function, so the two cannot drift; `useSettingsFocus` stays.
|
|
127
|
-
*/
|
|
128
|
-
export const useFocusParam: typeof useSettingsFocus = useSettingsFocus;
|