@eifi1/ui-kit 0.51.7 → 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 +141 -23
- 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 +1 -3
- 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.js +2 -1
- 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-subscription.d.ts +20 -8
- package/dist/billing/cancel-subscription.js +7 -5
- 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 +19 -7
- package/dist/billing/plan-switch.js +8 -4
- 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 +13 -0
- package/dist/components/amount-input.js +1 -0
- 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/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 +111 -2
- package/dist/components/combobox-core.js +148 -42
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +1 -1
- package/dist/components/combobox.js +141 -130
- 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 +12 -7
- package/dist/components/data-table-mobile.js +43 -30
- 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 +13 -4
- package/dist/components/data-table.js +139 -36
- 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/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 +148 -140
- 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 +3 -2
- 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.js +3 -1
- package/dist/components/modal.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-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/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/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 +3 -3
- 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 +1 -1
- 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-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.js +19 -3
- 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/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/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.js +5 -14
- 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 +29 -0
- package/dist/lib/text-match.js +20 -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 +13 -3
- package/dist/tour/tour.js +59 -781
- 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/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 +10 -6
- 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 +1 -5
- 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 +4 -1
- 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-subscription.tsx +26 -12
- 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 +26 -12
- 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 +18 -7
- 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/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 +293 -62
- package/src/components/combobox.tsx +183 -153
- 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 +61 -26
- 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 +239 -68
- 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/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 +197 -153
- 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 +10 -4
- package/src/components/measured-grid.tsx +8 -4
- package/src/components/mini-calendar.tsx +6 -5
- package/src/components/modal.tsx +6 -1
- package/src/components/month-grid.tsx +229 -0
- package/src/components/month-picker.tsx +192 -200
- package/src/components/multi-select.tsx +21 -9
- 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/row-actions.tsx +2 -1
- package/src/components/section-nav.tsx +7 -0
- package/src/components/series-chart-axes.ts +3 -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 +2 -2
- 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-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 +32 -3
- 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/date-format.ts +89 -13
- package/src/lib/day-format.ts +96 -0
- 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 +5 -17
- 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 +57 -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 +108 -1202
- package/src/tour/use-tour-progress.ts +1 -1
- 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
|
@@ -42,8 +42,9 @@ import { ColumnSettingsPanel } from "./data-table-column-settings";
|
|
|
42
42
|
import { useLargeText } from "../hooks/use-large-text";
|
|
43
43
|
import { cn } from "../lib/cn";
|
|
44
44
|
import { isFilterActive, resolveFilter, rowMatches } from "./data-table-filters";
|
|
45
|
+
import { matchesSearch, searchWords } from "../lib/text-match";
|
|
45
46
|
import type { ColumnFilter, FilterValue } from "./data-table-filters";
|
|
46
|
-
import { nextSorts } from "./data-table-sort";
|
|
47
|
+
import { compareSortValues, nextSorts } from "./data-table-sort";
|
|
47
48
|
import type { SortCycle, SortDir, SortState } from "./data-table-sort";
|
|
48
49
|
import { Pagination } from "./data-table-pagination";
|
|
49
50
|
import type { SwipeAction } from "./swipeable-row";
|
|
@@ -61,6 +62,7 @@ import {
|
|
|
61
62
|
} from "../i18n/kit-labels";
|
|
62
63
|
import { useEdgeFade } from "../lib/strip-fade";
|
|
63
64
|
import { dirOf, type Direction } from "../lib/direction";
|
|
65
|
+
import { focusContainer, focusFirst, focusIsLost, tabStops, whenFocusLeftForNothing } from "../lib/focus-left";
|
|
64
66
|
|
|
65
67
|
// ---------- Types ----------
|
|
66
68
|
|
|
@@ -71,7 +73,8 @@ export interface DataTableColumn<T> {
|
|
|
71
73
|
/** What a client sort orders the column by. Strings collate in the table's `locale`
|
|
72
74
|
* (digits as numbers, case and accents left out; 0.51.7, audit 2026-10-30 DSP-3),
|
|
73
75
|
* numbers compare as numbers and sort before strings, `null` and `undefined` sort
|
|
74
|
-
* last in either direction.
|
|
76
|
+
* last in either direction. The order is `compareSortValues`, exported for an app's
|
|
77
|
+
* own list beside the table (0.52). */
|
|
75
78
|
sortBy?: (row: T) => string | number | null | undefined;
|
|
76
79
|
filter?: ColumnFilter<T>;
|
|
77
80
|
filterBy?: (row: T) => string;
|
|
@@ -266,8 +269,11 @@ export interface ServerPagination {
|
|
|
266
269
|
}
|
|
267
270
|
|
|
268
271
|
export interface DataTableProps<T> {
|
|
269
|
-
|
|
270
|
-
|
|
272
|
+
/** `readonly` since 0.52 (refactor audit 2026-10-30, API-7): the table never changes the
|
|
273
|
+
* arrays it is handed, so a caller's `as const` list or a query's frozen result needs no
|
|
274
|
+
* copy. Only widens: a mutable array is still one. The same for `columns` and `sorts`. */
|
|
275
|
+
rows: readonly T[];
|
|
276
|
+
columns: readonly DataTableColumn<T>[];
|
|
271
277
|
rowKey: (row: T) => string | number;
|
|
272
278
|
defaultPageSize?: number;
|
|
273
279
|
onRowClick?: (row: T) => void;
|
|
@@ -289,6 +295,11 @@ export interface DataTableProps<T> {
|
|
|
289
295
|
* not wrap table cells, and the absolutely-positioned row overlay that is the
|
|
290
296
|
* usual workaround would sit on top of the per-cell controls these rows carry
|
|
291
297
|
* (status toggles, the selection checkbox, nested links) and swallow them.
|
|
298
|
+
*
|
|
299
|
+
* With `onRowClick` a plain click opens the row through it, in place. Without one
|
|
300
|
+
* (0.52, refactor audit 2026-10-30, DSP-23 b) the click follows the link — through the
|
|
301
|
+
* provider's `linkComponent` for an in-app path, as every kit link — and the phone
|
|
302
|
+
* card is that link too; before, the click was cancelled and opened nothing.
|
|
292
303
|
*/
|
|
293
304
|
rowHref?: (row: T) => string | undefined;
|
|
294
305
|
expandedRow?: (row: T) => ReactNode | null;
|
|
@@ -442,7 +453,7 @@ export interface DataTableProps<T> {
|
|
|
442
453
|
*/
|
|
443
454
|
filters?: FilterState;
|
|
444
455
|
onFiltersChange?: (next: FilterState) => void;
|
|
445
|
-
sorts?: SortState[];
|
|
456
|
+
sorts?: readonly SortState[];
|
|
446
457
|
onSortsChange?: (next: SortState[]) => void;
|
|
447
458
|
/**
|
|
448
459
|
* Controlled page size, as `sorts` above: the table pages by it and hands its pager's
|
|
@@ -931,6 +942,28 @@ export interface DataTableDesktopSwipeActions<T> {
|
|
|
931
942
|
*/
|
|
932
943
|
const FOOTER_CELL = "sticky bottom-0 z-10 bg-surface-2 shadow-[inset_0_2px_0_var(--border-strong)]";
|
|
933
944
|
|
|
945
|
+
/** Where focus that leaves a row is still the row's (DSP-4): an overlay — a confirm, a
|
|
946
|
+
* menu, a sheet — hands it back or closes with the row it was about. The kit marks its
|
|
947
|
+
* own (`data-kit-layer`); an app's dialog says what it is. */
|
|
948
|
+
const OVERLAY_SELECTOR = '[data-kit-layer],[role="dialog"],[role="alertdialog"],[aria-modal="true"],[role="menu"]';
|
|
949
|
+
|
|
950
|
+
/** `rows`' places by `rowKey`, the first row of a key winning as a `findIndex`'s did; the
|
|
951
|
+
* map built at the first lookup (0.52 code review, data-table.tsx). */
|
|
952
|
+
function keyIndex<T>(rows: readonly T[], rowKey: (row: T) => string | number): (key: string | number) => number {
|
|
953
|
+
let at: Map<string | number, number> | null = null;
|
|
954
|
+
return (key) => {
|
|
955
|
+
if (!at) {
|
|
956
|
+
at = new Map();
|
|
957
|
+
for (let i = rows.length - 1; i >= 0; i--) at.set(rowKey(rows[i]), i);
|
|
958
|
+
}
|
|
959
|
+
return at.get(key) ?? -1;
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/** How long a filter's "n of m rows" waits for the typing to pause (DSP-23 d): longer than
|
|
964
|
+
* the gap between two keystrokes, short enough to answer the word just typed. */
|
|
965
|
+
const FILTER_ANNOUNCE_DELAY_MS = 500;
|
|
966
|
+
|
|
934
967
|
// ---------- Phone sort control (keksdose K10) ----------
|
|
935
968
|
|
|
936
969
|
/**
|
|
@@ -962,38 +995,6 @@ export const DEFAULT_DATA_TABLE_SORT_LABELS: DataTableSortLabels = {
|
|
|
962
995
|
|
|
963
996
|
const flipDir = (d: SortDir): SortDir => (d === "asc" ? "desc" : "asc");
|
|
964
997
|
|
|
965
|
-
/**
|
|
966
|
-
* The client sort's and the derived select options' string order (audit 2026-10-30
|
|
967
|
-
* DSP-3): the table locale's collation, digits as numbers ("Item 2" before "Item 10"),
|
|
968
|
-
* case and accents left out (two values that differ only by them go to the next sort
|
|
969
|
-
* key, then keep the order given). `<` and `Array.sort()` compared UTF-16 code units —
|
|
970
|
-
* every lower-case initial after every capital, Ä/Ö/Ü after Z — on the payees, names,
|
|
971
|
-
* insurers and titles all three apps sort. Built once per table locale, not per
|
|
972
|
-
* comparison: `localeCompare` with a locale sets one up on every call, n·log n times a
|
|
973
|
-
* sort. An unknown tag (a typo in a provider's `locale`) throws a RangeError, and a
|
|
974
|
-
* sort is no reason for a table to stop rendering: the runtime's own collation then,
|
|
975
|
-
* as CountrySelect falls back.
|
|
976
|
-
*/
|
|
977
|
-
function sortCollator(locale: string | undefined): Intl.Collator {
|
|
978
|
-
const options: Intl.CollatorOptions = { numeric: true, sensitivity: "base" };
|
|
979
|
-
try {
|
|
980
|
-
return new Intl.Collator(locale, options);
|
|
981
|
-
} catch {
|
|
982
|
-
return new Intl.Collator(undefined, options);
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
/** Two present `sortBy` values, ascending. Strings collate; a number sorts before a
|
|
987
|
-
* string (`<` called that pair equal, so they stayed wherever they were given); any
|
|
988
|
-
* other pair — numbers, and a `Date` an untyped caller returns — keeps `<` / `>`. */
|
|
989
|
-
function compareSortValues(a: string | number, b: string | number, collator: Intl.Collator): number {
|
|
990
|
-
const aText = typeof a === "string";
|
|
991
|
-
const bText = typeof b === "string";
|
|
992
|
-
if (aText && bText) return collator.compare(a, b);
|
|
993
|
-
if (aText !== bText) return aText ? 1 : -1;
|
|
994
|
-
return a < b ? -1 : a > b ? 1 : 0;
|
|
995
|
-
}
|
|
996
|
-
|
|
997
998
|
// `virtualize`'s constants (0.48.2): the band levels a group's `<tbody>` opens with.
|
|
998
999
|
const NO_BANDS: readonly (1 | 2)[] = [];
|
|
999
1000
|
const BAND_1: readonly (1 | 2)[] = [1];
|
|
@@ -1009,6 +1010,21 @@ import { DEFAULT_PERSIST_PREFIX, useTableState, type TableUrlSync } from "./use-
|
|
|
1009
1010
|
import { useMobileReveal } from "./use-mobile-reveal";
|
|
1010
1011
|
import { GROW_CELL_CLASS, GROW_PEER_CELL_CLASS, useColumnFit } from "./data-table-fit";
|
|
1011
1012
|
|
|
1013
|
+
/**
|
|
1014
|
+
* rowMatches for one column's filter state, the text filter's query folded once (0.52
|
|
1015
|
+
* code review, data-table-filters.ts): folded again for every row it tested, a 5000-row
|
|
1016
|
+
* table folded the same query 5000 times per keystroke. Module-private: data-table-filters
|
|
1017
|
+
* is re-exported whole by @eifi1/ui-kit/data-table, and this is no public API.
|
|
1018
|
+
*/
|
|
1019
|
+
function rowMatcher<T>(col: DataTableColumn<T>, state: FilterValue, locale?: string): (row: T) => boolean {
|
|
1020
|
+
const filter = resolveFilter(col);
|
|
1021
|
+
if (filter?.type === "text" && state.type === "text" && state.q.trim()) {
|
|
1022
|
+
const words = searchWords(state.q, locale);
|
|
1023
|
+
return (row) => matchesSearch(words, [filter.getValue(row)], locale);
|
|
1024
|
+
}
|
|
1025
|
+
return (row) => rowMatches(col, row, state, locale);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1012
1028
|
export function DataTable<T>({
|
|
1013
1029
|
rows,
|
|
1014
1030
|
columns: columnsProp,
|
|
@@ -1093,7 +1109,6 @@ export function DataTable<T>({
|
|
|
1093
1109
|
const storageKeyPrefix = storageKeyPrefixProp ?? providerStorageKeyPrefix ?? DEFAULT_PERSIST_PREFIX;
|
|
1094
1110
|
const labels = useMemo(() => resolveDataTableLabels(labelOverrides, labelsProp), [labelOverrides, labelsProp]);
|
|
1095
1111
|
const locale = useKitLocale(localeProp);
|
|
1096
|
-
const collator = useMemo(() => sortCollator(locale), [locale]);
|
|
1097
1112
|
|
|
1098
1113
|
// ---- Row actions ---- (data-table-row-actions.tsx)
|
|
1099
1114
|
// The actions column joins the caller's columns; on a phone the same actions are the
|
|
@@ -1150,13 +1165,15 @@ export function DataTable<T>({
|
|
|
1150
1165
|
// (a drag or "Auto-size columns" before it grew, KS N2) is ignored, and it has no
|
|
1151
1166
|
// handle, so it can never pin it again. Ignored rather than deleted from storage, as
|
|
1152
1167
|
// the widths above; the next resize or auto-size writes a blob without it.
|
|
1168
|
+
// Keyed on the `grow` column's key, not the columns array: an inline `columns={…}`
|
|
1169
|
+
// gave every render new widths, and the fit measured the table for it (DSP-19).
|
|
1170
|
+
const growKey = columns.find((c) => c.grow)?.key;
|
|
1153
1171
|
const widths = useMemo(() => {
|
|
1154
1172
|
if (!resizable) return {};
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
const { [grow]: _ignored, ...rest } = storedWidths;
|
|
1173
|
+
if (!growKey || !(growKey in storedWidths)) return storedWidths;
|
|
1174
|
+
const { [growKey]: _ignored, ...rest } = storedWidths;
|
|
1158
1175
|
return rest;
|
|
1159
|
-
}, [resizable, storedWidths,
|
|
1176
|
+
}, [resizable, storedWidths, growKey]);
|
|
1160
1177
|
const hiddenCols = useMemo(
|
|
1161
1178
|
() => (columnSettings ? storedHiddenCols : new Set<string>()),
|
|
1162
1179
|
[columnSettings, storedHiddenCols],
|
|
@@ -1201,13 +1218,13 @@ export function DataTable<T>({
|
|
|
1201
1218
|
if (v && !seen.has(v)) seen.add(v);
|
|
1202
1219
|
}
|
|
1203
1220
|
map[col.key] = Array.from(seen)
|
|
1204
|
-
.sort(
|
|
1221
|
+
.sort((a, b) => compareSortValues(a, b, locale))
|
|
1205
1222
|
.map((v) => ({ value: v, label: v }));
|
|
1206
1223
|
}
|
|
1207
1224
|
return map;
|
|
1208
1225
|
// `columns` by signature — see the note above the signatures.
|
|
1209
1226
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1210
|
-
}, [columnSig, selectOptionsSig, rows,
|
|
1227
|
+
}, [columnSig, selectOptionsSig, rows, locale]);
|
|
1211
1228
|
|
|
1212
1229
|
const filtered = useMemo(() => {
|
|
1213
1230
|
if (serverRows) return rows;
|
|
@@ -1215,7 +1232,8 @@ export function DataTable<T>({
|
|
|
1215
1232
|
for (const col of columns) {
|
|
1216
1233
|
const state = filters[col.key];
|
|
1217
1234
|
if (!state || !isFilterActive(state)) continue;
|
|
1218
|
-
|
|
1235
|
+
// One matcher per filter, its query folded once (0.52 code review, data-table-filters.ts).
|
|
1236
|
+
result = result.filter(rowMatcher(col, state, locale));
|
|
1219
1237
|
}
|
|
1220
1238
|
return result;
|
|
1221
1239
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -1240,14 +1258,16 @@ export function DataTable<T>({
|
|
|
1240
1258
|
if (av == null && bv == null) continue;
|
|
1241
1259
|
if (av == null) return 1;
|
|
1242
1260
|
if (bv == null) return -1;
|
|
1243
|
-
|
|
1261
|
+
// The order `compareSortValues` exports (0.52): one rule, here and in an app's
|
|
1262
|
+
// own list beside the table. Nulls are last above, in either direction.
|
|
1263
|
+
const order = compareSortValues(av, bv, locale);
|
|
1244
1264
|
if (order !== 0) return dir === "asc" ? order : -order;
|
|
1245
1265
|
}
|
|
1246
1266
|
return 0;
|
|
1247
1267
|
});
|
|
1248
1268
|
return copy;
|
|
1249
1269
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1250
|
-
}, [filtered, sorts, columnSig, serverRows,
|
|
1270
|
+
}, [filtered, sorts, columnSig, serverRows, locale]);
|
|
1251
1271
|
|
|
1252
1272
|
// `paginated={false}` is expressed as "page size = everything" rather than as a
|
|
1253
1273
|
// second code path, so slicing, the page clamp and the range summary all keep
|
|
@@ -1266,10 +1286,16 @@ export function DataTable<T>({
|
|
|
1266
1286
|
const safePage = isServer
|
|
1267
1287
|
? Math.min(Math.max(0, serverPagination!.page), totalPages - 1)
|
|
1268
1288
|
: Math.min(page, totalPages - 1);
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1289
|
+
// Memoised (refactor audit 2026-10-30, DSP-19): the fit, the rows' window and the
|
|
1290
|
+
// range selection compare the page's rows by identity, and a fresh `slice(…)` on every
|
|
1291
|
+
// render of a paginated table — the default — had the fit lay the whole table out on a
|
|
1292
|
+
// ticked box, a keystroke, any parent render.
|
|
1293
|
+
const wholeList = isServer || unpaged || pageSize === Infinity;
|
|
1294
|
+
const slice = useMemo(
|
|
1295
|
+
() =>
|
|
1296
|
+
wholeList ? sorted : sorted.slice(safePage * effectivePageSize, safePage * effectivePageSize + effectivePageSize),
|
|
1297
|
+
[wholeList, sorted, safePage, effectivePageSize],
|
|
1298
|
+
);
|
|
1273
1299
|
|
|
1274
1300
|
const toggleSort = (key: string, shiftKey: boolean) => {
|
|
1275
1301
|
const col = columns.find((c) => c.key === key);
|
|
@@ -1362,6 +1388,16 @@ export function DataTable<T>({
|
|
|
1362
1388
|
// Seeded with the mount value: a live region that speaks on first paint talks over
|
|
1363
1389
|
// the page the user has just opened, and every table on that page does it at once.
|
|
1364
1390
|
const announcedFilterKey = useRef(filterKey);
|
|
1391
|
+
// Spoken once the typing pauses (refactor audit 2026-10-30, DSP-23 d): every keystroke
|
|
1392
|
+
// in a text filter is a new filter, and "12 of 137 rows" on each one — through the live
|
|
1393
|
+
// region's 50 ms reset — talked over the very letters being typed. The count is read
|
|
1394
|
+
// when the sentence goes out, so it is the rows the pause left on screen.
|
|
1395
|
+
const filterSpeech = useRef({ shown: filtered.length, total: rows.length, labels });
|
|
1396
|
+
useLayoutEffect(() => {
|
|
1397
|
+
filterSpeech.current = { shown: filtered.length, total: rows.length, labels };
|
|
1398
|
+
});
|
|
1399
|
+
const filterTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
|
|
1400
|
+
useEffect(() => () => clearTimeout(filterTimer.current), []);
|
|
1365
1401
|
useEffect(() => {
|
|
1366
1402
|
if (announcedFilterKey.current === filterKey) return;
|
|
1367
1403
|
announcedFilterKey.current = filterKey;
|
|
@@ -1370,8 +1406,12 @@ export function DataTable<T>({
|
|
|
1370
1406
|
// filtered total — so the "n of m" sentence has no second number to give here.
|
|
1371
1407
|
// Saying nothing is better than announcing the page size as a result count.
|
|
1372
1408
|
if (serverRows) return;
|
|
1373
|
-
|
|
1374
|
-
|
|
1409
|
+
clearTimeout(filterTimer.current);
|
|
1410
|
+
filterTimer.current = setTimeout(() => {
|
|
1411
|
+
const { shown, total, labels: words } = filterSpeech.current;
|
|
1412
|
+
announce(words.filterResults(shown, total));
|
|
1413
|
+
}, FILTER_ANNOUNCE_DELAY_MS);
|
|
1414
|
+
}, [filterKey, serverRows, announce]);
|
|
1375
1415
|
|
|
1376
1416
|
// 1-based, because that is what the page strip shows and what a person says.
|
|
1377
1417
|
const goToPage = (p: number) => {
|
|
@@ -1390,8 +1430,11 @@ export function DataTable<T>({
|
|
|
1390
1430
|
headRefs,
|
|
1391
1431
|
scroller: () => desktopScroller.current,
|
|
1392
1432
|
enabled: !usePhoneLayout(),
|
|
1393
|
-
// Measured only when one of these changed (0.48.2): not on a ticked box.
|
|
1394
|
-
|
|
1433
|
+
// Measured only when one of these changed (0.48.2): not on a ticked box. The columns
|
|
1434
|
+
// by their keys (DSP-19): an inline `columns={…}` is a new array every render. The
|
|
1435
|
+
// locale (0.52 code review, data-table.tsx): the cells' dates, numbers and the kit's
|
|
1436
|
+
// words follow it under the same rows and keys; the fit adds the headers' drawn text.
|
|
1437
|
+
content: [slice, columnSig, hiddenCols, widths, density, large, locale],
|
|
1395
1438
|
});
|
|
1396
1439
|
const visibleColumns = useMemo(
|
|
1397
1440
|
() => columns.filter((c) => !hiddenCols.has(c.key) && !autoHidden.has(c.key)),
|
|
@@ -1446,7 +1489,10 @@ export function DataTable<T>({
|
|
|
1446
1489
|
const footerLabelCol = showFooter
|
|
1447
1490
|
? (visibleColumns.find((c) => !c.footer && !isTableOwnColumn(c.key)) ?? visibleColumns[0])
|
|
1448
1491
|
: undefined;
|
|
1449
|
-
|
|
1492
|
+
// `footer` keeps its `T[]` parameters: narrowed to `readonly`, a caller's footer typed
|
|
1493
|
+
// `(rows: Row[]) => …` would no longer fit (API-7 only widens). The table hands over the
|
|
1494
|
+
// arrays it holds, as before, and changes neither.
|
|
1495
|
+
const footerValue = (col: DataTableColumn<T>) => col.footer?.(sorted as T[], slice as T[]);
|
|
1450
1496
|
const footerHeadingId = useId();
|
|
1451
1497
|
// Each open row's detail row, for its disclosure button's `aria-controls`.
|
|
1452
1498
|
const detailIdBase = useId();
|
|
@@ -1588,8 +1634,9 @@ export function DataTable<T>({
|
|
|
1588
1634
|
const [phoneLeadHeight, setPhoneLeadHeight] = useState(0);
|
|
1589
1635
|
|
|
1590
1636
|
const { mobileSlice, canRevealMoreMobile, loadMoreRef } = useMobileReveal({
|
|
1591
|
-
|
|
1592
|
-
|
|
1637
|
+
// Read only there; its `T[]` widens to `readonly T[]` with its owner (API-7).
|
|
1638
|
+
rows: sorted as T[],
|
|
1639
|
+
slice: slice as T[],
|
|
1593
1640
|
isServer,
|
|
1594
1641
|
isMdUp,
|
|
1595
1642
|
unpaged,
|
|
@@ -1639,12 +1686,18 @@ export function DataTable<T>({
|
|
|
1639
1686
|
// the pager.
|
|
1640
1687
|
const rowsFocusable = !!onRowClick;
|
|
1641
1688
|
const [focusRowKey, setFocusRowKey] = useState<string | number | null>(null);
|
|
1689
|
+
// The rows' places by key (0.52 code review, data-table.tsx): the tab stop's check
|
|
1690
|
+
// below, the focus note and its recovery each walked the rows calling `rowKey` — on
|
|
1691
|
+
// every render, at each focus, in every commit while a row was noted: under
|
|
1692
|
+
// `virtualize`, 3000 rows, ~15000 calls per arrow step at the table's end. Built at the
|
|
1693
|
+
// first lookup, once per array, so a table nobody focuses builds none. Keyed on the
|
|
1694
|
+
// rows alone: `rowKey` is a pure function of its row, and a call site writes it inline.
|
|
1695
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1696
|
+
const sliceIndex = useMemo(() => keyIndex(slice, rowKey), [slice]);
|
|
1697
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1698
|
+
const mobileIndex = useMemo(() => keyIndex(mobileSlice, rowKey), [mobileSlice]);
|
|
1642
1699
|
const tabRowKey =
|
|
1643
|
-
focusRowKey !== null &&
|
|
1644
|
-
? focusRowKey
|
|
1645
|
-
: slice.length
|
|
1646
|
-
? rowKey(slice[0])
|
|
1647
|
-
: null;
|
|
1700
|
+
focusRowKey !== null && sliceIndex(focusRowKey) !== -1 ? focusRowKey : slice.length ? rowKey(slice[0]) : null;
|
|
1648
1701
|
|
|
1649
1702
|
// What the memoised rows' handlers read at event time (0.48.2, K-052-2): the latest
|
|
1650
1703
|
// props, refreshed every commit, so a row that bailed out of a render still toggles
|
|
@@ -1653,7 +1706,38 @@ export function DataTable<T>({
|
|
|
1653
1706
|
// move over every row, rendered or not: the target is rendered, then focused.
|
|
1654
1707
|
const virtualOn = !!virtualize && isMdUp && slice.length > 0;
|
|
1655
1708
|
const focusRowRef = useRef<((index: number) => void) | undefined>(undefined);
|
|
1709
|
+
// ---- When the focused row leaves (refactor audit 2026-10-30, DSP-4) ----
|
|
1710
|
+
// The row holding the focus — its key, and where it stood — noted as the focus comes
|
|
1711
|
+
// into it (the rows report it, through React, so a menu or a dialog a row opened in a
|
|
1712
|
+
// portal is the row's too). A delete, a status change that filters the row out, an
|
|
1713
|
+
// approval: the row's DOM goes, the focus with it to <body>, and the commit that took it
|
|
1714
|
+
// puts the focus on the row now in its place (below).
|
|
1715
|
+
const heldRow = useRef<{ key: string | number; index: number } | null>(null);
|
|
1716
|
+
const noteRowFocus = (key: string | number) => {
|
|
1717
|
+
heldRow.current = { key, index: (isMdUp ? sliceIndex : mobileIndex)(key) };
|
|
1718
|
+
};
|
|
1719
|
+
// A gone row's note waiting for the overlay that holds the focus (below): watched as
|
|
1720
|
+
// a node until it leaves the page, since its close need not render the table.
|
|
1721
|
+
const overlayWatch = useRef<{ layer: Element; stop: () => void } | null>(null);
|
|
1722
|
+
const settleRef = useRef<() => void>(() => {});
|
|
1723
|
+
const watchOverlay = (layer: Element) => {
|
|
1724
|
+
if (overlayWatch.current?.layer === layer) return;
|
|
1725
|
+
overlayWatch.current?.stop();
|
|
1726
|
+
const observer = new MutationObserver(() => {
|
|
1727
|
+
if (layer.isConnected) return;
|
|
1728
|
+
stop();
|
|
1729
|
+
settleRef.current();
|
|
1730
|
+
});
|
|
1731
|
+
const stop = () => {
|
|
1732
|
+
observer.disconnect();
|
|
1733
|
+
if (overlayWatch.current?.layer === layer) overlayWatch.current = null;
|
|
1734
|
+
};
|
|
1735
|
+
observer.observe(layer.ownerDocument.body, { childList: true, subtree: true });
|
|
1736
|
+
overlayWatch.current = { layer, stop };
|
|
1737
|
+
};
|
|
1738
|
+
useEffect(() => () => overlayWatch.current?.stop(), []);
|
|
1656
1739
|
const latestRowCtx: DataTableRowCtx<T> = {
|
|
1740
|
+
noteFocus: noteRowFocus,
|
|
1657
1741
|
moveFocus: virtualOn
|
|
1658
1742
|
? (from, key) => {
|
|
1659
1743
|
const target = rowNavTarget(from, key, slice.length);
|
|
@@ -1698,7 +1782,7 @@ export function DataTable<T>({
|
|
|
1698
1782
|
|
|
1699
1783
|
// One mobile card (`MobileRow`, data-table-mobile.tsx). A function so the flat list
|
|
1700
1784
|
// and the grouped list (below) share identical row markup.
|
|
1701
|
-
const renderMobileRow = (row: T) => {
|
|
1785
|
+
const renderMobileRow = (row: T, index: number) => {
|
|
1702
1786
|
const key = rowKey(row);
|
|
1703
1787
|
const expanded = isExpanded?.(row) ?? false;
|
|
1704
1788
|
return (
|
|
@@ -1706,6 +1790,7 @@ export function DataTable<T>({
|
|
|
1706
1790
|
key={key}
|
|
1707
1791
|
ctx={rowCtx}
|
|
1708
1792
|
rowKey={key}
|
|
1793
|
+
rowIndex={index}
|
|
1709
1794
|
row={row}
|
|
1710
1795
|
expanded={expanded}
|
|
1711
1796
|
expansion={expanded ? openedRowContent(row) : null}
|
|
@@ -1801,15 +1886,72 @@ export function DataTable<T>({
|
|
|
1801
1886
|
focusRowRef.current = focusRowAt;
|
|
1802
1887
|
}, [focusRowAt]);
|
|
1803
1888
|
|
|
1889
|
+
// The commit that took the focused row (DSP-4): if the focus fell with it — to <body>,
|
|
1890
|
+
// not into a dialog or a field the app chose — it goes to the row now at that index,
|
|
1891
|
+
// else the last row, else the table itself (`tabIndex=-1` while empty, named by
|
|
1892
|
+
// `labels.table`); the card on a phone. A focusable row (`onRowClick`) takes it itself,
|
|
1893
|
+
// any other its first control. The remaining count is said, as a filter's is: the
|
|
1894
|
+
// focus moved without the user moving it. translation-review's `keepFocusAt` is the
|
|
1895
|
+
// kit's earlier copy of the rule, for its groups.
|
|
1896
|
+
//
|
|
1897
|
+
// Every commit while a row is noted, a lookup by its key. A focus the user took
|
|
1898
|
+
// elsewhere drops the note (`onBlur` on the root, below), and since the 0.52 code review
|
|
1899
|
+
// so does one that went to nothing — a click on the page's background: kept, it was the
|
|
1900
|
+
// one case where a later removal (a refetch, a sync) pulled the focus back in.
|
|
1901
|
+
const settleFocus = () => {
|
|
1902
|
+
const held = heldRow.current;
|
|
1903
|
+
if (!held) return;
|
|
1904
|
+
const now = (isMdUp ? sliceIndex : mobileIndex)(held.key);
|
|
1905
|
+
if (now !== -1) {
|
|
1906
|
+
held.index = now;
|
|
1907
|
+
return;
|
|
1908
|
+
}
|
|
1909
|
+
const list = isMdUp ? tableRef.current : phoneListRef.current;
|
|
1910
|
+
// In an overlay — a confirm, an edit drawer — the focus is not lost yet: the overlay
|
|
1911
|
+
// hands it back to its opener as it closes, and the opener was in the row (0.52 code
|
|
1912
|
+
// review, data-table.tsx: an optimistic delete with its confirm still open dropped the
|
|
1913
|
+
// note, and the confirm's close dropped the focus to <body>). The note waits for the
|
|
1914
|
+
// overlay to leave the page, watched as a node: the table need not render when it does
|
|
1915
|
+
// (`useConfirm`'s provider, a Modal's exit). Not an overlay the table itself is in.
|
|
1916
|
+
const layer = focusIsLost() ? null : document.activeElement?.closest(OVERLAY_SELECTOR);
|
|
1917
|
+
if (layer && !(list && layer.contains(list))) {
|
|
1918
|
+
watchOverlay(layer);
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
heldRow.current = null;
|
|
1922
|
+
overlayWatch.current?.stop();
|
|
1923
|
+
if (!list || !focusIsLost()) return;
|
|
1924
|
+
const shown = isMdUp ? slice : mobileSlice;
|
|
1925
|
+
const at = shown.length === 0 ? -1 : Math.min(Math.max(held.index, 0), shown.length - 1);
|
|
1926
|
+
if (at === -1) list.focus();
|
|
1927
|
+
else if (isMdUp && virtualOn && rowsFocusable) focusRowRef.current?.(at);
|
|
1928
|
+
else {
|
|
1929
|
+
const row = list.querySelector<HTMLElement>(
|
|
1930
|
+
isMdUp ? `:scope > tbody > tr[data-row-index="${at}"]` : `:scope > li[data-row-index="${at}"]`,
|
|
1931
|
+
);
|
|
1932
|
+
// Each of the row's stops in turn, then the table (0.52 code review): `focus()` on
|
|
1933
|
+
// one that cannot hold it — `display: none`, in a closed <details>, a hidden input —
|
|
1934
|
+
// does nothing, and the focus stayed on <body>.
|
|
1935
|
+
const stops = !row ? [] : isMdUp && rowsFocusable ? [row] : tabStops(row, { includeSelf: false });
|
|
1936
|
+
if (!focusFirst(stops)) focusContainer(list);
|
|
1937
|
+
}
|
|
1938
|
+
announce(labels.filterResults(paginationTotal, isServer ? paginationTotal : rows.length));
|
|
1939
|
+
};
|
|
1940
|
+
useLayoutEffect(() => {
|
|
1941
|
+
settleRef.current = settleFocus;
|
|
1942
|
+
settleFocus();
|
|
1943
|
+
});
|
|
1944
|
+
|
|
1804
1945
|
// `mobileGroupBy` may be a desktop `groupBy` level (0.48), its label and end slot too.
|
|
1805
1946
|
const mobileLevel = typeof mobileGroupBy === "function" ? null : (mobileGroupBy ?? null);
|
|
1806
1947
|
const mobileKey = typeof mobileGroupBy === "function" ? mobileGroupBy : mobileGroupBy?.key;
|
|
1807
|
-
|
|
1808
|
-
|
|
1948
|
+
// `start`: the section's first card's place in the list (its `data-row-index`, DSP-4).
|
|
1949
|
+
const mobileGroups: { key: string; rows: T[]; start: number }[] | null = mobileKey
|
|
1950
|
+
? mobileSlice.reduce<{ key: string; rows: T[]; start: number }[]>((acc, row, i) => {
|
|
1809
1951
|
const key = mobileKey(row);
|
|
1810
1952
|
const last = acc[acc.length - 1];
|
|
1811
1953
|
if (last && last.key === key) last.rows.push(row);
|
|
1812
|
-
else acc.push({ key, rows: [row] });
|
|
1954
|
+
else acc.push({ key, rows: [row], start: i });
|
|
1813
1955
|
return acc;
|
|
1814
1956
|
}, [])
|
|
1815
1957
|
: null;
|
|
@@ -1833,6 +1975,24 @@ export function DataTable<T>({
|
|
|
1833
1975
|
// `<main>` and every `FillHeight` between it and this table key off it with
|
|
1834
1976
|
// `has-[[data-fill-height]]`, so a page asks for the fill by passing the prop.
|
|
1835
1977
|
data-fill-height={fillHeight ? "" : undefined}
|
|
1978
|
+
// The focused row's note (DSP-4): cleared on the way down to whatever takes the
|
|
1979
|
+
// focus, and set again on the way up by the row that holds it. Focus leaving for
|
|
1980
|
+
// something real outside the table drops it — unless that is an overlay (a confirm,
|
|
1981
|
+
// a menu), which hands the focus back, or closes with the row it asked about.
|
|
1982
|
+
onFocusCapture={() => {
|
|
1983
|
+
heldRow.current = null;
|
|
1984
|
+
overlayWatch.current?.stop();
|
|
1985
|
+
}}
|
|
1986
|
+
onBlur={(e) => {
|
|
1987
|
+
const to = e.relatedTarget;
|
|
1988
|
+
if (to instanceof Element && !to.closest(OVERLAY_SELECTOR)) heldRow.current = null;
|
|
1989
|
+
// Focus that left for nothing — a click on the page (0.52 code review): no
|
|
1990
|
+
// element to say where, and a later removal of the row is no longer the user's.
|
|
1991
|
+
const held = heldRow.current;
|
|
1992
|
+
whenFocusLeftForNothing(e, () => {
|
|
1993
|
+
if (heldRow.current === held) heldRow.current = null;
|
|
1994
|
+
});
|
|
1995
|
+
}}
|
|
1836
1996
|
className={cn(
|
|
1837
1997
|
"group/table",
|
|
1838
1998
|
frame ? "overflow-clip" : "min-w-0",
|
|
@@ -1924,6 +2084,10 @@ export function DataTable<T>({
|
|
|
1924
2084
|
)}
|
|
1925
2085
|
<ul
|
|
1926
2086
|
ref={phoneListRef}
|
|
2087
|
+
// Named as the table is, and focusable while empty: where the focus goes when
|
|
2088
|
+
// the last card leaves (DSP-4).
|
|
2089
|
+
aria-label={labels.table}
|
|
2090
|
+
tabIndex={mobileSlice.length === 0 ? -1 : undefined}
|
|
1927
2091
|
className={cn(
|
|
1928
2092
|
"divide-y divide-subtle",
|
|
1929
2093
|
// Under `fillHeight` the list takes the room its parent gives it, and in a
|
|
@@ -1964,7 +2128,7 @@ export function DataTable<T>({
|
|
|
1964
2128
|
<span className="ms-auto tabular-nums">{mobileLevel.end(g.key, g.rows)}</span>
|
|
1965
2129
|
)}
|
|
1966
2130
|
</li>
|
|
1967
|
-
{g.rows.map(renderMobileRow)}
|
|
2131
|
+
{g.rows.map((r, i) => renderMobileRow(r, g.start + i))}
|
|
1968
2132
|
</Fragment>
|
|
1969
2133
|
))
|
|
1970
2134
|
: mobileSlice.map(renderMobileRow)}
|
|
@@ -2047,6 +2211,11 @@ export function DataTable<T>({
|
|
|
2047
2211
|
behind it shows, so the panel names the row it opened from. */}
|
|
2048
2212
|
<FullBleedDialog
|
|
2049
2213
|
open={dialogOpen}
|
|
2214
|
+
// The open row's editor is the row's focus too: a Delete in it takes the row,
|
|
2215
|
+
// and the dialog with it (DSP-4).
|
|
2216
|
+
onFocus={() => {
|
|
2217
|
+
if (mobileDialogRow) noteRowFocus(rowKey(mobileDialogRow));
|
|
2218
|
+
}}
|
|
2050
2219
|
onClose={closeDialog}
|
|
2051
2220
|
closeLabel={labels.close}
|
|
2052
2221
|
header={mobileDialogRow ? mobilePrimaryCol?.cell(mobileDialogRow) : null}
|
|
@@ -2091,6 +2260,8 @@ export function DataTable<T>({
|
|
|
2091
2260
|
className={cn("w-full", compact ? "text-xs" : "text-sm")}
|
|
2092
2261
|
data-fit-grow={growDrawn ? "" : undefined}
|
|
2093
2262
|
aria-label={labels.table}
|
|
2263
|
+
// Focusable while empty: where the focus goes when the last row leaves (DSP-4).
|
|
2264
|
+
tabIndex={slice.length === 0 ? -1 : undefined}
|
|
2094
2265
|
aria-busy={isLoading || undefined}
|
|
2095
2266
|
// `virtualize` (0.48.2): every row counted, rendered or not.
|
|
2096
2267
|
aria-rowcount={rowWindow?.rowCount}
|