@eifi1/ui-kit 0.51.6 → 0.52.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 +146 -26
- package/dist/account/account-parts.d.ts +10 -8
- package/dist/account/account-parts.js +1 -18
- package/dist/account/account-parts.js.map +1 -1
- package/dist/account/data-export-setting-labels.js +1 -1
- package/dist/account/data-export-setting-labels.js.map +1 -1
- package/dist/account/delete-account-setting-labels.js +1 -1
- package/dist/account/delete-account-setting-labels.js.map +1 -1
- package/dist/account/email-change-setting-labels.js +1 -1
- package/dist/account/email-change-setting-labels.js.map +1 -1
- package/dist/account/passkeys-setting.d.ts +9 -2
- package/dist/account/passkeys-setting.js +41 -29
- package/dist/account/passkeys-setting.js.map +1 -1
- package/dist/account/sessions-setting.d.ts +3 -2
- package/dist/account/sessions-setting.js +10 -8
- package/dist/account/sessions-setting.js.map +1 -1
- package/dist/admin/admin-action-confirm.js +3 -7
- package/dist/admin/admin-action-confirm.js.map +1 -1
- package/dist/admin/admin-parts.d.ts +6 -3
- package/dist/admin/admin-parts.js +6 -21
- package/dist/admin/admin-parts.js.map +1 -1
- package/dist/admin/mail-test-card-labels.js +1 -1
- package/dist/admin/mail-test-card-labels.js.map +1 -1
- package/dist/admin/plan-change-labels.d.ts +2 -2
- package/dist/admin/plan-change-labels.js +1 -17
- package/dist/admin/plan-change-labels.js.map +1 -1
- package/dist/admin/plan-change.d.ts +3 -42
- package/dist/admin/plan-change.js +1 -1
- package/dist/admin/plan-change.js.map +1 -1
- package/dist/admin/reviewer-scope-editor.js +3 -3
- package/dist/admin/reviewer-scope-editor.js.map +1 -1
- package/dist/auth/auth-errors-labels.d.ts +11 -0
- package/dist/auth/auth-errors-labels.js +13 -0
- package/dist/auth/auth-errors-labels.js.map +1 -0
- package/dist/auth/auth-errors.d.ts +7 -23
- package/dist/auth/auth-errors.js +2 -15
- package/dist/auth/auth-errors.js.map +1 -1
- package/dist/auth/complete-name-dialog.d.ts +3 -2
- package/dist/auth/complete-name-dialog.js +3 -5
- package/dist/auth/complete-name-dialog.js.map +1 -1
- package/dist/auth/forgot-password-form-labels.js +1 -1
- package/dist/auth/forgot-password-form-labels.js.map +1 -1
- package/dist/auth/forgot-password-form.js +7 -2
- package/dist/auth/forgot-password-form.js.map +1 -1
- package/dist/auth/register-form-labels.js +1 -1
- package/dist/auth/register-form-labels.js.map +1 -1
- package/dist/auth/reset-password-form-labels.js +1 -1
- package/dist/auth/reset-password-form-labels.js.map +1 -1
- package/dist/auth/reset-password-form.js +5 -1
- package/dist/auth/reset-password-form.js.map +1 -1
- package/dist/auth/sign-in-form-labels.js +1 -1
- package/dist/auth/sign-in-form-labels.js.map +1 -1
- package/dist/auth/status-parts.d.ts +0 -3
- package/dist/auth/status-parts.js +0 -4
- package/dist/auth/status-parts.js.map +1 -1
- package/dist/auth/verify-email-labels.js +1 -1
- package/dist/auth/verify-email-labels.js.map +1 -1
- package/dist/auth/verify-email.js +7 -2
- package/dist/auth/verify-email.js.map +1 -1
- package/dist/billing/cancel-request.d.ts +11 -2
- package/dist/billing/cancel-request.js +15 -3
- package/dist/billing/cancel-request.js.map +1 -1
- package/dist/billing/cancel-subscription.d.ts +22 -10
- package/dist/billing/cancel-subscription.js +8 -11
- package/dist/billing/cancel-subscription.js.map +1 -1
- package/dist/billing/dialog-close.d.ts +29 -0
- package/dist/billing/dialog-close.js +8 -0
- package/dist/billing/dialog-close.js.map +1 -0
- package/dist/billing/plan-card.d.ts +14 -4
- package/dist/billing/plan-card.js +15 -8
- package/dist/billing/plan-card.js.map +1 -1
- package/dist/billing/plan-change-labels.d.ts +42 -0
- package/dist/billing/plan-change-labels.js +22 -0
- package/dist/billing/plan-change-labels.js.map +1 -0
- package/dist/billing/plan-switch.d.ts +21 -9
- package/dist/billing/plan-switch.js +10 -8
- package/dist/billing/plan-switch.js.map +1 -1
- package/dist/chart.d.ts +12 -0
- package/dist/chart.js +16 -1
- package/dist/chart.js.map +1 -1
- package/dist/components/account-chips.d.ts +5 -5
- package/dist/components/account-chips.js +11 -13
- package/dist/components/account-chips.js.map +1 -1
- package/dist/components/alert-banner.d.ts +16 -5
- package/dist/components/alert-banner.js +46 -1
- package/dist/components/alert-banner.js.map +1 -1
- package/dist/components/amount-input.d.ts +22 -4
- package/dist/components/amount-input.js +3 -3
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.js +57 -65
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/bulk-action-bar.d.ts +12 -2
- package/dist/components/bulk-action-bar.js +65 -21
- package/dist/components/bulk-action-bar.js.map +1 -1
- package/dist/components/button-look.d.ts +5 -5
- package/dist/components/button-look.js.map +1 -1
- package/dist/components/button.d.ts +2 -2
- package/dist/components/button.js.map +1 -1
- package/dist/components/calculator.d.ts +21 -2
- package/dist/components/calculator.js +53 -14
- package/dist/components/calculator.js.map +1 -1
- package/dist/components/chart-edge.d.ts +16 -0
- package/dist/components/chart-edge.js +14 -1
- package/dist/components/chart-edge.js.map +1 -1
- package/dist/components/chart-figure.d.ts +13 -0
- package/dist/components/chart-figure.js +15 -0
- package/dist/components/chart-figure.js.map +1 -0
- package/dist/components/chart-zoom-core.js +1 -4
- package/dist/components/chart-zoom-core.js.map +1 -1
- package/dist/components/chart.d.ts +8 -1
- package/dist/components/chart.js +19 -10
- package/dist/components/chart.js.map +1 -1
- package/dist/components/combobox-core.d.ts +119 -7
- package/dist/components/combobox-core.js +151 -46
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +1 -1
- package/dist/components/combobox.js +142 -131
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/copy-button.d.ts +6 -5
- package/dist/components/copy-button.js +5 -3
- package/dist/components/copy-button.js.map +1 -1
- package/dist/components/country-select.js +2 -2
- package/dist/components/country-select.js.map +1 -1
- package/dist/components/data-table-column-settings.d.ts +1 -1
- package/dist/components/data-table-column-settings.js +33 -7
- package/dist/components/data-table-column-settings.js.map +1 -1
- package/dist/components/data-table-filters.d.ts +4 -2
- package/dist/components/data-table-filters.js +2 -2
- package/dist/components/data-table-filters.js.map +1 -1
- package/dist/components/data-table-fit.d.ts +6 -4
- package/dist/components/data-table-fit.js +4 -1
- package/dist/components/data-table-fit.js.map +1 -1
- package/dist/components/data-table-groups.d.ts +1 -1
- package/dist/components/data-table-groups.js.map +1 -1
- package/dist/components/data-table-head.d.ts +1 -1
- package/dist/components/data-table-head.js +15 -12
- package/dist/components/data-table-head.js.map +1 -1
- package/dist/components/data-table-mobile.d.ts +36 -7
- package/dist/components/data-table-mobile.js +63 -31
- package/dist/components/data-table-mobile.js.map +1 -1
- package/dist/components/data-table-pagination.js +11 -6
- package/dist/components/data-table-pagination.js.map +1 -1
- package/dist/components/data-table-resize.d.ts +1 -1
- package/dist/components/data-table-resize.js.map +1 -1
- package/dist/components/data-table-row-actions.d.ts +2 -2
- package/dist/components/data-table-row-actions.js.map +1 -1
- package/dist/components/data-table-row.d.ts +6 -2
- package/dist/components/data-table-row.js +17 -10
- package/dist/components/data-table-row.js.map +1 -1
- package/dist/components/data-table-selection.d.ts +1 -1
- package/dist/components/data-table-selection.js.map +1 -1
- package/dist/components/data-table-shared.d.ts +10 -2
- package/dist/components/data-table-shared.js +18 -0
- package/dist/components/data-table-shared.js.map +1 -1
- package/dist/components/data-table-sort.d.ts +21 -2
- package/dist/components/data-table-sort.js +24 -0
- package/dist/components/data-table-sort.js.map +1 -1
- package/dist/components/data-table-virtual.d.ts +1 -1
- package/dist/components/data-table-virtual.js +18 -6
- package/dist/components/data-table-virtual.js.map +1 -1
- package/dist/components/data-table.d.ts +25 -8
- package/dist/components/data-table.js +154 -25
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-field.d.ts +24 -2
- package/dist/components/date-field.js +33 -8
- package/dist/components/date-field.js.map +1 -1
- package/dist/components/date-picker.d.ts +15 -2
- package/dist/components/date-picker.js +55 -26
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/date-range-picker.d.ts +47 -20
- package/dist/components/date-range-picker.js +23 -7
- package/dist/components/date-range-picker.js.map +1 -1
- package/dist/components/dialog-frame.d.ts +2 -1
- package/dist/components/dialog-frame.js.map +1 -1
- package/dist/components/entity-combobox.js +4 -2
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/error-boundary.js +37 -30
- package/dist/components/error-boundary.js.map +1 -1
- package/dist/components/{ui-labels.d.ts → field-base-labels.d.ts} +0 -2
- package/dist/components/{ui-labels.js → field-base-labels.js} +2 -9
- package/dist/components/field-base-labels.js.map +1 -0
- package/dist/components/field-base.d.ts +4 -3
- package/dist/components/field-base.js +3 -3
- package/dist/components/field-base.js.map +1 -1
- package/dist/components/field-sync-labels.d.ts +1 -0
- package/dist/components/field-sync-labels.js.map +1 -1
- package/dist/components/field-sync.d.ts +23 -1
- package/dist/components/field-sync.js.map +1 -1
- package/dist/components/form-actions.js +11 -5
- package/dist/components/form-actions.js.map +1 -1
- package/dist/components/hover-menu.d.ts +3 -0
- package/dist/components/hover-menu.js +5 -3
- package/dist/components/hover-menu.js.map +1 -1
- package/dist/components/icon-button.js +14 -9
- package/dist/components/icon-button.js.map +1 -1
- package/dist/components/inline-confirm.d.ts +43 -0
- package/dist/components/inline-confirm.js +67 -0
- package/dist/components/inline-confirm.js.map +1 -0
- package/dist/components/inline-entity-combobox.d.ts +4 -3
- package/dist/components/inline-entity-combobox.js +150 -141
- package/dist/components/inline-entity-combobox.js.map +1 -1
- package/dist/components/input.js +1 -1
- package/dist/components/input.js.map +1 -1
- package/dist/components/jump-calendar.js +28 -112
- package/dist/components/jump-calendar.js.map +1 -1
- package/dist/components/legal-page.d.ts +3 -1
- package/dist/components/legal-page.js +3 -2
- package/dist/components/legal-page.js.map +1 -1
- package/dist/components/legal.d.ts +4 -2
- package/dist/components/legal.js.map +1 -1
- package/dist/components/lightbox.d.ts +2 -2
- package/dist/components/lightbox.js +17 -6
- package/dist/components/lightbox.js.map +1 -1
- package/dist/components/list.d.ts +6 -2
- package/dist/components/list.js +4 -3
- package/dist/components/list.js.map +1 -1
- package/dist/components/measured-grid.d.ts +1 -1
- package/dist/components/measured-grid.js +2 -1
- package/dist/components/measured-grid.js.map +1 -1
- package/dist/components/mini-calendar.js +3 -5
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/modal.d.ts +24 -0
- package/dist/components/modal.js +12 -4
- package/dist/components/modal.js.map +1 -1
- package/dist/components/money-draft.js +7 -5
- package/dist/components/money-draft.js.map +1 -1
- package/dist/components/money-field.d.ts +2 -2
- package/dist/components/money-field.js.map +1 -1
- package/dist/components/month-grid.d.ts +55 -0
- package/dist/components/month-grid.js +148 -0
- package/dist/components/month-grid.js.map +1 -0
- package/dist/components/month-picker.d.ts +36 -4
- package/dist/components/month-picker.js +123 -146
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.js +2 -1
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/multi-select.d.ts +2 -2
- package/dist/components/multi-select.js +11 -6
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/number-field.d.ts +6 -4
- package/dist/components/number-field.js +3 -2
- package/dist/components/number-field.js.map +1 -1
- package/dist/components/number-input.d.ts +4 -1
- package/dist/components/number-input.js +3 -2
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.js.map +1 -1
- package/dist/components/picker-sheet.js +2 -1
- package/dist/components/picker-sheet.js.map +1 -1
- package/dist/components/pie-chart-labels.d.ts +7 -0
- package/dist/components/pie-chart-labels.js +1 -0
- package/dist/components/pie-chart-labels.js.map +1 -1
- package/dist/components/pie-chart.d.ts +5 -3
- package/dist/components/pie-chart.js +7 -22
- package/dist/components/pie-chart.js.map +1 -1
- package/dist/components/popover.d.ts +3 -0
- package/dist/components/popover.js +7 -1
- package/dist/components/popover.js.map +1 -1
- package/dist/components/reauth-dialog.d.ts +4 -5
- package/dist/components/reauth-dialog.js +1 -4
- package/dist/components/reauth-dialog.js.map +1 -1
- package/dist/components/row-actions.js +2 -1
- package/dist/components/row-actions.js.map +1 -1
- package/dist/components/section-nav.d.ts +7 -0
- package/dist/components/section-nav.js.map +1 -1
- package/dist/components/series-chart-axes.d.ts +10 -3
- package/dist/components/series-chart-axes.js +1 -0
- package/dist/components/series-chart-axes.js.map +1 -1
- package/dist/components/series-chart-labels.d.ts +7 -4
- package/dist/components/series-chart-labels.js.map +1 -1
- package/dist/components/series-chart.d.ts +31 -7
- package/dist/components/series-chart.js +72 -29
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/share-card.js +3 -3
- package/dist/components/share-card.js.map +1 -1
- package/dist/components/sign-chip-labels.d.ts +1 -0
- package/dist/components/sign-chip-labels.js.map +1 -1
- package/dist/components/sign-chip.d.ts +10 -1
- package/dist/components/sign-chip.js.map +1 -1
- package/dist/components/tabs-labels.d.ts +2 -0
- package/dist/components/tabs-labels.js +11 -0
- package/dist/components/tabs-labels.js.map +1 -0
- package/dist/components/tabs.d.ts +1 -1
- package/dist/components/tabs.js +13 -11
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/toggle-legend.d.ts +2 -2
- package/dist/components/toggle-legend.js +6 -6
- package/dist/components/toggle-legend.js.map +1 -1
- package/dist/components/translation-review-editor.d.ts +4 -2
- package/dist/components/translation-review-editor.js +2 -3
- package/dist/components/translation-review-editor.js.map +1 -1
- package/dist/components/translation-review.d.ts +2 -1
- package/dist/components/translation-review.js +2 -2
- package/dist/components/translation-review.js.map +1 -1
- package/dist/components/treemap-labels.d.ts +26 -0
- package/dist/components/treemap-labels.js +10 -0
- package/dist/components/treemap-labels.js.map +1 -0
- package/dist/components/treemap-layout.d.ts +62 -0
- package/dist/components/treemap-layout.js +126 -0
- package/dist/components/treemap-layout.js.map +1 -0
- package/dist/components/treemap.d.ts +140 -17
- package/dist/components/treemap.js +324 -97
- package/dist/components/treemap.js.map +1 -1
- package/dist/components/use-table-state.d.ts +5 -5
- package/dist/components/use-table-state.js +4 -1
- package/dist/components/use-table-state.js.map +1 -1
- package/dist/data-table.d.ts +6 -2
- package/dist/data-table.js +7 -2
- package/dist/data-table.js.map +1 -1
- package/dist/eslint/index.js +1 -1
- package/dist/eslint/role-utilities.d.ts +36 -7
- package/dist/eslint/role-utilities.js +42 -9
- package/dist/eslint/role-utilities.js.map +1 -1
- package/dist/feedback/feedback-dialog.d.ts +25 -16
- package/dist/feedback/feedback-dialog.js +6 -2
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-mutation.d.ts +30 -0
- package/dist/feedback/feedback-mutation.js +16 -0
- package/dist/feedback/feedback-mutation.js.map +1 -0
- package/dist/feedback/feedback-page-link.d.ts +53 -0
- package/dist/feedback/feedback-page-link.js +37 -0
- package/dist/feedback/feedback-page-link.js.map +1 -0
- package/dist/feedback/feedback-public-list.d.ts +12 -3
- package/dist/feedback/feedback-public-list.js +2 -1
- package/dist/feedback/feedback-public-list.js.map +1 -1
- package/dist/feedback/feedback-replies.d.ts +3 -1
- package/dist/feedback/feedback-replies.js +5 -4
- package/dist/feedback/feedback-replies.js.map +1 -1
- package/dist/feedback/feedback-row-detail-labels.js +5 -0
- package/dist/feedback/feedback-row-detail-labels.js.map +1 -1
- package/dist/feedback/feedback-row-detail.d.ts +64 -28
- package/dist/feedback/feedback-row-detail.js +30 -28
- package/dist/feedback/feedback-row-detail.js.map +1 -1
- package/dist/feedback/feedback-status-undo.d.ts +30 -11
- package/dist/feedback/feedback-status-undo.js +10 -15
- package/dist/feedback/feedback-status-undo.js.map +1 -1
- package/dist/feedback/feedback-submit-dialog.d.ts +1 -1
- package/dist/feedback/feedback-submit-dialog.js +1 -1
- package/dist/feedback/feedback-submit-dialog.js.map +1 -1
- package/dist/feedback/feedback-submit.js +9 -3
- package/dist/feedback/feedback-submit.js.map +1 -1
- package/dist/feedback/feedback-swipe.d.ts +1 -1
- package/dist/feedback/feedback-swipe.js.map +1 -1
- package/dist/feedback/feedback-table.d.ts +21 -9
- package/dist/feedback/feedback-table.js +45 -25
- package/dist/feedback/feedback-table.js.map +1 -1
- package/dist/feedback/feedback-thread-labels.d.ts +2 -2
- package/dist/feedback/feedback-thread-labels.js.map +1 -1
- package/dist/feedback/feedback-thread.d.ts +24 -23
- package/dist/feedback/feedback-thread.js +2 -1
- package/dist/feedback/feedback-thread.js.map +1 -1
- package/dist/feedback.d.ts +34 -0
- package/dist/feedback.js +42 -0
- package/dist/feedback.js.map +1 -1
- package/dist/hooks/use-dismiss.js.map +1 -1
- package/dist/hooks/use-focus-trap.d.ts +35 -0
- package/dist/hooks/use-focus-trap.js +6 -4
- package/dist/hooks/use-focus-trap.js.map +1 -1
- package/dist/hooks/use-hotkey.d.ts +5 -2
- package/dist/hooks/use-hotkey.js +5 -4
- package/dist/hooks/use-hotkey.js.map +1 -1
- package/dist/hooks/use-long-press.d.ts +7 -4
- package/dist/hooks/use-long-press.js +3 -0
- package/dist/hooks/use-long-press.js.map +1 -1
- package/dist/hooks/use-media-query.js +12 -4
- package/dist/hooks/use-media-query.js.map +1 -1
- package/dist/hooks/use-mounted.d.ts +22 -0
- package/dist/hooks/use-mounted.js +24 -0
- package/dist/hooks/use-mounted.js.map +1 -0
- package/dist/hooks/use-overlay-history.d.ts +7 -1
- package/dist/hooks/use-overlay-history.js +35 -5
- package/dist/hooks/use-overlay-history.js.map +1 -1
- package/dist/i18n/defaults.js +4 -5
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.js +7 -1
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +9 -2
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/en.js +20 -41
- package/dist/i18n/locales/en.js.map +3 -3
- package/dist/i18n/locales/es.js +7 -1
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.js +20 -10
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.js +9 -1
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.js +7 -1
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.js +8 -1
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.js +5 -0
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +64 -17
- package/dist/index.js +77 -12
- package/dist/index.js.map +1 -1
- package/dist/landing/routing.d.ts +3 -1
- package/dist/landing/routing.js +4 -7
- package/dist/landing/routing.js.map +1 -1
- package/dist/lib/broadcast.d.ts +17 -0
- package/dist/lib/broadcast.js +30 -0
- package/dist/lib/broadcast.js.map +1 -0
- package/dist/lib/calc.d.ts +7 -1
- package/dist/lib/calc.js +3 -1
- package/dist/lib/calc.js.map +1 -1
- package/dist/lib/clipboard-minus.d.ts +2 -2
- package/dist/lib/clipboard-minus.js +1 -1
- package/dist/lib/clipboard-minus.js.map +1 -1
- package/dist/lib/date-format.d.ts +37 -2
- package/dist/lib/date-format.js +34 -8
- package/dist/lib/date-format.js.map +1 -1
- package/dist/lib/day-format.d.ts +46 -0
- package/dist/lib/day-format.js +46 -0
- package/dist/lib/day-format.js.map +1 -0
- package/dist/lib/decimal-marks.d.ts +7 -1
- package/dist/lib/decimal-marks.js +5 -2
- package/dist/lib/decimal-marks.js.map +1 -1
- package/dist/lib/describe-failure.d.ts +14 -0
- package/dist/lib/describe-failure.js +9 -0
- package/dist/lib/describe-failure.js.map +1 -0
- package/dist/lib/direction.d.ts +16 -0
- package/dist/lib/direction.js +9 -1
- package/dist/lib/direction.js.map +1 -1
- package/dist/lib/focus-left.d.ts +63 -0
- package/dist/lib/focus-left.js +67 -0
- package/dist/lib/focus-left.js.map +1 -0
- package/dist/lib/format.d.ts +5 -3
- package/dist/lib/format.js +16 -13
- package/dist/lib/format.js.map +1 -1
- package/dist/lib/http-status.d.ts +24 -0
- package/dist/lib/http-status.js +14 -0
- package/dist/lib/http-status.js.map +1 -0
- package/dist/lib/intl-cache.d.ts +14 -0
- package/dist/lib/intl-cache.js +15 -0
- package/dist/lib/intl-cache.js.map +1 -0
- package/dist/lib/isin.d.ts +10 -0
- package/dist/lib/isin.js.map +1 -1
- package/dist/lib/iso-day.d.ts +11 -0
- package/dist/lib/iso-day.js +8 -0
- package/dist/lib/iso-day.js.map +1 -0
- package/dist/lib/lazy-with-fallback.d.ts +31 -0
- package/dist/lib/lazy-with-fallback.js +40 -0
- package/dist/lib/lazy-with-fallback.js.map +1 -0
- package/dist/lib/path-pattern.d.ts +34 -0
- package/dist/lib/path-pattern.js +24 -0
- package/dist/lib/path-pattern.js.map +1 -0
- package/dist/lib/reduced-motion.d.ts +2 -1
- package/dist/lib/reduced-motion.js.map +1 -1
- package/dist/lib/round.d.ts +2 -1
- package/dist/lib/round.js +2 -1
- package/dist/lib/round.js.map +1 -1
- package/dist/lib/safe-storage.d.ts +24 -5
- package/dist/lib/safe-storage.js +27 -2
- package/dist/lib/safe-storage.js.map +1 -1
- package/dist/lib/session-refresh.js +1 -1
- package/dist/lib/session-refresh.js.map +1 -1
- package/dist/lib/share-format.d.ts +13 -0
- package/dist/lib/share-format.js +10 -0
- package/dist/lib/share-format.js.map +1 -0
- package/dist/lib/text-case.d.ts +17 -0
- package/dist/lib/text-case.js +8 -0
- package/dist/lib/text-case.js.map +1 -0
- package/dist/lib/text-match.d.ts +38 -0
- package/dist/lib/text-match.js +24 -2
- package/dist/lib/text-match.js.map +1 -1
- package/dist/lib/thenable.d.ts +13 -0
- package/dist/lib/thenable.js +8 -0
- package/dist/lib/thenable.js.map +1 -0
- package/dist/lib/translation-review.d.ts +7 -2
- package/dist/lib/translation-review.js +4 -4
- package/dist/lib/translation-review.js.map +1 -1
- package/dist/notifications/device-zone-report.js +1 -1
- package/dist/notifications/device-zone-report.js.map +1 -1
- package/dist/notifications/notification-bell.d.ts +2 -1
- package/dist/notifications/notification-bell.js +3 -3
- package/dist/notifications/notification-bell.js.map +1 -1
- package/dist/notifications/notification-inbox.d.ts +10 -6
- package/dist/notifications/notification-inbox.js +26 -48
- package/dist/notifications/notification-inbox.js.map +1 -1
- package/dist/notifications/notification-parts.d.ts +3 -2
- package/dist/notifications/notification-parts.js +1 -3
- package/dist/notifications/notification-parts.js.map +1 -1
- package/dist/notifications/notification-types-setting.js +1 -1
- package/dist/notifications/notification-types-setting.js.map +1 -1
- package/dist/notifications/notifications-labels.d.ts +6 -0
- package/dist/notifications/notifications-labels.js +1 -0
- package/dist/notifications/notifications-labels.js.map +1 -1
- package/dist/notifications/push-device-setting.js +1 -1
- package/dist/notifications/push-device-setting.js.map +1 -1
- package/dist/notifications/push-devices-setting.d.ts +2 -1
- package/dist/notifications/push-devices-setting.js +27 -49
- package/dist/notifications/push-devices-setting.js.map +1 -1
- package/dist/notifications/quiet-hours-setting.d.ts +10 -3
- package/dist/notifications/quiet-hours-setting.js +65 -26
- package/dist/notifications/quiet-hours-setting.js.map +1 -1
- package/dist/notifications/unsubscribe-panel.js +4 -7
- package/dist/notifications/unsubscribe-panel.js.map +1 -1
- package/dist/notifications/use-push-device.d.ts +39 -1
- package/dist/notifications/use-push-device.js +28 -7
- package/dist/notifications/use-push-device.js.map +1 -1
- package/dist/offline/query-persistence.d.ts +3 -1
- package/dist/offline/query-persistence.js +19 -2
- package/dist/offline/query-persistence.js.map +1 -1
- package/dist/rhf/fields.d.ts +11 -4
- package/dist/rhf/fields.js.map +1 -1
- package/dist/search/command-palette.js +1 -1
- package/dist/search/command-palette.js.map +1 -1
- package/dist/search/global-search.js +19 -9
- package/dist/search/global-search.js.map +1 -1
- package/dist/search/use-command-key.d.ts +12 -1
- package/dist/search/use-command-key.js +3 -12
- package/dist/search/use-command-key.js.map +1 -1
- package/dist/search.d.ts +7 -0
- package/dist/search.js +10 -0
- package/dist/search.js.map +1 -1
- package/dist/settings/use-settings-focus.js +1 -0
- package/dist/settings/use-settings-focus.js.map +1 -1
- package/dist/shell/account-menu-language.d.ts +21 -5
- package/dist/shell/account-menu-language.js +3 -1
- package/dist/shell/account-menu-language.js.map +1 -1
- package/dist/shell/account-menu-text-size.d.ts +26 -9
- package/dist/shell/account-menu-text-size.js +3 -2
- package/dist/shell/account-menu-text-size.js.map +1 -1
- package/dist/shell/dev-menu.js +5 -18
- package/dist/shell/dev-menu.js.map +1 -1
- package/dist/shell/role-switcher.d.ts +7 -0
- package/dist/shell/role-switcher.js.map +1 -1
- package/dist/shell/top-bar-actions.d.ts +1 -1
- package/dist/shell/top-bar-actions.js.map +1 -1
- package/dist/shell/top-bar-parts-labels.d.ts +0 -2
- package/dist/shell/top-bar-parts-labels.js +0 -1
- package/dist/shell/top-bar-parts-labels.js.map +1 -1
- package/dist/shell.d.ts +27 -8
- package/dist/shell.js +28 -7
- package/dist/shell.js.map +1 -1
- package/dist/sync/engine.d.ts +30 -4
- package/dist/sync/engine.js +172 -52
- package/dist/sync/engine.js.map +1 -1
- package/dist/sync.d.ts +6 -2
- package/dist/sync.js +6 -1
- package/dist/sync.js.map +1 -1
- package/dist/testing/css-variables.js +3 -8
- package/dist/testing/css-variables.js.map +1 -1
- package/dist/theme/contrast.d.ts +2 -1
- package/dist/theme/contrast.js +3 -8
- package/dist/theme/contrast.js.map +1 -1
- package/dist/theme/palette-store.js +6 -6
- package/dist/theme/palette-store.js.map +1 -1
- package/dist/theme/text-size.js +3 -8
- package/dist/theme/text-size.js.map +1 -1
- package/dist/theme/theme-store.js +3 -6
- package/dist/theme/theme-store.js.map +1 -1
- package/dist/tour/tour-catalogue.d.ts +7 -4
- package/dist/tour/tour-catalogue.js +12 -10
- package/dist/tour/tour-catalogue.js.map +1 -1
- package/dist/tour/tour-dock.d.ts +0 -2
- package/dist/tour/tour-dock.js +0 -2
- package/dist/tour/tour-dock.js.map +1 -1
- package/dist/tour/tour-gates.d.ts +4 -0
- package/dist/tour/tour-gates.js +14 -0
- package/dist/tour/tour-gates.js.map +1 -1
- package/dist/tour/tour-overlay.d.ts +27 -0
- package/dist/tour/tour-overlay.js +741 -0
- package/dist/tour/tour-overlay.js.map +1 -0
- package/dist/tour/tour.d.ts +16 -4
- package/dist/tour/tour.js +62 -778
- package/dist/tour/tour.js.map +1 -1
- package/dist/tour/use-tour-progress.js +1 -1
- package/dist/tour/use-tour-progress.js.map +1 -1
- package/dist/tour/use-tour-url-sync.js +2 -2
- package/dist/tour/use-tour-url-sync.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +5 -1
- package/dist/wizard/stepper-nav.js.map +1 -1
- package/dist/wizard/types.d.ts +6 -2
- package/dist/wizard/types.js.map +1 -1
- package/dist/wizard/use-wizard.d.ts +3 -1
- package/dist/wizard/use-wizard.js.map +1 -1
- package/dist/wizard/validation.d.ts +3 -1
- package/dist/wizard/validation.js.map +1 -1
- package/package.json +12 -8
- package/src/account/account-parts.ts +5 -25
- package/src/account/data-export-setting-labels.ts +1 -1
- package/src/account/delete-account-setting-labels.ts +1 -1
- package/src/account/email-change-setting-labels.ts +1 -1
- package/src/account/passkeys-setting.tsx +60 -38
- package/src/account/sessions-setting.tsx +18 -12
- package/src/admin/admin-action-confirm.tsx +5 -10
- package/src/admin/admin-parts.ts +11 -25
- package/src/admin/mail-test-card-labels.ts +1 -1
- package/src/admin/plan-change-labels.ts +5 -23
- package/src/admin/plan-change.tsx +7 -44
- package/src/admin/reviewer-scope-editor.tsx +3 -3
- package/src/auth/auth-errors-labels.ts +23 -0
- package/src/auth/auth-errors.ts +11 -38
- package/src/auth/complete-name-dialog.tsx +9 -8
- package/src/auth/forgot-password-form-labels.ts +1 -1
- package/src/auth/forgot-password-form.tsx +11 -6
- package/src/auth/register-form-labels.ts +1 -1
- package/src/auth/reset-password-form-labels.ts +1 -1
- package/src/auth/reset-password-form.tsx +8 -4
- package/src/auth/sign-in-form-labels.ts +1 -1
- package/src/auth/status-parts.tsx +0 -6
- package/src/auth/verify-email-labels.ts +1 -1
- package/src/auth/verify-email.tsx +11 -6
- package/src/billing/cancel-request.ts +28 -6
- package/src/billing/cancel-subscription.tsx +29 -22
- package/src/billing/dialog-close.ts +34 -0
- package/src/billing/plan-card.tsx +36 -11
- package/src/billing/plan-change-labels.ts +66 -0
- package/src/billing/plan-switch.tsx +31 -20
- package/src/chart.ts +21 -3
- package/src/components/account-chips.tsx +20 -23
- package/src/components/alert-banner.tsx +82 -5
- package/src/components/amount-input.tsx +32 -14
- package/src/components/autocomplete.tsx +64 -70
- package/src/components/bulk-action-bar.tsx +70 -2
- package/src/components/button-look.ts +5 -5
- package/src/components/button.tsx +2 -2
- package/src/components/calculator.tsx +98 -17
- package/src/components/chart-edge.ts +34 -1
- package/src/components/chart-figure.tsx +35 -0
- package/src/components/chart-zoom-core.tsx +6 -5
- package/src/components/chart.tsx +26 -5
- package/src/components/combobox-core.tsx +303 -69
- package/src/components/combobox.tsx +184 -155
- package/src/components/copy-button.tsx +34 -23
- package/src/components/country-select.tsx +16 -11
- package/src/components/data-table-column-settings.tsx +52 -10
- package/src/components/data-table-filters.ts +6 -4
- package/src/components/data-table-fit.ts +19 -5
- package/src/components/data-table-groups.tsx +1 -1
- package/src/components/data-table-head.tsx +32 -22
- package/src/components/data-table-mobile.tsx +110 -27
- package/src/components/data-table-pagination.tsx +21 -6
- package/src/components/data-table-resize.ts +1 -1
- package/src/components/data-table-row-actions.tsx +3 -3
- package/src/components/data-table-row.tsx +25 -14
- package/src/components/data-table-selection.ts +1 -1
- package/src/components/data-table-shared.tsx +33 -1
- package/src/components/data-table-sort.ts +57 -2
- package/src/components/data-table-virtual.ts +32 -8
- package/src/components/data-table.tsx +267 -41
- package/src/components/date-field.tsx +65 -8
- package/src/components/date-picker.tsx +125 -48
- package/src/components/date-range-picker.tsx +82 -31
- package/src/components/dialog-frame.tsx +2 -1
- package/src/components/entity-combobox.tsx +4 -1
- package/src/components/error-boundary.tsx +53 -39
- package/src/components/field-base-labels.ts +20 -0
- package/src/components/field-base.tsx +13 -7
- package/src/components/field-sync-labels.ts +1 -0
- package/src/components/field-sync.tsx +23 -1
- package/src/components/form-actions.tsx +20 -5
- package/src/components/hover-menu.tsx +18 -8
- package/src/components/icon-button.tsx +14 -9
- package/src/components/inline-confirm.tsx +116 -0
- package/src/components/inline-entity-combobox.tsx +198 -152
- package/src/components/input.tsx +1 -1
- package/src/components/jump-calendar.tsx +30 -146
- package/src/components/legal-page.tsx +10 -7
- package/src/components/legal.tsx +4 -2
- package/src/components/lightbox.tsx +21 -8
- package/src/components/list.tsx +14 -5
- package/src/components/measured-grid.tsx +8 -4
- package/src/components/mini-calendar.tsx +6 -5
- package/src/components/modal.tsx +45 -4
- package/src/components/money-draft.ts +16 -5
- package/src/components/money-field.tsx +2 -2
- package/src/components/month-grid.tsx +229 -0
- package/src/components/month-picker.tsx +192 -200
- package/src/components/multi-entity-combobox.tsx +1 -0
- package/src/components/multi-select.tsx +21 -9
- package/src/components/number-field.tsx +14 -7
- package/src/components/number-input.tsx +9 -3
- package/src/components/numpad-sheet.tsx +4 -3
- package/src/components/picker-sheet.tsx +12 -9
- package/src/components/pie-chart-labels.ts +8 -0
- package/src/components/pie-chart.tsx +22 -28
- package/src/components/popover.tsx +18 -1
- package/src/components/reauth-dialog.tsx +6 -10
- package/src/components/row-actions.tsx +2 -1
- package/src/components/section-nav.tsx +7 -0
- package/src/components/series-chart-axes.ts +11 -3
- package/src/components/series-chart-labels.ts +7 -4
- package/src/components/series-chart.tsx +178 -69
- package/src/components/share-card.tsx +6 -6
- package/src/components/sign-chip-labels.ts +1 -0
- package/src/components/sign-chip.tsx +10 -1
- package/src/components/tabs-labels.ts +13 -0
- package/src/components/tabs.tsx +35 -19
- package/src/components/toggle-legend.tsx +16 -11
- package/src/components/translation-review-editor.tsx +6 -5
- package/src/components/translation-review.tsx +4 -3
- package/src/components/treemap-labels.ts +39 -0
- package/src/components/treemap-layout.ts +210 -0
- package/src/components/treemap.tsx +722 -133
- package/src/components/use-table-state.ts +12 -9
- package/src/data-table.ts +9 -2
- package/src/eslint/role-utilities.ts +97 -19
- package/src/feedback/feedback-dialog.tsx +30 -19
- package/src/feedback/feedback-mutation.ts +41 -0
- package/src/feedback/feedback-page-link.ts +90 -0
- package/src/feedback/feedback-public-list.tsx +17 -5
- package/src/feedback/feedback-replies.tsx +13 -6
- package/src/feedback/feedback-row-detail-labels.ts +5 -0
- package/src/feedback/feedback-row-detail.tsx +103 -67
- package/src/feedback/feedback-status-undo.ts +41 -27
- package/src/feedback/feedback-submit-dialog.tsx +2 -2
- package/src/feedback/feedback-submit.tsx +21 -7
- package/src/feedback/feedback-swipe.tsx +1 -1
- package/src/feedback/feedback-table.tsx +86 -38
- package/src/feedback/feedback-thread-labels.ts +2 -2
- package/src/feedback/feedback-thread.tsx +27 -25
- package/src/feedback.ts +42 -0
- package/src/hooks/use-dismiss.ts +3 -2
- package/src/hooks/use-focus-trap.ts +8 -24
- package/src/hooks/use-hotkey.ts +24 -7
- package/src/hooks/use-long-press.ts +16 -2
- package/src/hooks/use-media-query.ts +20 -4
- package/src/hooks/use-mounted.ts +39 -0
- package/src/hooks/use-overlay-history.ts +70 -5
- package/src/i18n/defaults.ts +4 -5
- package/src/i18n/german.ts +8 -2
- package/src/i18n/kit-labels.tsx +9 -2
- package/src/i18n/locales/es.ts +8 -2
- package/src/i18n/locales/fr.ts +21 -13
- package/src/i18n/locales/hu.ts +10 -2
- package/src/i18n/locales/it.ts +8 -2
- package/src/i18n/locales/zh.ts +9 -2
- package/src/i18n/review.ts +5 -0
- package/src/index.ts +103 -13
- package/src/landing/routing.tsx +14 -10
- package/src/lib/broadcast.ts +52 -0
- package/src/lib/calc.ts +13 -2
- package/src/lib/clipboard-minus.ts +14 -4
- package/src/lib/date-format.ts +89 -13
- package/src/lib/day-format.ts +96 -0
- package/src/lib/decimal-marks.ts +12 -3
- package/src/lib/describe-failure.ts +18 -0
- package/src/lib/direction.ts +39 -0
- package/src/lib/focus-left.ts +156 -0
- package/src/lib/format.ts +34 -19
- package/src/lib/http-status.ts +38 -0
- package/src/lib/intl-cache.ts +25 -0
- package/src/lib/isin.ts +10 -0
- package/src/lib/iso-day.ts +13 -0
- package/src/lib/lazy-with-fallback.ts +82 -0
- package/src/lib/path-pattern.ts +55 -0
- package/src/lib/reduced-motion.ts +2 -1
- package/src/lib/round.ts +7 -2
- package/src/lib/safe-storage.ts +48 -6
- package/src/lib/session-refresh.ts +1 -1
- package/src/lib/share-format.ts +18 -0
- package/src/lib/text-case.ts +19 -0
- package/src/lib/text-match.ts +69 -2
- package/src/lib/thenable.ts +19 -0
- package/src/lib/translation-review.ts +13 -5
- package/src/notifications/device-zone-report.ts +1 -1
- package/src/notifications/notification-bell.tsx +7 -4
- package/src/notifications/notification-inbox.tsx +40 -58
- package/src/notifications/notification-parts.tsx +3 -4
- package/src/notifications/notification-types-setting.tsx +1 -1
- package/src/notifications/notifications-labels.ts +7 -0
- package/src/notifications/push-device-setting.tsx +1 -1
- package/src/notifications/push-devices-setting.tsx +30 -55
- package/src/notifications/quiet-hours-setting.tsx +93 -31
- package/src/notifications/unsubscribe-panel.tsx +4 -7
- package/src/notifications/use-push-device.ts +76 -10
- package/src/offline/query-persistence.ts +35 -3
- package/src/rhf/fields.tsx +11 -4
- package/src/search/command-palette.tsx +2 -4
- package/src/search/global-search.tsx +36 -15
- package/src/search/use-command-key.ts +13 -12
- package/src/search.ts +9 -0
- package/src/settings/use-settings-focus.ts +3 -0
- package/src/shell/account-menu-language.tsx +27 -5
- package/src/shell/account-menu-text-size.tsx +32 -10
- package/src/shell/dev-menu.tsx +7 -21
- package/src/shell/role-switcher.tsx +7 -0
- package/src/shell/top-bar-actions.tsx +1 -1
- package/src/shell/top-bar-parts-labels.ts +0 -3
- package/src/shell.ts +40 -9
- package/src/sync/engine.ts +339 -61
- package/src/sync.ts +8 -1
- package/src/testing/css-variables.ts +8 -9
- package/src/theme/contrast.ts +8 -9
- package/src/theme/palette-store.ts +9 -9
- package/src/theme/text-size.ts +6 -8
- package/src/theme/theme-store.ts +7 -9
- package/src/tour/tour-catalogue.tsx +26 -15
- package/src/tour/tour-dock.ts +0 -2
- package/src/tour/tour-gates.ts +23 -0
- package/src/tour/tour-overlay.tsx +1170 -0
- package/src/tour/tour.tsx +116 -1193
- package/src/tour/use-tour-progress.ts +1 -1
- package/src/tour/use-tour-url-sync.ts +7 -3
- package/src/wizard/stepper-nav.tsx +3 -1
- package/src/wizard/types.ts +11 -2
- package/src/wizard/use-wizard.ts +2 -1
- package/src/wizard/validation.ts +8 -2
- package/tokens.css +2 -1
- package/dist/components/ui-labels.js.map +0 -1
- package/dist/shell/dev-switchers.d.ts +0 -6
- package/dist/shell/dev-switchers.js +0 -12
- package/dist/shell/dev-switchers.js.map +0 -1
- package/src/components/ui-labels.ts +0 -24
- package/src/shell/dev-switchers.tsx +0 -18
package/src/components/tabs.tsx
CHANGED
|
@@ -2,14 +2,14 @@ import { useLayoutEffect, useMemo, useRef } from "react";
|
|
|
2
2
|
import { ChevronLeft, ChevronRight, Plus, X } from "lucide-react";
|
|
3
3
|
import type { ComponentPropsWithoutRef, KeyboardEvent, ReactNode, Ref } from "react";
|
|
4
4
|
import { cn } from "../lib/cn";
|
|
5
|
-
import {
|
|
5
|
+
import { FOCUS_RING } from "./focus-ring";
|
|
6
6
|
import { scrollIntoStrip, useStripFade } from "../lib/strip-fade";
|
|
7
7
|
import { horizontalStep } from "../lib/direction";
|
|
8
8
|
import { usePhoneLayout } from "../hooks/use-breakpoint";
|
|
9
9
|
import { prefersReducedMotion } from "../lib/reduced-motion";
|
|
10
10
|
import { useKitLabels, type LabelOverride } from "../i18n/kit-labels";
|
|
11
11
|
import { mergeRefs } from "./field-parts";
|
|
12
|
-
import { DEFAULT_TABS_LABELS } from "./
|
|
12
|
+
import { DEFAULT_TABS_LABELS } from "./tabs-labels";
|
|
13
13
|
import { IconButton } from "./icon-button";
|
|
14
14
|
import { HIT_AREA_LARGE } from "./button-look";
|
|
15
15
|
|
|
@@ -55,7 +55,7 @@ export interface TabsLabels {
|
|
|
55
55
|
previous: string;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
// Defined in ./
|
|
58
|
+
// Defined in ./tabs-labels, which holds no component code (0.34, KS U8).
|
|
59
59
|
export { DEFAULT_TABS_LABELS };
|
|
60
60
|
|
|
61
61
|
/**
|
|
@@ -205,9 +205,7 @@ const TABLIST_CLASSES = "flex gap-1 overflow-x-auto overflow-y-hidden border-b b
|
|
|
205
205
|
// selection. `--bg-active` is the kit's own selected-row fill (the sidebar's), so the
|
|
206
206
|
// admin page's nav and the app's own sidebar mark "you are here" the same way.
|
|
207
207
|
const TABLIST_VERTICAL_CLASSES = "flex flex-col gap-0.5";
|
|
208
|
-
const TAB_VERTICAL_CLASSES =
|
|
209
|
-
FOCUS_RING_WIDTH +
|
|
210
|
-
" flex w-full items-center rounded-md px-3 py-2 text-start text-sm font-medium transition-colors focus:outline-none focus-visible:ring-strong";
|
|
208
|
+
const TAB_VERTICAL_CLASSES = `flex w-full items-center rounded-md px-3 py-2 text-start text-sm font-medium transition-colors focus:outline-none ${FOCUS_RING}`;
|
|
211
209
|
const TAB_VERTICAL_ACTIVE_CLASSES = "bg-active text-primary";
|
|
212
210
|
const TAB_VERTICAL_INACTIVE_CLASSES = "text-muted hover:bg-hover hover:text-primary";
|
|
213
211
|
|
|
@@ -215,9 +213,14 @@ const TAB_VERTICAL_INACTIVE_CLASSES = "text-muted hover:bg-hover hover:text-prim
|
|
|
215
213
|
// links · … · 31 Punkte") made one tab 448px wide in a 390px strip, and a tab wider
|
|
216
214
|
// than the strip cannot be scrolled into view — its end was simply off screen
|
|
217
215
|
// (lenkbank L3). The label and detail truncate inside it instead; see `inner`.
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
216
|
+
//
|
|
217
|
+
// Keyboard focus on a tab, a side-nav row and the add button is the kit's one focus frame
|
|
218
|
+
// (text-size §5), in brand. Until 0.51.7 it rang in `ring-strong`: 2.54:1 on the light
|
|
219
|
+
// page and 2.76:1 on a card, under WCAG 1.4.11's 3:1 (refactor audit 2026-10-30, DSP-8;
|
|
220
|
+
// NavPills made the same move in 0.34, DOC-7). INSET on a tab: the strip scrolls
|
|
221
|
+
// (`overflow-x-auto overflow-y-hidden`), so a ring outside the tab is cut off along its
|
|
222
|
+
// top and bottom, and at a cut end.
|
|
223
|
+
const TAB_CLASSES = `max-w-full whitespace-nowrap px-3 py-2 text-sm font-medium transition-colors border-b-2 -mb-px focus:outline-none ${FOCUS_RING} focus-visible:ring-inset`;
|
|
221
224
|
const TAB_ACTIVE_CLASSES = "border-[var(--text-primary)] text-primary";
|
|
222
225
|
const TAB_INACTIVE_CLASSES = "border-transparent text-muted hover:text-secondary hover:border-strong";
|
|
223
226
|
|
|
@@ -225,9 +228,7 @@ const TAB_INACTIVE_CLASSES = "border-transparent text-muted hover:text-secondary
|
|
|
225
228
|
// `onRemove`).
|
|
226
229
|
const TAB_REMOVABLE_CLASSES = "pe-8";
|
|
227
230
|
const TAB_EMPTY_CLASSES = "-mx-1.5 rounded border border-dashed border-strong px-1.5";
|
|
228
|
-
const TAB_ADD_CLASSES =
|
|
229
|
-
FOCUS_RING_WIDTH +
|
|
230
|
-
" inline-flex items-center gap-1 whitespace-nowrap rounded-md px-3 py-2 text-sm font-medium text-muted transition-colors hover:text-primary focus:outline-none focus-visible:ring-strong disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:size-4";
|
|
231
|
+
const TAB_ADD_CLASSES = `inline-flex items-center gap-1 whitespace-nowrap rounded-md px-3 py-2 text-sm font-medium text-muted transition-colors hover:text-primary focus:outline-none ${FOCUS_RING} disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:size-4`;
|
|
231
232
|
// `relative`: the phone's visually hidden label needs a positioned ancestor (see the
|
|
232
233
|
// sr-only rule in CONTRIBUTING); `max-md:px-2` squares the lone "+".
|
|
233
234
|
const TAB_ADD_PHONE_CLASSES = "relative max-md:px-2";
|
|
@@ -262,6 +263,8 @@ export function Tabs<T extends string>({
|
|
|
262
263
|
const cue = overflowCue && !vertical;
|
|
263
264
|
const cueStart = cue && (fade.overflow === "start" || fade.overflow === "both");
|
|
264
265
|
const cueEnd = cue && (fade.overflow === "end" || fade.overflow === "both");
|
|
266
|
+
// The cue gutters (see `stripBox`): there only while the strip overflows at all.
|
|
267
|
+
const gutters = cue && fade.overflow !== undefined;
|
|
265
268
|
// Three quarters of the visible width toward `side`; an RTL strip runs leftward.
|
|
266
269
|
const onCue = (side: "start" | "end") => {
|
|
267
270
|
const strip = stripRef.current;
|
|
@@ -333,15 +336,25 @@ export function Tabs<T extends string>({
|
|
|
333
336
|
// "80 km," under the add button. Only the strip scrolls (`scrollBy` on it, not
|
|
334
337
|
// `scrollIntoView`, which would scroll the page as well), and only as far as needed
|
|
335
338
|
// to clear the fade.
|
|
339
|
+
//
|
|
340
|
+
// And again when the cue gutters appear (refactor audit 2026-10-30, DSP-16). They come a
|
|
341
|
+
// render after the strip is first measured as overflowing — on mount, or with the very
|
|
342
|
+
// tab that tipped it over — and take 24px off each end, so a tab scrolled clear before
|
|
343
|
+
// them ended 24px past the visible end, under the fade and the ›.
|
|
336
344
|
useLayoutEffect(() => {
|
|
337
345
|
const strip = stripRef.current;
|
|
338
346
|
const tab = strip?.querySelector<HTMLElement>('[role="tab"][aria-selected="true"]');
|
|
339
347
|
if (strip && tab) scrollIntoStrip(strip, tab);
|
|
340
|
-
}, [active]);
|
|
348
|
+
}, [active, gutters]);
|
|
341
349
|
const isRemovable = (tab: TabItem<T>) => onRemove !== undefined && tab.removable !== false;
|
|
342
350
|
// Whether Delete reaches this tab: every removable tab, or only the open one.
|
|
343
351
|
const deletesOnKey = (tab: TabItem<T>) => isRemovable(tab) && (removeOn === "every" || tab.id === active);
|
|
344
352
|
const nameOf = (tab: TabItem<T>) => tab.name ?? (typeof tab.label === "string" ? tab.label : tab.id);
|
|
353
|
+
// The strip's one tab stop (see `tabIndex` below): the open tab, or the first while
|
|
354
|
+
// `active` names none. "No sheet open" is a real state — KS's sheet strips pass `""` —
|
|
355
|
+
// and with the stop on the selection alone every tab was -1, so the keyboard could not
|
|
356
|
+
// reach the one control that opens a sheet (refactor audit 2026-10-30, DSP-1).
|
|
357
|
+
const stop = tabs.some((t) => t.id === active) ? active : tabs[0]?.id;
|
|
345
358
|
|
|
346
359
|
// Where focus goes once a removal the strip asked for has happened. The caller
|
|
347
360
|
// owns `tabs` and may take its time (a confirmation, a request), so this waits
|
|
@@ -370,10 +383,14 @@ export function Tabs<T extends string>({
|
|
|
370
383
|
if (focused && focused !== document.body && !strip.contains(focused) && focused !== removeRef.current) return;
|
|
371
384
|
// The removed tab was open: focus follows the caller's new selection, which is
|
|
372
385
|
// also the strip's tab stop. It was not: its neighbour, as the ARIA pattern has it.
|
|
373
|
-
|
|
386
|
+
// The caller opened nothing in its place (KS drops the sheet and the selection in one
|
|
387
|
+
// render): the neighbour too, else the stop — not an index of -1 and the page (DSP-1).
|
|
388
|
+
const present = (id: T | undefined) => tabs.some((t) => t.id === id);
|
|
389
|
+
const target =
|
|
390
|
+
pending.wasActive && present(active) ? active : present(pending.neighbour) ? pending.neighbour : stop;
|
|
374
391
|
const index = tabs.findIndex((t) => t.id === target);
|
|
375
392
|
strip.querySelectorAll<HTMLElement>('[role="tab"]')[index]?.focus();
|
|
376
|
-
}, [tabs, active]);
|
|
393
|
+
}, [tabs, active, stop]);
|
|
377
394
|
|
|
378
395
|
// Arrow keys walk the strip in DOM order (ARIA tabs pattern). Home/End jump
|
|
379
396
|
// to the ends. Focus only — activation stays on click/Enter/Space, because a tab
|
|
@@ -462,8 +479,8 @@ export function Tabs<T extends string>({
|
|
|
462
479
|
// strip back on the next visit in a state they never chose. The cost is that
|
|
463
480
|
// Tab out and back returns to the open tab rather than to the last one
|
|
464
481
|
// looked at; the ARIA pattern allows either, and this one needs no second
|
|
465
|
-
// piece of state shadowing `active`.
|
|
466
|
-
tabIndex:
|
|
482
|
+
// piece of state shadowing `active`. With nothing open, the first tab (`stop`).
|
|
483
|
+
tabIndex: tab.id === stop ? 0 : -1,
|
|
467
484
|
// Only the open tab: see `panelId`.
|
|
468
485
|
"aria-controls": isActive ? panelId : undefined,
|
|
469
486
|
id: isActive && panelId ? `${panelId}-tab` : undefined,
|
|
@@ -612,8 +629,7 @@ export function Tabs<T extends string>({
|
|
|
612
629
|
) : null;
|
|
613
630
|
// The box the cues sit in, ‹ in the gutter before the strip and › in the one after it
|
|
614
631
|
// (see `gutterAt`). There whether or not the strip overflows right now, so a resize
|
|
615
|
-
// never re-parents it; the gutters only while it overflows at all.
|
|
616
|
-
const gutters = cue && fade.overflow !== undefined;
|
|
632
|
+
// never re-parents it; the gutters only while it overflows at all (`gutters`).
|
|
617
633
|
const stripBox = cue ? (
|
|
618
634
|
<div className={cn("relative flex min-w-0", !onAdd && "flex-1", gutters && "px-[24px]")}>
|
|
619
635
|
{tablist}
|
|
@@ -123,7 +123,7 @@ export interface LegendEntry {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
export interface ToggleLegendProps {
|
|
126
|
-
entries: LegendEntry[];
|
|
126
|
+
entries: readonly LegendEntry[];
|
|
127
127
|
/** The keys currently off the chart. */
|
|
128
128
|
hidden: ReadonlySet<string>;
|
|
129
129
|
onToggle: (key: string) => void;
|
|
@@ -198,12 +198,15 @@ export function ToggleLegend({
|
|
|
198
198
|
className={cn(
|
|
199
199
|
"flex items-center gap-1.5 rounded text-start text-caption text-secondary transition-opacity hover:opacity-80",
|
|
200
200
|
FOCUS_RING,
|
|
201
|
-
off && "opacity-35",
|
|
202
201
|
entry.align === "end" && "ms-auto",
|
|
203
202
|
)}
|
|
204
203
|
>
|
|
205
204
|
<LegendMark entry={entry} off={off} />
|
|
206
|
-
{
|
|
205
|
+
{/* Off, the label keeps its ink and is struck through; only the mark fades
|
|
206
|
+
(0.52, refactor audit 2026-10-30, DSP-9). The whole entry at 35 % put the
|
|
207
|
+
label at 1.8:1 — on a button that brings the series back, whose label is
|
|
208
|
+
the only thing saying which one. `aria-pressed` carries the state. */}
|
|
209
|
+
<span className={cn(off && "line-through")}>{entry.label}</span>
|
|
207
210
|
</button>
|
|
208
211
|
);
|
|
209
212
|
})}
|
|
@@ -212,7 +215,7 @@ export function ToggleLegend({
|
|
|
212
215
|
}
|
|
213
216
|
|
|
214
217
|
export interface StaticLegendProps {
|
|
215
|
-
entries: LegendEntry[];
|
|
218
|
+
entries: readonly LegendEntry[];
|
|
216
219
|
/** See {@link ToggleLegendProps.orientation}. */
|
|
217
220
|
orientation?: "horizontal" | "vertical";
|
|
218
221
|
/** The list's accessible name. Default: the `seriesChart.legend` label. */
|
|
@@ -338,13 +341,15 @@ export function LegendGroup({ title, children }: { title: ReactNode; children: R
|
|
|
338
341
|
* A stroke is an SVG line with the chart's own `strokeDasharray`, not a CSS gradient
|
|
339
342
|
* approximating it: a gradient can say "solid or dashed" and nothing more.
|
|
340
343
|
*
|
|
341
|
-
* A hidden
|
|
342
|
-
*
|
|
343
|
-
* gone rather than dimmed, while the square beside it
|
|
344
|
+
* A hidden mark fades ONCE, on its own box (`opacity-35`; since 0.52 the label beside
|
|
345
|
+
* it keeps its ink, DSP-9). The line used to take its own 0.35 inside a faded button —
|
|
346
|
+
* 0.35 × 0.35, about 12 %, a mark gone rather than dimmed, while the square beside it
|
|
347
|
+
* read at the full 35 %. */
|
|
344
348
|
function LegendMark({ entry, off }: { entry: LegendEntry; off: boolean }) {
|
|
349
|
+
const fade = off && "opacity-35";
|
|
345
350
|
if (entry.icon != null) {
|
|
346
351
|
return (
|
|
347
|
-
<span aria-hidden className="inline-flex shrink-0 items-center">
|
|
352
|
+
<span aria-hidden className={cn("inline-flex shrink-0 items-center", fade)}>
|
|
348
353
|
{entry.icon}
|
|
349
354
|
</span>
|
|
350
355
|
);
|
|
@@ -353,7 +358,7 @@ function LegendMark({ entry, off }: { entry: LegendEntry; off: boolean }) {
|
|
|
353
358
|
return (
|
|
354
359
|
<span
|
|
355
360
|
aria-hidden
|
|
356
|
-
className="size-2 shrink-0 rounded-full"
|
|
361
|
+
className={cn("size-2 shrink-0 rounded-full", fade)}
|
|
357
362
|
style={{
|
|
358
363
|
backgroundColor: off ? "transparent" : entry.color,
|
|
359
364
|
boxShadow: `inset 0 0 0 1.5px ${entry.color}`,
|
|
@@ -363,7 +368,7 @@ function LegendMark({ entry, off }: { entry: LegendEntry; off: boolean }) {
|
|
|
363
368
|
}
|
|
364
369
|
if (entry.marker === "stroke") {
|
|
365
370
|
return (
|
|
366
|
-
<svg aria-hidden viewBox="0 0 20 2" className="h-0.5 w-5 shrink-0 overflow-visible">
|
|
371
|
+
<svg aria-hidden viewBox="0 0 20 2" className={cn("h-0.5 w-5 shrink-0 overflow-visible", fade)}>
|
|
367
372
|
<line
|
|
368
373
|
x1={0}
|
|
369
374
|
y1={1}
|
|
@@ -379,7 +384,7 @@ function LegendMark({ entry, off }: { entry: LegendEntry; off: boolean }) {
|
|
|
379
384
|
return (
|
|
380
385
|
<span
|
|
381
386
|
aria-hidden
|
|
382
|
-
className="h-2.5 w-2.5 shrink-0 rounded-[3px]"
|
|
387
|
+
className={cn("h-2.5 w-2.5 shrink-0 rounded-[3px]", fade)}
|
|
383
388
|
style={{
|
|
384
389
|
backgroundColor: off ? "transparent" : entry.color,
|
|
385
390
|
boxShadow: `inset 0 0 0 1.5px ${entry.color}`,
|
|
@@ -3,7 +3,7 @@ import type { ReactNode } from "react";
|
|
|
3
3
|
|
|
4
4
|
import { useKitLabels, type LabelOverride } from "../i18n/kit-labels";
|
|
5
5
|
import { cn } from "../lib/cn";
|
|
6
|
-
import {
|
|
6
|
+
import { useDayFormatter } from "../lib/day-format";
|
|
7
7
|
import { placeholderTokens, reviewWrite } from "../lib/translation-review";
|
|
8
8
|
import type {
|
|
9
9
|
TranslationReviewKey,
|
|
@@ -48,8 +48,10 @@ export interface TranslationReviewEditorProps {
|
|
|
48
48
|
* opened by a tap — that one may only be opened to read.
|
|
49
49
|
*/
|
|
50
50
|
focusWording?: boolean;
|
|
51
|
-
/** How the verdict's date reads. Default: the
|
|
52
|
-
*
|
|
51
|
+
/** How the verdict's date reads. Default (0.52): the `<UiKitProvider formatDate>` when
|
|
52
|
+
* the app set one (its date preference; the day sits in a sentence, so no weekday), else
|
|
53
|
+
* the kit's `formatDate`, medium, in the provider's locale and `timeZone`. An empty
|
|
54
|
+
* answer falls back to the kit's. */
|
|
53
55
|
formatDate?: (iso: string) => string;
|
|
54
56
|
/** Turns a rejection into words. Default {@link TranslationReviewLabels.failed}. */
|
|
55
57
|
formatError?: (error: unknown) => ReactNode;
|
|
@@ -106,7 +108,7 @@ export function TranslationReviewEditor({
|
|
|
106
108
|
labels: labelsProp,
|
|
107
109
|
}: TranslationReviewEditorProps) {
|
|
108
110
|
const labels = useKitLabels("translationReview", DEFAULT_TRANSLATION_REVIEW_LABELS, labelsProp);
|
|
109
|
-
const
|
|
111
|
+
const date = useDayFormatter(formatDateProp);
|
|
110
112
|
const review = row.review;
|
|
111
113
|
const missing = row.text === "";
|
|
112
114
|
const editable = !readOnly && onSave !== undefined;
|
|
@@ -127,7 +129,6 @@ export function TranslationReviewEditor({
|
|
|
127
129
|
|
|
128
130
|
const canFlag = note.trim() !== "" || suggestion.trim() !== row.text.trim();
|
|
129
131
|
const changed = row.status === "changed" ? review : null;
|
|
130
|
-
const date = (iso: string) => (formatDateProp ? formatDateProp(iso) : formatDate(iso, "medium"));
|
|
131
132
|
|
|
132
133
|
const run = async (kind: "approve" | "flag" | "clear", action: () => MaybePromise) => {
|
|
133
134
|
setBusy(kind);
|
|
@@ -181,7 +181,8 @@ export interface TranslationReviewPanelProps {
|
|
|
181
181
|
* kit's, which an app listing what it stores had to list as its own (KS U4).
|
|
182
182
|
*/
|
|
183
183
|
storageKeyPrefix?: string;
|
|
184
|
-
/** How a verdict's date reads in the editor.
|
|
184
|
+
/** How a verdict's date reads in the editor. Default: the editor's — the
|
|
185
|
+
* `<UiKitProvider formatDate>`, else the kit's medium date (0.52). */
|
|
185
186
|
formatDate?: (iso: string) => string;
|
|
186
187
|
/** Turns a callback's rejection into words. Default {@link TranslationReviewLabels.failed}. */
|
|
187
188
|
formatError?: (error: unknown) => ReactNode;
|
|
@@ -561,8 +562,8 @@ export function TranslationReviewPanel({
|
|
|
561
562
|
// `filter` is rebuilt every render; its fields are what the list depends on.
|
|
562
563
|
const { status, query, placeholdersOnly } = filter;
|
|
563
564
|
const visible = useMemo(
|
|
564
|
-
() => filterTranslationRows(rows, { status, source, namespace, query, placeholdersOnly }),
|
|
565
|
-
[rows, status, source, namespace, query, placeholdersOnly],
|
|
565
|
+
() => filterTranslationRows(rows, { status, source, namespace, query, placeholdersOnly }, locale),
|
|
566
|
+
[rows, status, source, namespace, query, placeholdersOnly, locale],
|
|
566
567
|
);
|
|
567
568
|
|
|
568
569
|
// ── Groups ──
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// All user-facing strings for `Treemap`, as the `treemap` namespace of
|
|
2
|
+
// `<UiKitProvider labels>`, and per map the `labels` prop over that (0.52, refactor audit
|
|
3
|
+
// 2026-10-30, DSP-5).
|
|
4
|
+
//
|
|
5
|
+
// A module of its own, with no recharts in it, for the reason `pie-chart-labels` is one:
|
|
6
|
+
// the label registry (src/i18n) imports the defaults, and must not pull the chart
|
|
7
|
+
// library in behind them.
|
|
8
|
+
|
|
9
|
+
export interface TreemapLabels {
|
|
10
|
+
/**
|
|
11
|
+
* One tile's accessible name — what a screen reader says for a tile, clickable or
|
|
12
|
+
* not, since its area is nothing it can say. `value` arrives through the map's
|
|
13
|
+
* `valueFormatter` when that returns text, else as the number in the provider's
|
|
14
|
+
* locale; `share` is the tile's share of what is drawn, already a formatted percent
|
|
15
|
+
* ("60 %" in German, "60%" in English) — the function only arranges them.
|
|
16
|
+
*/
|
|
17
|
+
tile: (name: string, value: string, share: string) => string;
|
|
18
|
+
/**
|
|
19
|
+
* A group's accessible name (0.52, `TreemapNode.children`): its frame is a stop of the
|
|
20
|
+
* map's keyboard before its tiles, so a reader hears the group and its total once, on the
|
|
21
|
+
* way in. `value` and `share` as for {@link TreemapLabels.tile}, of the group's tiles
|
|
22
|
+
* together; the word "group" tells it from a tile of the same shape.
|
|
23
|
+
*/
|
|
24
|
+
group: (name: string, value: string, share: string) => string;
|
|
25
|
+
/**
|
|
26
|
+
* A name inside a group: `name` is the tile's (or a nested group's) own, from
|
|
27
|
+
* {@link TreemapLabels.tile} or {@link TreemapLabels.group}, and `group` the name of the
|
|
28
|
+
* group round it — applied once per group, the innermost first, so a tile two levels deep
|
|
29
|
+
* reads "Rent: 1,050 (40%), in Housing, in Fixed costs". In the name rather than said once
|
|
30
|
+
* by the frame, because Home, End and a click land on a tile without passing its frame.
|
|
31
|
+
*/
|
|
32
|
+
inGroup: (name: string, group: string) => string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const DEFAULT_TREEMAP_LABELS: TreemapLabels = {
|
|
36
|
+
tile: (name, value, share) => `${name}: ${value} (${share})`,
|
|
37
|
+
group: (name, value, share) => `${name}, group: ${value} (${share})`,
|
|
38
|
+
inGroup: (name, group) => `${name}, in ${group}`,
|
|
39
|
+
};
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// Where `Treemap` draws each node — a pure function of the nodes, the chart's size and the
|
|
2
|
+
// text size, with no recharts in it (0.52 code review of treemap.tsx, findings 1 and 8).
|
|
3
|
+
//
|
|
4
|
+
// recharts lays nested data out itself, edge to edge, and 0.52 first made the groups' room
|
|
5
|
+
// afterwards: a group's cell took its band and margin out of its rectangle and each child's
|
|
6
|
+
// cell SQUEEZED the rectangle recharts gave it into what was left. Two faults followed.
|
|
7
|
+
// A fixed 23px is a different share of every group, so a €100 tile in a 61px group was
|
|
8
|
+
// drawn at two thirds of a €100 tile in a 300px one — in a chart whose one promise is that
|
|
9
|
+
// area is share. And the squeeze ran through a cache the group's cell wrote during render
|
|
10
|
+
// for its children's cells to read, which held only because recharts renders a group
|
|
11
|
+
// before its children.
|
|
12
|
+
//
|
|
13
|
+
// So the layout is made here, up front: squarified as recharts does it, with each group
|
|
14
|
+
// asking for its tiles' area PLUS its frame's, and its tiles laid out in its body. A
|
|
15
|
+
// frame's area depends on the rectangle it gets, so the layout is run again with each
|
|
16
|
+
// group's frame as measured until no frame moves by a pixel — two or three rounds.
|
|
17
|
+
|
|
18
|
+
export interface Box {
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** What the layout needs of a node: its key, its value, and a group's nodes. */
|
|
26
|
+
export interface LayoutNode {
|
|
27
|
+
path: string;
|
|
28
|
+
size: number;
|
|
29
|
+
children?: readonly LayoutNode[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** A node as drawn: its rectangle, and for a group the body its nodes fill and whether
|
|
33
|
+
* its band is drawn. Whole pixels, on shared edges, so neighbours meet without a seam. */
|
|
34
|
+
export interface Placed {
|
|
35
|
+
box: Box;
|
|
36
|
+
body?: Box;
|
|
37
|
+
banded?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const PHI = (1 + Math.sqrt(5)) / 2;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A group's band, in px at Normal, × the text size's scale: the 20px floor a tile keeps
|
|
44
|
+
* for its own name, so the group's name sits in it as a tile's does in a tile.
|
|
45
|
+
*/
|
|
46
|
+
export const BAND = 20;
|
|
47
|
+
/**
|
|
48
|
+
* The frame's margin round its body, in px. Each tile keeps its 2px gutter, half of it
|
|
49
|
+
* inside the tile, so 3 leaves one pixel of the frame's own colour between the group's
|
|
50
|
+
* gutter and its tiles' — the frame reads as one outline round the group, not as a gutter
|
|
51
|
+
* that happens to be wider.
|
|
52
|
+
*/
|
|
53
|
+
export const FRAME_MARGIN = 3;
|
|
54
|
+
/**
|
|
55
|
+
* The least of a group's height its body keeps under the band: 1/φ. At Normal that is a
|
|
56
|
+
* group of 61px (20 band + 3 margin = 0.382 of it), whose body of 38px still holds a
|
|
57
|
+
* tile's name and its second line (the note's 36px floor) — so a single row of tiles under
|
|
58
|
+
* the band keeps both. A smaller group draws no band, and its name is in its tiles'
|
|
59
|
+
* accessible names and its tooltip rather than over their area. Since the frame's area is
|
|
60
|
+
* given to the group (above), this bounds the frame's share of the picture, not the tiles'.
|
|
61
|
+
*/
|
|
62
|
+
export const BODY_SHARE = 1 / PHI;
|
|
63
|
+
|
|
64
|
+
/** A group drawn at `box`: whether it has the room for its band (see {@link BODY_SHARE};
|
|
65
|
+
* and 44px across, the floor of a word), and the body its nodes are drawn into. */
|
|
66
|
+
export function groupBody(box: Box, scale: number): { banded: boolean; body: Box } {
|
|
67
|
+
const band = BAND * scale;
|
|
68
|
+
const margin = Math.min(FRAME_MARGIN, Math.floor(box.width / 4), Math.floor(box.height / 4));
|
|
69
|
+
const banded = box.width >= 44 * scale && box.height - band - margin >= box.height * BODY_SHARE;
|
|
70
|
+
const top = banded ? band : margin;
|
|
71
|
+
return {
|
|
72
|
+
banded,
|
|
73
|
+
body: {
|
|
74
|
+
x: box.x + margin,
|
|
75
|
+
y: box.y + top,
|
|
76
|
+
width: Math.max(0, box.width - 2 * margin),
|
|
77
|
+
height: Math.max(0, box.height - top - margin),
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** The worst aspect ratio in a row of `area` along `side`, against the target `ratio`. */
|
|
83
|
+
function worst(area: number, min: number, max: number, side: number, ratio: number): number {
|
|
84
|
+
const along = side * side;
|
|
85
|
+
const across = area * area;
|
|
86
|
+
if (across === 0 || min === 0) return Infinity;
|
|
87
|
+
return Math.max((along * max * ratio) / across, across / (along * min * ratio));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Bruls, Huizing and van Wijk's squarified layout, as recharts runs it: `weights` share
|
|
92
|
+
* out `rect` in order, a row at a time along its shorter side, and a row closes when the
|
|
93
|
+
* next node would make its worst tile further from φ:1 (recharts' default ratio). Returns
|
|
94
|
+
* one rectangle per weight, in order, in fractional pixels.
|
|
95
|
+
*/
|
|
96
|
+
export function squarify(weights: readonly number[], rect: Box, ratio = PHI): Box[] {
|
|
97
|
+
const out: Box[] = weights.map(() => ({ x: rect.x, y: rect.y, width: 0, height: 0 }));
|
|
98
|
+
const sum = weights.reduce((acc, w) => acc + Math.max(0, w), 0);
|
|
99
|
+
if (!(sum > 0) || rect.width <= 0 || rect.height <= 0) return out;
|
|
100
|
+
const areas = weights.map((w) => (Math.max(0, w) * rect.width * rect.height) / sum);
|
|
101
|
+
let { x, y, width, height } = rect;
|
|
102
|
+
let i = 0;
|
|
103
|
+
while (i < areas.length) {
|
|
104
|
+
const side = Math.min(width, height);
|
|
105
|
+
let rowArea = 0;
|
|
106
|
+
let min = Infinity;
|
|
107
|
+
let max = 0;
|
|
108
|
+
let best = Infinity;
|
|
109
|
+
let j = i;
|
|
110
|
+
while (j < areas.length) {
|
|
111
|
+
const a = areas[j]!;
|
|
112
|
+
const score = worst(rowArea + a, Math.min(min, a), Math.max(max, a), side, ratio);
|
|
113
|
+
if (j > i && score > best) break;
|
|
114
|
+
rowArea += a;
|
|
115
|
+
min = Math.min(min, a);
|
|
116
|
+
max = Math.max(max, a);
|
|
117
|
+
best = score;
|
|
118
|
+
j += 1;
|
|
119
|
+
}
|
|
120
|
+
// The last row takes what is left, so rounding never leaves a sliver unpainted.
|
|
121
|
+
const last = j === areas.length;
|
|
122
|
+
if (side === width) {
|
|
123
|
+
// A row along the top, as wide as the space.
|
|
124
|
+
const thick = last ? height : rowArea / width;
|
|
125
|
+
let at = x;
|
|
126
|
+
for (let k = i; k < j; k++) {
|
|
127
|
+
const len = k === j - 1 ? x + width - at : (areas[k]! / rowArea) * width;
|
|
128
|
+
out[k] = { x: at, y, width: len, height: thick };
|
|
129
|
+
at += len;
|
|
130
|
+
}
|
|
131
|
+
y += thick;
|
|
132
|
+
height -= thick;
|
|
133
|
+
} else {
|
|
134
|
+
// A column at the left, as tall as the space.
|
|
135
|
+
const thick = last ? width : rowArea / height;
|
|
136
|
+
let at = y;
|
|
137
|
+
for (let k = i; k < j; k++) {
|
|
138
|
+
const len = k === j - 1 ? y + height - at : (areas[k]! / rowArea) * height;
|
|
139
|
+
out[k] = { x, y: at, width: thick, height: len };
|
|
140
|
+
at += len;
|
|
141
|
+
}
|
|
142
|
+
x += thick;
|
|
143
|
+
width -= thick;
|
|
144
|
+
}
|
|
145
|
+
i = j;
|
|
146
|
+
}
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Whole pixels on the EDGES: neighbours share an edge, so they round it alike. */
|
|
151
|
+
function snap(b: Box): Box {
|
|
152
|
+
const x = Math.round(b.x);
|
|
153
|
+
const y = Math.round(b.y);
|
|
154
|
+
return { x, y, width: Math.round(b.x + b.width) - x, height: Math.round(b.y + b.height) - y };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** The rounds the frames get to settle; three is usual, more only when a band switches. */
|
|
158
|
+
const ROUNDS = 8;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Every node of `nodes` placed in a `width` × `height` chart, by path.
|
|
162
|
+
*
|
|
163
|
+
* Each tile's area is its value's share of what is left for tiles once the frames have
|
|
164
|
+
* theirs — the same density in every group and at the top. A group asks for its tiles'
|
|
165
|
+
* area and its own frame's (band and margin, as {@link groupBody} measures them on the
|
|
166
|
+
* rectangle it got last round), so its body holds exactly its tiles.
|
|
167
|
+
*/
|
|
168
|
+
export function layoutTreemap(
|
|
169
|
+
nodes: readonly LayoutNode[],
|
|
170
|
+
width: number,
|
|
171
|
+
height: number,
|
|
172
|
+
scale: number,
|
|
173
|
+
): Map<string, Placed> {
|
|
174
|
+
const total = nodes.reduce((acc, n) => acc + n.size, 0);
|
|
175
|
+
const frames = new Map<string, number>();
|
|
176
|
+
let placed = new Map<string, Placed>();
|
|
177
|
+
for (let round = 0; round < ROUNDS; round++) {
|
|
178
|
+
const framed = [...frames.values()].reduce((acc, a) => acc + a, 0);
|
|
179
|
+
const spare = width * height - framed;
|
|
180
|
+
// Frames that would take the whole chart (a tiny chart of many groups) leave nothing
|
|
181
|
+
// to share; the tiles then take the density they would have without frames.
|
|
182
|
+
const density = total > 0 ? (spare > 0 ? spare : width * height) / total : 0;
|
|
183
|
+
const need = (n: LayoutNode): number =>
|
|
184
|
+
n.children ? (frames.get(n.path) ?? 0) + n.children.reduce((acc, c) => acc + need(c), 0) : n.size * density;
|
|
185
|
+
let moved = 0;
|
|
186
|
+
placed = new Map();
|
|
187
|
+
const place = (list: readonly LayoutNode[], rect: Box) => {
|
|
188
|
+
const boxes = squarify(
|
|
189
|
+
list.map((n) => need(n)),
|
|
190
|
+
rect,
|
|
191
|
+
);
|
|
192
|
+
list.forEach((n, i) => {
|
|
193
|
+
const box = snap(boxes[i]!);
|
|
194
|
+
if (!n.children) {
|
|
195
|
+
placed.set(n.path, { box });
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const { banded, body } = groupBody(box, scale);
|
|
199
|
+
placed.set(n.path, { box, body, banded });
|
|
200
|
+
const frame = box.width * box.height - body.width * body.height;
|
|
201
|
+
moved = Math.max(moved, Math.abs(frame - (frames.get(n.path) ?? 0)));
|
|
202
|
+
frames.set(n.path, frame);
|
|
203
|
+
place(n.children, body);
|
|
204
|
+
});
|
|
205
|
+
};
|
|
206
|
+
place(nodes, { x: 0, y: 0, width, height });
|
|
207
|
+
if (moved < 1) break;
|
|
208
|
+
}
|
|
209
|
+
return placed;
|
|
210
|
+
}
|