@eifi1/ui-kit 0.34.0 → 0.36.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 +115 -41
- package/dist/admin/role-select.d.ts +3 -2
- package/dist/admin/role-select.js +2 -0
- package/dist/admin/role-select.js.map +1 -1
- package/dist/billing/billing-banner.d.ts +5 -2
- package/dist/billing/billing-banner.js.map +1 -1
- package/dist/billing/plan-limit-notice.d.ts +5 -2
- package/dist/billing/plan-limit-notice.js.map +1 -1
- package/dist/chart.js.map +1 -1
- package/dist/components/amount-input.d.ts +2 -5
- package/dist/components/amount-input.js +2 -2
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.d.ts +2 -2
- package/dist/components/autocomplete.js +2 -1
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/button-look.d.ts +1 -1
- package/dist/components/button-look.js +9 -4
- package/dist/components/button-look.js.map +1 -1
- package/dist/components/calculator.d.ts +1 -4
- package/dist/components/calculator.js +1 -3
- package/dist/components/calculator.js.map +1 -1
- package/dist/components/chart-zoom.d.ts +0 -37
- package/dist/components/chart-zoom.js +1 -28
- package/dist/components/chart-zoom.js.map +1 -1
- package/dist/components/checkbox-group.d.ts +5 -2
- package/dist/components/checkbox-group.js +15 -4
- package/dist/components/checkbox-group.js.map +1 -1
- package/dist/components/chip-input.d.ts +0 -4
- package/dist/components/chip-input.js +1 -5
- package/dist/components/chip-input.js.map +1 -1
- package/dist/components/column-mapper.d.ts +5 -3
- package/dist/components/column-mapper.js +2 -0
- package/dist/components/column-mapper.js.map +1 -1
- package/dist/components/combobox.d.ts +3 -3
- package/dist/components/combobox.js +2 -1
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/copy-button.d.ts +5 -1
- package/dist/components/copy-button.js.map +1 -1
- package/dist/components/country-select.d.ts +3 -3
- package/dist/components/country-select.js +3 -0
- package/dist/components/country-select.js.map +1 -1
- package/dist/components/currency-option-list.d.ts +3 -8
- package/dist/components/currency-option-list.js +1 -29
- package/dist/components/currency-option-list.js.map +1 -1
- package/dist/components/currency-select.d.ts +3 -2
- package/dist/components/currency-select.js +10 -1
- package/dist/components/currency-select.js.map +1 -1
- package/dist/components/danger-confirm.d.ts +3 -3
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/data-table-filter-popover.d.ts +1 -1
- package/dist/components/data-table-filter-popover.js +1 -1
- package/dist/components/data-table-filter-popover.js.map +1 -1
- package/dist/components/data-table-labels.d.ts +1 -42
- package/dist/components/data-table-labels.js +2 -31
- package/dist/components/data-table-labels.js.map +1 -1
- package/dist/components/data-table-shared.d.ts +17 -1
- package/dist/components/data-table-shared.js +22 -0
- package/dist/components/data-table-shared.js.map +1 -1
- package/dist/components/data-table.d.ts +12 -2
- package/dist/components/data-table.js +18 -14
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-field.d.ts +2 -1
- package/dist/components/date-field.js.map +1 -1
- package/dist/components/date-picker.js +3 -0
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/date-range-picker.js +3 -0
- package/dist/components/date-range-picker.js.map +1 -1
- package/dist/components/dialog-frame.d.ts +3 -1
- package/dist/components/dialog-frame.js.map +1 -1
- package/dist/components/dropdown.d.ts +18 -15
- package/dist/components/dropdown.js +11 -3
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/entity-combobox.d.ts +3 -3
- package/dist/components/entity-combobox.js +2 -1
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/field-base.d.ts +0 -5
- package/dist/components/field-base.js +0 -5
- package/dist/components/field-base.js.map +1 -1
- package/dist/components/field-parts.d.ts +69 -22
- package/dist/components/field-parts.js +33 -19
- package/dist/components/field-parts.js.map +1 -1
- package/dist/components/field-strip.d.ts +9 -23
- package/dist/components/field-strip.js +26 -23
- package/dist/components/field-strip.js.map +1 -1
- package/dist/components/field-sync.d.ts +0 -4
- package/dist/components/field-sync.js +0 -4
- package/dist/components/field-sync.js.map +1 -1
- package/dist/components/field.d.ts +7 -6
- package/dist/components/field.js +24 -15
- package/dist/components/field.js.map +1 -1
- package/dist/components/full-bleed-dialog.js +2 -2
- package/dist/components/full-bleed-dialog.js.map +1 -1
- package/dist/components/help-popover.d.ts +9 -7
- package/dist/components/help-popover.js.map +1 -1
- package/dist/components/hover-menu.d.ts +6 -13
- package/dist/components/hover-menu.js +3 -3
- package/dist/components/hover-menu.js.map +1 -1
- package/dist/components/icon-picker.d.ts +3 -2
- package/dist/components/icon-picker.js +3 -0
- package/dist/components/icon-picker.js.map +1 -1
- package/dist/components/inline-entity-combobox.d.ts +3 -3
- package/dist/components/inline-entity-combobox.js +2 -1
- package/dist/components/inline-entity-combobox.js.map +1 -1
- package/dist/components/input.d.ts +2 -2
- package/dist/components/input.js +2 -1
- package/dist/components/input.js.map +1 -1
- package/dist/components/modal.d.ts +9 -1
- package/dist/components/modal.js +7 -4
- package/dist/components/modal.js.map +1 -1
- package/dist/components/month-picker.d.ts +2 -1
- package/dist/components/month-picker.js +8 -1
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.d.ts +2 -2
- 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 +7 -18
- package/dist/components/multi-select.js +8 -10
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/number-input.d.ts +2 -5
- package/dist/components/number-input.js +2 -4
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numeric-field.d.ts +5 -2
- package/dist/components/numeric-field.js +4 -1
- package/dist/components/numeric-field.js.map +1 -1
- package/dist/components/one-time-code-input.d.ts +2 -1
- package/dist/components/one-time-code-input.js +2 -1
- package/dist/components/one-time-code-input.js.map +1 -1
- package/dist/components/phone-input.d.ts +1 -1
- package/dist/components/phone-input.js +4 -0
- package/dist/components/phone-input.js.map +1 -1
- package/dist/components/popover.js +3 -3
- package/dist/components/popover.js.map +1 -1
- package/dist/components/select.d.ts +4 -3
- package/dist/components/select.js +2 -1
- package/dist/components/select.js.map +1 -1
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/server-wake.d.ts +0 -6
- package/dist/components/server-wake.js.map +1 -1
- package/dist/components/settings-fields.d.ts +4 -2
- package/dist/components/settings-fields.js.map +1 -1
- package/dist/components/slider.d.ts +3 -2
- package/dist/components/slider.js +7 -1
- package/dist/components/slider.js.map +1 -1
- package/dist/components/stat-tile.d.ts +8 -2
- package/dist/components/stat-tile.js +2 -11
- package/dist/components/stat-tile.js.map +1 -1
- package/dist/components/swatch-picker.d.ts +3 -2
- package/dist/components/swatch-picker.js +3 -0
- package/dist/components/swatch-picker.js.map +1 -1
- package/dist/components/swipeable-row.d.ts +2 -17
- package/dist/components/swipeable-row.js +11 -16
- package/dist/components/swipeable-row.js.map +1 -1
- package/dist/components/text-link.js +3 -1
- package/dist/components/text-link.js.map +1 -1
- package/dist/components/textarea.d.ts +2 -1
- package/dist/components/textarea.js +9 -3
- package/dist/components/textarea.js.map +1 -1
- package/dist/components/toggle-group.d.ts +2 -2
- package/dist/components/toggle-group.js +7 -3
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/tooltip.d.ts +9 -1
- package/dist/components/tooltip.js +20 -5
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/translation-review.d.ts +10 -2
- package/dist/components/translation-review.js +11 -3
- package/dist/components/translation-review.js.map +1 -1
- package/dist/components/use-table-state.d.ts +31 -3
- package/dist/components/use-table-state.js +53 -8
- package/dist/components/use-table-state.js.map +1 -1
- package/dist/components/user-avatar.d.ts +2 -2
- package/dist/components/user-avatar.js.map +1 -1
- package/dist/components/wizard-stepper.d.ts +1 -4
- package/dist/components/wizard-stepper.js +2 -3
- package/dist/components/wizard-stepper.js.map +1 -1
- package/dist/currencies.d.ts +23 -0
- package/dist/currencies.js +38 -0
- package/dist/currencies.js.map +1 -0
- package/dist/demo/demo-banner.d.ts +7 -2
- package/dist/demo/demo-banner.js.map +1 -1
- package/dist/eslint/index.d.ts +83 -0
- package/dist/eslint/index.js +69 -0
- package/dist/eslint/index.js.map +1 -0
- package/dist/eslint/role-utilities.d.ts +48 -0
- package/dist/eslint/role-utilities.generated.d.ts +2 -0
- package/dist/eslint/role-utilities.generated.js +143 -0
- package/dist/eslint/role-utilities.generated.js.map +1 -0
- package/dist/eslint/role-utilities.js +43 -0
- package/dist/eslint/role-utilities.js.map +1 -0
- package/dist/feedback/feedback-menu.d.ts +2 -2
- package/dist/feedback/feedback-menu.js.map +1 -1
- package/dist/feedback/feedback-thread.d.ts +3 -8
- package/dist/feedback/feedback-thread.js +0 -2
- package/dist/feedback/feedback-thread.js.map +1 -1
- package/dist/hooks/use-dismiss.d.ts +16 -3
- package/dist/hooks/use-dismiss.js +14 -2
- package/dist/hooks/use-dismiss.js.map +1 -1
- package/dist/i18n/defaults.js +5 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.js +97 -1
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +29 -4
- package/dist/i18n/kit-labels.js +21 -1
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/en.js +104 -3
- package/dist/i18n/locales/en.js.map +3 -3
- package/dist/i18n/locales/es.js +95 -1
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.js +99 -3
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.js +95 -1
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.js +99 -3
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.js +95 -1
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.js +13 -0
- package/dist/i18n/review.js.map +1 -1
- package/dist/i18n/shared-labels.js +3 -1
- package/dist/i18n/shared-labels.js.map +1 -1
- package/dist/index.d.ts +23 -1
- package/dist/index.js +40 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/device-settings.d.ts +72 -0
- package/dist/lib/device-settings.js +64 -0
- package/dist/lib/device-settings.js.map +1 -0
- package/dist/lib/plain-text.d.ts +11 -0
- package/dist/lib/plain-text.js +16 -0
- package/dist/lib/plain-text.js.map +1 -0
- package/dist/lib/refs.d.ts +13 -0
- package/dist/lib/refs.js +15 -0
- package/dist/lib/refs.js.map +1 -0
- package/dist/lib/safe-storage.d.ts +6 -0
- package/dist/lib/safe-storage.js +11 -0
- package/dist/lib/safe-storage.js.map +1 -1
- package/dist/notifications/notification-parts.d.ts +39 -0
- package/dist/notifications/notification-parts.js +47 -0
- package/dist/notifications/notification-parts.js.map +1 -0
- package/dist/notifications/notification-types-setting.d.ts +62 -0
- package/dist/notifications/notification-types-setting.js +192 -0
- package/dist/notifications/notification-types-setting.js.map +1 -0
- package/dist/notifications/notification-types.d.ts +75 -0
- package/dist/notifications/notification-types.js +2 -0
- package/dist/notifications/notification-types.js.map +1 -0
- package/dist/notifications/notifications-labels.d.ts +131 -0
- package/dist/notifications/notifications-labels.js +83 -0
- package/dist/notifications/notifications-labels.js.map +1 -0
- package/dist/notifications/push-device-setting.d.ts +37 -0
- package/dist/notifications/push-device-setting.js +164 -0
- package/dist/notifications/push-device-setting.js.map +1 -0
- package/dist/notifications/push-devices-setting.d.ts +44 -0
- package/dist/notifications/push-devices-setting.js +203 -0
- package/dist/notifications/push-devices-setting.js.map +1 -0
- package/dist/notifications/quiet-hours-setting.d.ts +47 -0
- package/dist/notifications/quiet-hours-setting.js +131 -0
- package/dist/notifications/quiet-hours-setting.js.map +1 -0
- package/dist/notifications/time-zone-select.d.ts +50 -0
- package/dist/notifications/time-zone-select.js +76 -0
- package/dist/notifications/time-zone-select.js.map +1 -0
- package/dist/notifications/unsubscribe-panel.d.ts +53 -0
- package/dist/notifications/unsubscribe-panel.js +139 -0
- package/dist/notifications/unsubscribe-panel.js.map +1 -0
- package/dist/notifications/use-push-device.d.ts +122 -0
- package/dist/notifications/use-push-device.js +230 -0
- package/dist/notifications/use-push-device.js.map +1 -0
- package/dist/rhf/fields.d.ts +36 -29
- package/dist/rhf/fields.js +51 -22
- package/dist/rhf/fields.js.map +1 -1
- package/dist/rhf/form-core.d.ts +5 -4
- package/dist/rhf/form-core.js.map +1 -1
- package/dist/rhf/form.d.ts +7 -36
- package/dist/rhf/form.js +1 -16
- package/dist/rhf/form.js.map +1 -1
- package/dist/rhf/line-items.d.ts +1 -1
- package/dist/rhf/line-items.js.map +1 -1
- package/dist/rhf/use-rhf-wizard-step.js.map +1 -1
- package/dist/rhf.js.map +1 -1
- package/dist/settings/device-reset-setting-labels.d.ts +3 -0
- package/dist/settings/device-reset-setting-labels.js +15 -0
- package/dist/settings/device-reset-setting-labels.js.map +1 -0
- package/dist/settings/device-reset-setting.d.ts +58 -0
- package/dist/settings/device-reset-setting.js +51 -0
- package/dist/settings/device-reset-setting.js.map +1 -0
- package/dist/shell/app-shell.js +5 -0
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/option-switcher-menu.d.ts +5 -17
- package/dist/shell/option-switcher-menu.js +1 -3
- package/dist/shell/option-switcher-menu.js.map +1 -1
- package/dist/shell/role-switcher.d.ts +1 -4
- package/dist/shell/role-switcher.js +2 -3
- package/dist/shell/role-switcher.js.map +1 -1
- package/dist/shell/topbar-action-menu.d.ts +7 -19
- package/dist/shell/topbar-action-menu.js +1 -3
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell/topbar-controls.d.ts +3 -12
- package/dist/shell/topbar-controls.js +6 -9
- package/dist/shell/topbar-controls.js.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +2 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/viewport.d.ts +25 -2
- package/dist/testing/viewport.js +61 -10
- package/dist/testing/viewport.js.map +1 -1
- package/dist/theme/contrast-tokens.d.ts +42 -4
- package/dist/theme/contrast-tokens.js +56 -9
- package/dist/theme/contrast-tokens.js.map +1 -1
- package/dist/theme/contrast.d.ts +4 -2
- package/dist/theme/contrast.js +13 -0
- package/dist/theme/contrast.js.map +1 -1
- package/dist/theme/palette-derive.d.ts +15 -1
- package/dist/theme/palette-derive.js +37 -8
- package/dist/theme/palette-derive.js.map +1 -1
- package/dist/theme/palette-presets.d.ts +2 -8
- package/dist/theme/palette-presets.js +5 -284
- package/dist/theme/palette-presets.js.map +1 -1
- package/dist/theme/palette-store.js +6 -0
- package/dist/theme/palette-store.js.map +1 -1
- package/dist/theme/text-size.js +6 -0
- package/dist/theme/text-size.js.map +1 -1
- package/dist/theme/theme-store.js +6 -0
- package/dist/theme/theme-store.js.map +1 -1
- package/dist/wizard/types.d.ts +0 -5
- package/dist/wizard/types.js +1 -5
- package/dist/wizard/types.js.map +1 -1
- package/package.json +9 -1
- package/src/admin/role-select.tsx +4 -1
- package/src/billing/billing-banner.tsx +5 -2
- package/src/billing/plan-limit-notice.tsx +5 -2
- package/src/chart.ts +5 -3
- package/src/components/amount-input.tsx +4 -7
- package/src/components/autocomplete.tsx +5 -2
- package/src/components/button-look.ts +15 -5
- package/src/components/calculator.tsx +2 -7
- package/src/components/chart-zoom.tsx +4 -47
- package/src/components/checkbox-group.tsx +22 -4
- package/src/components/chip-input.tsx +0 -7
- package/src/components/column-mapper.tsx +6 -2
- package/src/components/combobox.tsx +6 -3
- package/src/components/copy-button.tsx +5 -1
- package/src/components/country-select.tsx +6 -1
- package/src/components/currency-option-list.tsx +8 -42
- package/src/components/currency-select.tsx +12 -3
- package/src/components/danger-confirm.tsx +3 -3
- package/src/components/data-table-filter-popover.tsx +2 -1
- package/src/components/data-table-labels.ts +2 -84
- package/src/components/data-table-shared.tsx +55 -2
- package/src/components/data-table.tsx +29 -17
- package/src/components/date-field.tsx +2 -2
- package/src/components/date-picker.tsx +3 -0
- package/src/components/date-range-picker.tsx +3 -0
- package/src/components/dialog-frame.tsx +3 -1
- package/src/components/dropdown.tsx +42 -18
- package/src/components/entity-combobox.tsx +6 -3
- package/src/components/field-base.tsx +0 -11
- package/src/components/field-parts.tsx +112 -38
- package/src/components/field-strip.tsx +12 -27
- package/src/components/field-sync.tsx +0 -7
- package/src/components/field.tsx +32 -19
- package/src/components/full-bleed-dialog.tsx +4 -3
- package/src/components/help-popover.tsx +9 -7
- package/src/components/hover-menu.tsx +12 -16
- package/src/components/icon-picker.tsx +8 -3
- package/src/components/inline-entity-combobox.tsx +6 -3
- package/src/components/input.tsx +4 -2
- package/src/components/modal.tsx +20 -4
- package/src/components/month-picker.tsx +10 -3
- package/src/components/multi-entity-combobox.tsx +5 -2
- package/src/components/multi-select.tsx +19 -31
- package/src/components/number-input.tsx +5 -10
- package/src/components/numeric-field.ts +10 -2
- package/src/components/one-time-code-input.tsx +5 -3
- package/src/components/phone-input.tsx +4 -0
- package/src/components/popover.tsx +8 -4
- package/src/components/select.tsx +6 -3
- package/src/components/series-chart.tsx +1 -1
- package/src/components/server-wake.tsx +0 -6
- package/src/components/settings-fields.tsx +4 -2
- package/src/components/slider.tsx +10 -3
- package/src/components/stat-tile.tsx +11 -20
- package/src/components/swatch-picker.tsx +9 -4
- package/src/components/swipeable-row.tsx +15 -37
- package/src/components/text-link.tsx +3 -1
- package/src/components/textarea.tsx +11 -4
- package/src/components/toggle-group.tsx +21 -5
- package/src/components/tooltip.tsx +37 -6
- package/src/components/translation-review.tsx +25 -7
- package/src/components/use-table-state.ts +91 -10
- package/src/components/user-avatar.tsx +2 -2
- package/src/components/wizard-stepper.tsx +2 -6
- package/src/currencies.ts +70 -0
- package/src/demo/demo-banner.tsx +7 -2
- package/src/eslint/index.ts +161 -0
- package/src/eslint/role-utilities.generated.ts +146 -0
- package/src/eslint/role-utilities.ts +99 -0
- package/src/feedback/feedback-menu.tsx +2 -2
- package/src/feedback/feedback-thread.tsx +3 -8
- package/src/hooks/use-dismiss.ts +39 -4
- package/src/i18n/defaults.ts +4 -0
- package/src/i18n/german.ts +113 -0
- package/src/i18n/kit-labels.tsx +66 -6
- package/src/i18n/locales/en.ts +6 -0
- package/src/i18n/locales/es.ts +106 -0
- package/src/i18n/locales/fr.ts +109 -2
- package/src/i18n/locales/hu.ts +104 -0
- package/src/i18n/locales/it.ts +108 -2
- package/src/i18n/locales/zh.ts +96 -0
- package/src/i18n/review.ts +13 -0
- package/src/i18n/shared-labels.ts +2 -0
- package/src/index.ts +53 -1
- package/src/lib/device-settings.ts +146 -0
- package/src/lib/plain-text.ts +22 -0
- package/src/lib/refs.ts +22 -0
- package/src/lib/safe-storage.ts +16 -0
- package/src/notifications/notification-parts.tsx +83 -0
- package/src/notifications/notification-types-setting.tsx +309 -0
- package/src/notifications/notification-types.ts +80 -0
- package/src/notifications/notifications-labels.ts +238 -0
- package/src/notifications/push-device-setting.tsx +224 -0
- package/src/notifications/push-devices-setting.tsx +306 -0
- package/src/notifications/quiet-hours-setting.tsx +185 -0
- package/src/notifications/time-zone-select.tsx +126 -0
- package/src/notifications/unsubscribe-panel.tsx +203 -0
- package/src/notifications/use-push-device.ts +392 -0
- package/src/rhf/fields.tsx +87 -39
- package/src/rhf/form-core.tsx +5 -4
- package/src/rhf/form.tsx +7 -43
- package/src/rhf/line-items.tsx +1 -1
- package/src/rhf/use-rhf-wizard-step.ts +4 -4
- package/src/rhf.ts +3 -2
- package/src/settings/device-reset-setting-labels.ts +20 -0
- package/src/settings/device-reset-setting.tsx +119 -0
- package/src/shell/app-shell.tsx +8 -0
- package/src/shell/option-switcher-menu.tsx +5 -22
- package/src/shell/role-switcher.tsx +2 -6
- package/src/shell/topbar-action-menu.tsx +7 -24
- package/src/shell/topbar-controls.tsx +6 -18
- package/src/testing/index.ts +3 -1
- package/src/testing/viewport.ts +125 -19
- package/src/theme/contrast-tokens.ts +106 -12
- package/src/theme/contrast.ts +30 -4
- package/src/theme/palette-derive.ts +68 -7
- package/src/theme/palette-presets.ts +16 -299
- package/src/theme/palette-store.ts +12 -0
- package/src/theme/text-size.ts +8 -0
- package/src/theme/theme-store.ts +10 -0
- package/src/wizard/types.ts +0 -8
- package/tokens.css +38 -4
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { createContext,
|
|
2
|
-
import type {
|
|
1
|
+
import { createContext, useContext, useId, useLayoutEffect, useState } from "react";
|
|
2
|
+
import type { ComponentPropsWithRef, CSSProperties, ReactElement, ReactNode } from "react";
|
|
3
3
|
import { ArrowDown, ArrowUp, Minus } from "lucide-react";
|
|
4
4
|
import { cn } from "../lib/cn";
|
|
5
|
+
// The sparkline's name: the label's text (lib since 0.36, which a field's `help` "?" shares).
|
|
6
|
+
import { plainText } from "../lib/plain-text";
|
|
5
7
|
import { useKitLabels, useKitLink, useKitLocale, type LabelOverride } from "../i18n/kit-labels";
|
|
6
8
|
import { pickLinkRenderer, RenderedKitLink } from "./text-link";
|
|
7
9
|
import { Card } from "./card";
|
|
@@ -115,8 +117,14 @@ export interface StatTileLinkProps {
|
|
|
115
117
|
children: ReactNode;
|
|
116
118
|
}
|
|
117
119
|
|
|
120
|
+
/**
|
|
121
|
+
* A `div`'s props, `ref` included since 0.35 (round 0.35 R4, the follow-up to API-2): they
|
|
122
|
+
* ride on to the {@link Card} that is the tile, so the ref is the tile's own `<div>` — the
|
|
123
|
+
* one to scroll into view or measure. `ComponentPropsWithoutRef` only kept it out of the
|
|
124
|
+
* type; at runtime `{...rest}` already carried it there.
|
|
125
|
+
*/
|
|
118
126
|
export interface StatTileProps
|
|
119
|
-
extends Omit<
|
|
127
|
+
extends Omit<ComponentPropsWithRef<"div">, "children" | "onClick"> {
|
|
120
128
|
/** What is measured. Also the tile's accessible name when it is a link/button. */
|
|
121
129
|
label: ReactNode;
|
|
122
130
|
/**
|
|
@@ -606,23 +614,6 @@ function FigureRow({
|
|
|
606
614
|
);
|
|
607
615
|
}
|
|
608
616
|
|
|
609
|
-
/**
|
|
610
|
-
* The text of a label node, for the sparkline's name: a string or number as is, an
|
|
611
|
-
* element by its children, recursively. A `<Tooltip label="…">Spend</Tooltip>` label
|
|
612
|
-
* yields "Spend" — the text the reader sees, not the bubble's. `undefined` when there
|
|
613
|
-
* is no text to find (an icon), so the sparkline falls back to its unnamed summary.
|
|
614
|
-
*/
|
|
615
|
-
function plainText(node: ReactNode): string | undefined {
|
|
616
|
-
const walk = (n: ReactNode): string => {
|
|
617
|
-
if (typeof n === "string" || typeof n === "number") return String(n);
|
|
618
|
-
if (Array.isArray(n)) return n.map(walk).join("");
|
|
619
|
-
if (isValidElement<{ children?: ReactNode }>(n)) return walk(n.props.children);
|
|
620
|
-
return "";
|
|
621
|
-
};
|
|
622
|
-
const text = walk(node).replace(/\s+/g, " ").trim();
|
|
623
|
-
return text === "" ? undefined : text;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
617
|
/**
|
|
627
618
|
* Whether `el`'s text is wider than its box — i.e. whether `truncate` is cutting it.
|
|
628
619
|
* Re-measured whenever the box resizes (a grid reflowing, a translation loading), not
|
|
@@ -7,7 +7,7 @@ import type { TileItem, TileSize } from "./tile-radio";
|
|
|
7
7
|
import { Tooltip } from "./tooltip";
|
|
8
8
|
import { useCommitReason, type CommitScope } from "./write-lock";
|
|
9
9
|
import { hasContent } from "../lib/presence";
|
|
10
|
-
import { LabelStrip, mergeDescribedBy, useFieldMessages } from "./field-parts";
|
|
10
|
+
import { LabelStrip, mergeDescribedBy, useFieldMessages, type FieldHelpProps } from "./field-parts";
|
|
11
11
|
import { DEFAULT_SWATCH_PICKER_LABELS } from "./swatch-picker-labels";
|
|
12
12
|
|
|
13
13
|
export interface SwatchPickerLabels {
|
|
@@ -62,7 +62,8 @@ export interface SwatchOption<T extends string> {
|
|
|
62
62
|
* is omitted rather than shadowed, as on {@link ToggleGroup}.
|
|
63
63
|
*/
|
|
64
64
|
export interface SwatchPickerProps<T extends string>
|
|
65
|
-
extends Omit<ComponentPropsWithRef<"div">, "onChange" | "children" | "defaultValue"
|
|
65
|
+
extends Omit<ComponentPropsWithRef<"div">, "onChange" | "children" | "defaultValue">,
|
|
66
|
+
FieldHelpProps {
|
|
66
67
|
options: SwatchOption<T>[];
|
|
67
68
|
/** The chosen colour, or `null` for none. */
|
|
68
69
|
value: T | null;
|
|
@@ -145,6 +146,7 @@ export function SwatchPicker<T extends string>({
|
|
|
145
146
|
labels,
|
|
146
147
|
label,
|
|
147
148
|
hint,
|
|
149
|
+
help,
|
|
148
150
|
disabledReason: ownDisabledReason,
|
|
149
151
|
commit,
|
|
150
152
|
className,
|
|
@@ -157,10 +159,13 @@ export function SwatchPicker<T extends string>({
|
|
|
157
159
|
const disabledReason = useCommitReason(commit, ownDisabledReason);
|
|
158
160
|
const locked = hasContent(disabledReason);
|
|
159
161
|
const labelled = hasContent(label);
|
|
160
|
-
// The label line's "?", or the caption under the swatches (DUP-2). Only with a label
|
|
161
|
-
// The caller's ids, the caption, then the group's state:
|
|
162
|
+
// The label line's "?", or the caption under the swatches (DUP-2). Only with a label,
|
|
163
|
+
// the help's "?" too (0.36). The caller's ids, the caption, then the group's state:
|
|
164
|
+
// mixed, locked.
|
|
162
165
|
const messages = useFieldMessages({
|
|
163
166
|
hint: labelled ? hint : undefined,
|
|
167
|
+
help: labelled ? help : undefined,
|
|
168
|
+
name: label,
|
|
164
169
|
describedBy: rest["aria-describedby"],
|
|
165
170
|
reasonId: mergeDescribedBy(mixed && mixedId, locked && reasonId),
|
|
166
171
|
});
|
|
@@ -51,9 +51,8 @@ interface SwipeActionBase {
|
|
|
51
51
|
* dark-mode pastel.
|
|
52
52
|
*
|
|
53
53
|
* **`paint`** follows the same rule for an app's documented exception (see
|
|
54
|
-
* {@link SwipePaint}).
|
|
55
|
-
*
|
|
56
|
-
* colour, and the idle panel is still dimmed.
|
|
54
|
+
* {@link SwipePaint}). The old path, a `className` / `armedClassName` pair under a white
|
|
55
|
+
* label and dimmed idle, was deprecated in 0.33 and removed in 0.35 (round 0.35 R1).
|
|
57
56
|
*/
|
|
58
57
|
export type SwipeAction = SwipeActionBase &
|
|
59
58
|
(
|
|
@@ -61,27 +60,12 @@ export type SwipeAction = SwipeActionBase &
|
|
|
61
60
|
/** The kit paints the panel: the tone's wash idle, its fill and `-contrast` armed. */
|
|
62
61
|
tone: SwipeTone;
|
|
63
62
|
paint?: never;
|
|
64
|
-
className?: never;
|
|
65
|
-
armedClassName?: never;
|
|
66
63
|
}
|
|
67
64
|
| {
|
|
68
65
|
/** A documented app exception: idle a 14 % wash of `fill` under the body ink,
|
|
69
66
|
* armed `fill` under `foreground`. */
|
|
70
67
|
paint: SwipePaint;
|
|
71
68
|
tone?: never;
|
|
72
|
-
className?: never;
|
|
73
|
-
armedClassName?: never;
|
|
74
|
-
}
|
|
75
|
-
| {
|
|
76
|
-
tone?: never;
|
|
77
|
-
paint?: never;
|
|
78
|
-
/** @deprecated 0.33 — pass `tone`, or `paint` for an exception; removed in 0.35.
|
|
79
|
-
* Background utility class while the action is previewed but not yet armed; the
|
|
80
|
-
* panel is dimmed then, and its text is white unless this sets a text colour. */
|
|
81
|
-
className: string;
|
|
82
|
-
/** @deprecated 0.33 — pass `tone`, or `paint`; removed in 0.35. Background
|
|
83
|
-
* utility class once the drag has passed this action's threshold. */
|
|
84
|
-
armedClassName: string;
|
|
85
69
|
}
|
|
86
70
|
);
|
|
87
71
|
|
|
@@ -114,21 +98,16 @@ export const SWIPE_TONE: Record<SwipeTone, { idle: string; armed: string }> = {
|
|
|
114
98
|
const PAINT_IDLE = "bg-[color-mix(in_oklab,var(--swipe-paint-fill)_14%,var(--bg-surface))] text-primary";
|
|
115
99
|
const PAINT_ARMED = "bg-[var(--swipe-paint-fill)] text-[var(--swipe-paint-fg)]";
|
|
116
100
|
|
|
117
|
-
/** The panel's colour classes
|
|
118
|
-
function panelLook(action: SwipeAction, armed: boolean): { className: string; style?: CSSProperties
|
|
119
|
-
if (action.tone) return { className: SWIPE_TONE[action.tone][armed ? "armed" : "idle"]
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
dim: false,
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
// The deprecated path, as it was: white text under the caller's fill, dimmed idle.
|
|
131
|
-
return { className: cn("text-white", armed ? action.armedClassName : action.className), dim: !armed };
|
|
101
|
+
/** The panel's colour classes and inline style for one action and state. */
|
|
102
|
+
function panelLook(action: SwipeAction, armed: boolean): { className: string; style?: CSSProperties } {
|
|
103
|
+
if (action.tone) return { className: SWIPE_TONE[action.tone][armed ? "armed" : "idle"] };
|
|
104
|
+
return {
|
|
105
|
+
className: armed ? PAINT_ARMED : PAINT_IDLE,
|
|
106
|
+
style: {
|
|
107
|
+
"--swipe-paint-fill": action.paint.fill,
|
|
108
|
+
"--swipe-paint-fg": action.paint.foreground,
|
|
109
|
+
} as CSSProperties,
|
|
110
|
+
};
|
|
132
111
|
}
|
|
133
112
|
|
|
134
113
|
/**
|
|
@@ -296,11 +275,10 @@ export function SwipeableRow({
|
|
|
296
275
|
className={cn(
|
|
297
276
|
"pointer-events-none absolute inset-0 flex items-center gap-2 px-4",
|
|
298
277
|
"text-xs font-medium transition-all",
|
|
278
|
+
// No dimming: a tone or a paint says "not yet armed" with the soft→solid
|
|
279
|
+
// step, which keeps its label readable at both ends (the 0.33 rule; the
|
|
280
|
+
// dimmed path went with `className` / `armedClassName` in 0.35).
|
|
299
281
|
look.className,
|
|
300
|
-
// The old path only: dimmed until the drag has passed a threshold. A tone
|
|
301
|
-
// or a paint says it with the soft→solid step instead, which keeps its
|
|
302
|
-
// label readable at both ends.
|
|
303
|
-
look.dim && "opacity-60",
|
|
304
282
|
// The panel is anchored to the edge the row is uncovering, so the label
|
|
305
283
|
// sits where the eye already is rather than across the screen. That edge is
|
|
306
284
|
// physical, while a flex row starts at the INLINE start — so in RTL the two
|
|
@@ -228,7 +228,9 @@ export interface TextLinkProps
|
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
const TONE: Record<TextLinkTone, string> = {
|
|
231
|
-
brand
|
|
231
|
+
// Under More contrast the brand as text, `--brand-muted`, at rest and hovered (0.36,
|
|
232
|
+
// colour-roles §13.3 decision 8): `--brand` is a mark's colour, solved to 3:1.
|
|
233
|
+
brand: "text-brand hover:text-[var(--brand-hover)] contrast:text-brand-muted contrast:hover:text-brand-muted",
|
|
232
234
|
muted: "text-muted hover:text-primary",
|
|
233
235
|
danger: "text-danger hover:text-[var(--danger-hover)]",
|
|
234
236
|
inherit: "",
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { useId, useLayoutEffect, useRef } from "react";
|
|
2
2
|
import type { ChangeEvent, ReactNode, Ref, TextareaHTMLAttributes } from "react";
|
|
3
3
|
import { cn } from "../lib/cn";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
EndHintRow,
|
|
6
|
+
FieldCaption,
|
|
7
|
+
mergeDescribedBy,
|
|
8
|
+
useFieldError,
|
|
9
|
+
useFieldHint,
|
|
10
|
+
type FieldHelpProps,
|
|
11
|
+
} from "./field-parts";
|
|
5
12
|
import {
|
|
6
13
|
CharacterCount,
|
|
7
14
|
FIELD_BASE,
|
|
@@ -221,7 +228,7 @@ function TextareaLabelStrip() {
|
|
|
221
228
|
return <span ref={ref} aria-hidden data-slot="label-strip" className={TEXTAREA_LABEL_STRIP} />;
|
|
222
229
|
}
|
|
223
230
|
|
|
224
|
-
export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement
|
|
231
|
+
export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement>, FieldHelpProps {
|
|
225
232
|
label?: ReactNode;
|
|
226
233
|
/** See {@link Input}'s `invalid`. */
|
|
227
234
|
invalid?: boolean;
|
|
@@ -240,13 +247,13 @@ export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElemen
|
|
|
240
247
|
}
|
|
241
248
|
|
|
242
249
|
export function Textarea(props: TextareaProps) {
|
|
243
|
-
const { ref, className, label, id, placeholder, invalid, error, hint, showCount, countLabels, ...rest } = props;
|
|
250
|
+
const { ref, className, label, id, placeholder, invalid, error, hint, help, showCount, countLabels, ...rest } = props;
|
|
244
251
|
// See Input's `reserve`.
|
|
245
252
|
const reserve = "error" in props || "hint" in props || "showCount" in props;
|
|
246
253
|
const generated = useId();
|
|
247
254
|
const fieldId = id ?? generated;
|
|
248
255
|
const countId = useId();
|
|
249
|
-
const hintParts = useFieldHint(hint, rest["aria-describedby"]);
|
|
256
|
+
const hintParts = useFieldHint(hint, rest["aria-describedby"], { help, name: label ?? rest["aria-label"] });
|
|
250
257
|
const maxLength = rest.maxLength;
|
|
251
258
|
const counting = Boolean(showCount) && typeof maxLength === "number" && maxLength > 0;
|
|
252
259
|
const length = useTypedLength(rest.value, rest.defaultValue);
|
|
@@ -11,11 +11,13 @@ import {
|
|
|
11
11
|
DISABLED_REASON_LINE_CLASS,
|
|
12
12
|
FIELD_CAPTION_CLASS,
|
|
13
13
|
FIELD_ERROR_CLASS,
|
|
14
|
+
fieldHelpMark,
|
|
14
15
|
isTextHint,
|
|
15
16
|
LabelStrip,
|
|
16
17
|
useDisabledReasonLine,
|
|
17
18
|
useInlineHint,
|
|
18
19
|
type DisabledReasonDisplay,
|
|
20
|
+
type FieldHelpProps,
|
|
19
21
|
} from "./field-parts";
|
|
20
22
|
import { FOCUS_RING_WIDTH } from "./focus-ring";
|
|
21
23
|
|
|
@@ -35,7 +37,8 @@ export interface ToggleOption<T extends string> {
|
|
|
35
37
|
* worse than one that does not compile.
|
|
36
38
|
*/
|
|
37
39
|
export interface ToggleGroupBaseProps<T extends string>
|
|
38
|
-
extends Omit<ComponentPropsWithoutRef<"div">, "onChange" | "children"
|
|
40
|
+
extends Omit<ComponentPropsWithoutRef<"div">, "onChange" | "children">,
|
|
41
|
+
FieldHelpProps {
|
|
39
42
|
options: ToggleOption<T>[];
|
|
40
43
|
className?: string;
|
|
41
44
|
/** Applied to every option button (e.g. to tune height/rounding to match
|
|
@@ -380,6 +383,7 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
|
|
|
380
383
|
labelPlacement = "field",
|
|
381
384
|
chromeClassName,
|
|
382
385
|
hint,
|
|
386
|
+
help,
|
|
383
387
|
error,
|
|
384
388
|
disabledReason: ownDisabledReason,
|
|
385
389
|
disabledReasonDisplay,
|
|
@@ -407,10 +411,22 @@ export function ToggleGroup<T extends string>(props: ToggleGroupProps<T>): React
|
|
|
407
411
|
// §4: at Large and on touch the reason is a line under the group, not a bubble.
|
|
408
412
|
const reasonLine = useDisabledReasonLine(disabledReasonDisplay) && locked;
|
|
409
413
|
// §4: likewise a FieldHint "?" on the label line becomes a caption under the group at
|
|
410
|
-
// Large and on touch; text is a caption at every size, as Select's (see `hint`).
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
const
|
|
414
|
+
// Large and on touch; text is a caption at every size, as Select's (see `hint`). With
|
|
415
|
+
// a `help` (0.36, only with `label`, as `hint`), its "?" is the label line's only one,
|
|
416
|
+
// and the hint — a FieldHint's words included — is the caption at every size.
|
|
417
|
+
const helpMark = fieldHelpMark(hasContent(label) ? help : undefined, label);
|
|
418
|
+
const withHelp = helpMark !== undefined;
|
|
419
|
+
const inlineHint = useInlineHint(hint, withHelp);
|
|
420
|
+
const hintAsCaption = withHelp
|
|
421
|
+
? hasContent(inlineHint)
|
|
422
|
+
? inlineHint
|
|
423
|
+
: undefined
|
|
424
|
+
: isTextHint(hint)
|
|
425
|
+
? hint
|
|
426
|
+
: inlineHint !== hint
|
|
427
|
+
? inlineHint
|
|
428
|
+
: undefined;
|
|
429
|
+
const labelHint = helpMark ?? (hintAsCaption === undefined ? hint : undefined);
|
|
414
430
|
// Locked looks disabled — the dimmed group, the not-allowed cursor, no hover offer —
|
|
415
431
|
// but stays focusable; `disabled` alone also takes the segments out of the tab order.
|
|
416
432
|
const dimmed = disabled || locked;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
cloneElement,
|
|
3
3
|
isValidElement,
|
|
4
|
+
useCallback,
|
|
4
5
|
useEffect,
|
|
5
6
|
useId,
|
|
6
7
|
useLayoutEffect,
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
type PointerEvent,
|
|
13
14
|
type ReactElement,
|
|
14
15
|
type ReactNode,
|
|
16
|
+
type Ref,
|
|
15
17
|
type RefObject,
|
|
16
18
|
} from "react";
|
|
17
19
|
import { createPortal } from "react-dom";
|
|
@@ -21,6 +23,7 @@ import { useAnchoredRect, type AnchorRect } from "../hooks/use-anchored-rect";
|
|
|
21
23
|
import { viewportSize } from "../hooks/use-anchored-panel";
|
|
22
24
|
import { dirOf, type Direction } from "../lib/direction";
|
|
23
25
|
import { hasClippingAncestor } from "../lib/clipping";
|
|
26
|
+
import { assignRef } from "../lib/refs";
|
|
24
27
|
|
|
25
28
|
/** The attribute that marks an element as a clipping container for {@link Tooltip}'s
|
|
26
29
|
* auto-portal, whatever its computed `overflow` — `<div data-clips>` or
|
|
@@ -129,6 +132,14 @@ export interface TooltipProps extends ComponentPropsWithoutRef<"span"> {
|
|
|
129
132
|
*/
|
|
130
133
|
tap?: TooltipTap;
|
|
131
134
|
children: ReactNode;
|
|
135
|
+
/**
|
|
136
|
+
* The trigger WRAPPER — the `<span>` the rest of the props go to, around the caller's
|
|
137
|
+
* child (round 0.35 R4, as Card and EmptyState took one in 0.34) — merged with its own
|
|
138
|
+
* ref, which the bubble is anchored to and dismissed by. Not the bubble: a portalled
|
|
139
|
+
* one exists only while it is up. On the empty-label branch there is no wrapper, so
|
|
140
|
+
* the ref stays `null` (see the ⚠️ above).
|
|
141
|
+
*/
|
|
142
|
+
ref?: Ref<HTMLSpanElement>;
|
|
132
143
|
}
|
|
133
144
|
|
|
134
145
|
/** What each variant below takes: the resolved `side` and `tap`, and every span attribute
|
|
@@ -630,6 +641,22 @@ function useTooltipTrigger(
|
|
|
630
641
|
return { open, dismissed, handlers };
|
|
631
642
|
}
|
|
632
643
|
|
|
644
|
+
/**
|
|
645
|
+
* The trigger wrapper's own ref, and one callback ref that hands the wrapper to the
|
|
646
|
+
* caller's `ref` as well (round 0.35 R4).
|
|
647
|
+
*/
|
|
648
|
+
function useTriggerRef(ref: Ref<HTMLSpanElement> | undefined) {
|
|
649
|
+
const triggerRef = useRef<HTMLSpanElement | null>(null);
|
|
650
|
+
const setTrigger = useCallback(
|
|
651
|
+
(el: HTMLSpanElement | null) => {
|
|
652
|
+
triggerRef.current = el;
|
|
653
|
+
assignRef(ref, el);
|
|
654
|
+
},
|
|
655
|
+
[ref],
|
|
656
|
+
);
|
|
657
|
+
return { triggerRef, setTrigger };
|
|
658
|
+
}
|
|
659
|
+
|
|
633
660
|
/** The variant that lives next to its trigger, and — when `detect` is on, which is the
|
|
634
661
|
* default — moves its bubble to `<body>` when that turns out to be inside a clipping
|
|
635
662
|
* container (see "Inside a scroll container" on {@link Tooltip}).
|
|
@@ -656,10 +683,11 @@ function InPlaceTooltip({
|
|
|
656
683
|
lazy,
|
|
657
684
|
tap,
|
|
658
685
|
children,
|
|
686
|
+
ref,
|
|
659
687
|
...rest
|
|
660
688
|
}: TooltipVariantProps & { detect: boolean; lazy: boolean }) {
|
|
661
689
|
const id = useId();
|
|
662
|
-
const triggerRef
|
|
690
|
+
const { triggerRef, setTrigger } = useTriggerRef(ref);
|
|
663
691
|
const [clipped, setClipped] = useState(false);
|
|
664
692
|
const [dir, setDir] = useState<Direction>("ltr");
|
|
665
693
|
// The reading direction on every request (the clamp keeps the start edge of a bubble
|
|
@@ -677,7 +705,8 @@ function InPlaceTooltip({
|
|
|
677
705
|
// phantom-scroll bug whether or not anyone opens it.
|
|
678
706
|
useLayoutEffect(() => {
|
|
679
707
|
if (detect) setClipped(hasClippingAncestor(triggerRef.current));
|
|
680
|
-
|
|
708
|
+
// `triggerRef` is the same object for the component's life (useTriggerRef's useRef).
|
|
709
|
+
}, [detect, triggerRef]);
|
|
681
710
|
return (
|
|
682
711
|
// No role for this span: its handlers track whether the bubble is up and activate
|
|
683
712
|
// nothing; the caller's child is the interactive element, keeps its own handlers,
|
|
@@ -687,7 +716,7 @@ function InPlaceTooltip({
|
|
|
687
716
|
// a caller passing an `onFocus` of its own must not replace them (its pointer
|
|
688
717
|
// handlers are called from them).
|
|
689
718
|
{...rest}
|
|
690
|
-
ref={
|
|
719
|
+
ref={setTrigger}
|
|
691
720
|
// Clipped for the one render in which the bubble is measured (see useViewportClamp):
|
|
692
721
|
// that layout must not reach the page's width.
|
|
693
722
|
style={measuring ? { ...rest.style, overflow: "clip" } : rest.style}
|
|
@@ -1041,9 +1070,10 @@ function PortalTooltip({
|
|
|
1041
1070
|
redact,
|
|
1042
1071
|
tap,
|
|
1043
1072
|
children,
|
|
1073
|
+
ref,
|
|
1044
1074
|
...rest
|
|
1045
1075
|
}: TooltipVariantProps) {
|
|
1046
|
-
const triggerRef
|
|
1076
|
+
const { triggerRef, setTrigger } = useTriggerRef(ref);
|
|
1047
1077
|
// The trigger's reading direction, read when the bubble is asked for (an event, not a
|
|
1048
1078
|
// render): it resolves `start` / `end`, and the portalled bubble — which has left the
|
|
1049
1079
|
// subtree it would have inherited `dir` from — carries it too.
|
|
@@ -1062,9 +1092,10 @@ function PortalTooltip({
|
|
|
1062
1092
|
// As in `InPlaceTooltip`: the caller's attributes first, the handlers that run
|
|
1063
1093
|
// this component after them. The BUBBLE is deliberately not given them — it
|
|
1064
1094
|
// is portalled to `<body>`, and an id or a tour anchor duplicated onto a node
|
|
1065
|
-
// that only exists while hovered would match twice or match nothing.
|
|
1095
|
+
// that only exists while hovered would match twice or match nothing. So, too,
|
|
1096
|
+
// the caller's `ref` (round 0.35 R4).
|
|
1066
1097
|
{...rest}
|
|
1067
|
-
ref={
|
|
1098
|
+
ref={setTrigger}
|
|
1068
1099
|
className={cn("relative inline-flex", className)}
|
|
1069
1100
|
{...handlers}
|
|
1070
1101
|
>
|
|
@@ -33,12 +33,13 @@ import { BulkActionBar } from "./bulk-action-bar";
|
|
|
33
33
|
import { Checkbox } from "./checkbox";
|
|
34
34
|
import { Chip } from "./chip";
|
|
35
35
|
import { DataTable } from "./data-table";
|
|
36
|
-
import type { DataTableColumn, DataTableProps, MobileSwipeActions
|
|
36
|
+
import type { DataTableColumn, DataTableProps, MobileSwipeActions } from "./data-table";
|
|
37
37
|
import { Disclosure } from "./disclosure";
|
|
38
38
|
import { SearchField } from "./search-field";
|
|
39
39
|
import { toast } from "./toast";
|
|
40
40
|
import type { SwipeAction } from "./swipeable-row";
|
|
41
41
|
import { ToggleGroup } from "./toggle-group";
|
|
42
|
+
import { useSharedTableView } from "./use-table-state";
|
|
42
43
|
import { TranslationReviewEditor } from "./translation-review-editor";
|
|
43
44
|
import { DEFAULT_TRANSLATION_REVIEW_LABELS, reviewStatusLabel } from "./translation-review-labels";
|
|
44
45
|
import type { TranslationReviewLabels } from "./translation-review-labels";
|
|
@@ -168,7 +169,8 @@ export interface TranslationReviewPanelProps {
|
|
|
168
169
|
/** Rows per page. Default 50. */
|
|
169
170
|
pageSize?: number;
|
|
170
171
|
/** Persists the table's sort and page size (DataTable's `storageKey`), under the
|
|
171
|
-
* prefix below
|
|
172
|
+
* prefix below — under {@link groupBy}, the one sort and page size every group
|
|
173
|
+
* shares, in the same place (0.35). */
|
|
172
174
|
storageKey?: string;
|
|
173
175
|
/**
|
|
174
176
|
* The `localStorage` prefix in front of `storageKey` (DataTable's `storageKeyPrefix`).
|
|
@@ -257,7 +259,14 @@ export interface TranslationReviewPanelProps {
|
|
|
257
259
|
* reference; a column sort orders the rows INSIDE every group alike. Each group pages
|
|
258
260
|
* on its own, `pageSize` rows at a time — a header then always stands over its own
|
|
259
261
|
* rows, and paging one area does not move another — rather than one pager cutting
|
|
260
|
-
* through the headers.
|
|
262
|
+
* through the headers. The page SIZE is one for all of them, as the sort is: a
|
|
263
|
+
* group's pager changes it everywhere.
|
|
264
|
+
*
|
|
265
|
+
* `storageKey` persists that one view — the sort and the page size — in the place the
|
|
266
|
+
* ungrouped table keeps its own (same key, same prefix, same blob), read on mount and
|
|
267
|
+
* written on a change, so a reviewer switching the grouping on or off keeps both
|
|
268
|
+
* (0.35, Kurvenschmiede; before, it persisted the ungrouped table only). What only
|
|
269
|
+
* the ungrouped table has — column widths, hidden columns — stays in the blob for it.
|
|
261
270
|
*
|
|
262
271
|
* Groups fold (each on its own, remembered while the panel lives), and a folded group's
|
|
263
272
|
* rows are not rendered at all — only its header. Which groups start open is
|
|
@@ -558,8 +567,15 @@ export function TranslationReviewPanel({
|
|
|
558
567
|
// has mounted and taken focus, the group that asked.
|
|
559
568
|
const [confirming, setConfirming] = useState<string | null>(null);
|
|
560
569
|
const confirmFocus = useRef<string | null>(null);
|
|
561
|
-
// One
|
|
562
|
-
|
|
570
|
+
// One view for every group's table — one sort, so a header click orders all of them
|
|
571
|
+
// alike, and one page size — kept under `storageKey` in the single table's own blob, so
|
|
572
|
+
// switching the grouping keeps both (0.35, Kurvenschmiede).
|
|
573
|
+
const groupView = useSharedTableView({
|
|
574
|
+
active: groupBy !== undefined,
|
|
575
|
+
storageKey,
|
|
576
|
+
storageKeyPrefix,
|
|
577
|
+
defaultPageSize: pageSize,
|
|
578
|
+
});
|
|
563
579
|
|
|
564
580
|
const setFilter = (patch: Partial<TranslationReviewFilter>) => {
|
|
565
581
|
const next = { ...filter, ...patch };
|
|
@@ -870,8 +886,10 @@ export function TranslationReviewPanel({
|
|
|
870
886
|
frame: false,
|
|
871
887
|
chrome: "minimal" as const,
|
|
872
888
|
maxBodyHeight: "none",
|
|
873
|
-
sorts:
|
|
874
|
-
onSortsChange:
|
|
889
|
+
sorts: groupView.sorts,
|
|
890
|
+
onSortsChange: groupView.setSorts,
|
|
891
|
+
pageSize: groupView.pageSize,
|
|
892
|
+
onPageSizeChange: groupView.setPageSize,
|
|
875
893
|
labels: { table: group.name },
|
|
876
894
|
}
|
|
877
895
|
: { storageKey, storageKeyPrefix })}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { useLocation, useSearchParams } from "react-router";
|
|
3
|
+
import { useKitTableStorageKeyPrefix } from "../i18n/kit-labels";
|
|
3
4
|
import { readStored, writeStored } from "../lib/safe-storage";
|
|
4
5
|
import {
|
|
5
6
|
decodeFilterValue,
|
|
@@ -45,6 +46,13 @@ function serializePersisted(state: PersistedState): string {
|
|
|
45
46
|
return JSON.stringify(state);
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
/** A stored page size as a table holds it — `"all"` is `Infinity` — or `fallback`. */
|
|
50
|
+
function storedPageSize(stored: Partial<PersistedState>, fallback: number): number {
|
|
51
|
+
if (stored.pageSize === "all") return Infinity;
|
|
52
|
+
if (typeof stored.pageSize === "number" && stored.pageSize > 0) return stored.pageSize;
|
|
53
|
+
return fallback;
|
|
54
|
+
}
|
|
55
|
+
|
|
48
56
|
// ---------- URL sync helpers ----------
|
|
49
57
|
|
|
50
58
|
const URL_FILTER_PREFIX = "f.";
|
|
@@ -251,8 +259,8 @@ function writeUrlState<T>(
|
|
|
251
259
|
* * **Persistence writes on every change, the URL only when asked.** `storageKey` is the
|
|
252
260
|
* per-table identity; `urlSync` is opt-in because only some tables want their view in
|
|
253
261
|
* a shareable address.
|
|
254
|
-
* * **A controlled filter or
|
|
255
|
-
* the note at the reset below.
|
|
262
|
+
* * **A controlled filter, sort or page size that changes sends the table back to page
|
|
263
|
+
* 1.** See the note at the reset below.
|
|
256
264
|
*/
|
|
257
265
|
export function useTableState<T>({
|
|
258
266
|
columns,
|
|
@@ -262,6 +270,7 @@ export function useTableState<T>({
|
|
|
262
270
|
defaultPageSize,
|
|
263
271
|
sortsProp,
|
|
264
272
|
filtersProp,
|
|
273
|
+
pageSizeProp,
|
|
265
274
|
}: {
|
|
266
275
|
columns: DataTableColumn<T>[];
|
|
267
276
|
storageKey?: string;
|
|
@@ -270,6 +279,7 @@ export function useTableState<T>({
|
|
|
270
279
|
defaultPageSize: number;
|
|
271
280
|
sortsProp?: SortState[];
|
|
272
281
|
filtersProp?: FilterState;
|
|
282
|
+
pageSizeProp?: number;
|
|
273
283
|
}) {
|
|
274
284
|
const { enabled: urlSync, prefix: urlPrefix } = resolveTableUrlSync(urlSyncOption);
|
|
275
285
|
const keys = useMemo(() => urlKeys(urlPrefix), [urlPrefix]);
|
|
@@ -312,21 +322,21 @@ export function useTableState<T>({
|
|
|
312
322
|
// is never painted and never written to the URL. Not on mount: a deep link's `p=3`
|
|
313
323
|
// must survive the owner's first render. (In `serverPagination` mode this state is
|
|
314
324
|
// unused — the owner's `page` is the page, and resetting it stays the owner's job.)
|
|
325
|
+
// A controlled page size counts too: the groups of `TranslationReviewPanel` share one,
|
|
326
|
+
// and a group paged deep into its rows starts over when another group's pager changes it.
|
|
315
327
|
const controlledSig =
|
|
316
|
-
sortsProp !== undefined || filtersProp !== undefined
|
|
317
|
-
? JSON.stringify([sortsProp ?? null, filtersProp ?? null])
|
|
328
|
+
sortsProp !== undefined || filtersProp !== undefined || pageSizeProp !== undefined
|
|
329
|
+
? JSON.stringify([sortsProp ?? null, filtersProp ?? null, String(pageSizeProp)])
|
|
318
330
|
: null;
|
|
319
331
|
const [seenControlledSig, setSeenControlledSig] = useState(controlledSig);
|
|
320
332
|
if (seenControlledSig !== controlledSig) {
|
|
321
333
|
setSeenControlledSig(controlledSig);
|
|
322
334
|
setPage(0);
|
|
323
335
|
}
|
|
324
|
-
const [
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
return defaultPageSize;
|
|
329
|
-
});
|
|
336
|
+
const [internalPageSize, setPageSize] = useState<number>(() =>
|
|
337
|
+
urlInitial.pageSize !== undefined ? urlInitial.pageSize : storedPageSize(initial, defaultPageSize),
|
|
338
|
+
);
|
|
339
|
+
const pageSize = pageSizeProp ?? internalPageSize;
|
|
330
340
|
const [widths, setWidths] = useState<Record<string, number>>(() => initial.widths ?? {});
|
|
331
341
|
const [hiddenCols, setHiddenCols] = useState<Set<string>>(() => new Set(initial.hidden ?? []));
|
|
332
342
|
const [showSettings, setShowSettings] = useState(false);
|
|
@@ -398,6 +408,77 @@ export function useTableState<T>({
|
|
|
398
408
|
};
|
|
399
409
|
}
|
|
400
410
|
|
|
411
|
+
// ---------- One view over several tables ----------
|
|
412
|
+
|
|
413
|
+
/** What {@link useSharedTableView} keeps. */
|
|
414
|
+
export interface SharedTableView {
|
|
415
|
+
sorts: SortState[];
|
|
416
|
+
setSorts: (next: SortState[]) => void;
|
|
417
|
+
/** `Infinity` for "all", as a table holds it. */
|
|
418
|
+
pageSize: number;
|
|
419
|
+
setPageSize: (next: number) => void;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* One table view — the sort and the page size — for an owner that draws it as SEVERAL
|
|
424
|
+
* tables over one `storageKey`: `TranslationReviewPanel`'s groups, which sort and page
|
|
425
|
+
* alike (0.35, Kurvenschmiede: its grouped review stored no view at all). Pass them to
|
|
426
|
+
* each table as `sorts`/`onSortsChange` and `pageSize`/`onPageSizeChange`.
|
|
427
|
+
*
|
|
428
|
+
* Kept in the very blob a `DataTable` with that `storageKey` keeps, not in a format of
|
|
429
|
+
* its own, so the single table and the groups read each other's view. What the blob
|
|
430
|
+
* holds besides (filters, column widths, hidden columns) is carried over as stored, for
|
|
431
|
+
* the single table to find as it left it. Read when `active` turns on — on mount, or
|
|
432
|
+
* when the owner switches to this view — and written on a change, never on a read. The
|
|
433
|
+
* prefix resolves as DataTable's does: prop > provider > the kit's.
|
|
434
|
+
*/
|
|
435
|
+
export function useSharedTableView({
|
|
436
|
+
active,
|
|
437
|
+
storageKey,
|
|
438
|
+
storageKeyPrefix,
|
|
439
|
+
defaultPageSize,
|
|
440
|
+
}: {
|
|
441
|
+
active: boolean;
|
|
442
|
+
storageKey?: string;
|
|
443
|
+
storageKeyPrefix?: string;
|
|
444
|
+
defaultPageSize: number;
|
|
445
|
+
}): SharedTableView {
|
|
446
|
+
const providerPrefix = useKitTableStorageKeyPrefix();
|
|
447
|
+
const prefix = storageKeyPrefix ?? providerPrefix ?? DEFAULT_PERSIST_PREFIX;
|
|
448
|
+
const read = () => {
|
|
449
|
+
const stored = active ? loadPersisted(storageKey, prefix) : {};
|
|
450
|
+
return { sorts: normalizeSorts(stored.sort), pageSize: storedPageSize(stored, defaultPageSize) };
|
|
451
|
+
};
|
|
452
|
+
const [view, setView] = useState(read);
|
|
453
|
+
// Adjusted during render when `active` turns on, so the first render of the groups
|
|
454
|
+
// already has the view the single table left, not a frame of the default.
|
|
455
|
+
const [wasActive, setWasActive] = useState(active);
|
|
456
|
+
if (active !== wasActive) {
|
|
457
|
+
setWasActive(active);
|
|
458
|
+
if (active) setView(read());
|
|
459
|
+
}
|
|
460
|
+
const change = (patch: Partial<typeof view>) => {
|
|
461
|
+
const next = { ...view, ...patch };
|
|
462
|
+
setView(next);
|
|
463
|
+
if (!active || !storageKey) return;
|
|
464
|
+
const stored = loadPersisted(storageKey, prefix);
|
|
465
|
+
const blob: PersistedState = {
|
|
466
|
+
sort: next.sorts,
|
|
467
|
+
filters: stored.filters ?? {},
|
|
468
|
+
pageSize: next.pageSize === Infinity ? "all" : next.pageSize,
|
|
469
|
+
widths: stored.widths,
|
|
470
|
+
hidden: stored.hidden,
|
|
471
|
+
};
|
|
472
|
+
writeStored(prefix + storageKey, serializePersisted(blob));
|
|
473
|
+
};
|
|
474
|
+
return {
|
|
475
|
+
sorts: view.sorts,
|
|
476
|
+
setSorts: (sorts) => change({ sorts }),
|
|
477
|
+
pageSize: view.pageSize,
|
|
478
|
+
setPageSize: (pageSize) => change({ pageSize }),
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
401
482
|
// ---------- Owner-held table state, mirrored to the URL ----------
|
|
402
483
|
|
|
403
484
|
export interface UseTableUrlStateOptions<T> {
|
|
@@ -69,9 +69,9 @@ export interface UserAvatarProps extends Omit<ComponentPropsWithRef<"span">, "ch
|
|
|
69
69
|
* in the surface colour so it reads as its own mark (keksdose account-menu ~385,
|
|
70
70
|
* top-bar :152). Its `label` is read as text where the dot sits — inside a button
|
|
71
71
|
* named by its content it joins that name. In `TopBarActionMenu`'s `trigger` the
|
|
72
|
-
* button is named by the menu's `
|
|
72
|
+
* button is named by the menu's `aria-label` followed by this label: "Account menu
|
|
73
73
|
* 3 unread". The initials stay hidden either way, so the person's name is NOT part
|
|
74
|
-
* of it — put it in `
|
|
74
|
+
* of it — put it in `aria-label` ("Marcel Eifert, account menu") if it should be.
|
|
75
75
|
*/
|
|
76
76
|
badge?: UserAvatarBadge | null;
|
|
77
77
|
}
|