@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,10 +1,13 @@
|
|
|
1
1
|
import { createContext, isValidElement, useContext, useId } from "react";
|
|
2
|
-
import type { ComponentPropsWithoutRef, ComponentPropsWithRef, ReactNode
|
|
2
|
+
import type { ComponentPropsWithoutRef, ComponentPropsWithRef, ReactNode } from "react";
|
|
3
3
|
import { HelpCircle } from "lucide-react";
|
|
4
4
|
import { cn } from "../lib/cn";
|
|
5
5
|
import { hasContent } from "../lib/presence";
|
|
6
|
+
import { plainText } from "../lib/plain-text";
|
|
7
|
+
import { DEFAULT_COMMON_LABELS, useKitLabels } from "../i18n/kit-labels";
|
|
6
8
|
import { useInlineFacts } from "../hooks/use-large-text";
|
|
7
9
|
import { FOCUS_RING } from "./focus-ring";
|
|
10
|
+
import { HelpPopover } from "./help-popover";
|
|
8
11
|
import { Tooltip, type TooltipSide } from "./tooltip";
|
|
9
12
|
import { useCommitReason, type CommitScope } from "./write-lock";
|
|
10
13
|
|
|
@@ -41,23 +44,9 @@ export function mergeDescribedBy(...ids: Array<string | false | null | undefined
|
|
|
41
44
|
return list.length ? list.join(" ") : undefined;
|
|
42
45
|
}
|
|
43
46
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
else if (ref) (ref as { current: T | null }).current = node;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* One callback ref feeding several — the caller's forwarded `ref` and a field's own
|
|
52
|
-
* (DUP-11: AmountInput, FormActions, ScrollArea and SearchField each wrote this by hand).
|
|
53
|
-
* Wrap it in `useCallback` (or `useMemo`) over the same refs where a new callback every
|
|
54
|
-
* render would detach and re-attach the node.
|
|
55
|
-
*/
|
|
56
|
-
export function mergeRefs<T>(...refs: Array<Ref<T> | undefined>): RefCallback<T> {
|
|
57
|
-
return (node) => {
|
|
58
|
-
for (const ref of refs) assignRef(ref, node);
|
|
59
|
-
};
|
|
60
|
-
}
|
|
47
|
+
// The ref plumbing lives in ../lib/refs since round 0.35 (Tooltip needs it, and this module
|
|
48
|
+
// renders a Tooltip); the fields keep importing it from here.
|
|
49
|
+
export { assignRef, mergeRefs } from "../lib/refs";
|
|
61
50
|
|
|
62
51
|
/* ── the static label ─────────────────────────────────────────────────────── */
|
|
63
52
|
|
|
@@ -216,16 +205,82 @@ export function FieldHint({
|
|
|
216
205
|
* The kit's fields call it through {@link useFieldHint} / {@link useFieldMessages}; a
|
|
217
206
|
* field that resolves its own `hint` (an app's, or one of the kit's own outside this
|
|
218
207
|
* file) calls it first and then treats the result as it treated a text hint.
|
|
208
|
+
*
|
|
209
|
+
* `withHelp` (round 0.36): the field has a `help`, whose "?" is the field's only one
|
|
210
|
+
* ({@link fieldHelpMark}) — so a FieldHint is its words at EVERY size, not only at Large
|
|
211
|
+
* and on touch.
|
|
219
212
|
*/
|
|
220
|
-
export function useInlineHint(hint: ReactNode): ReactNode {
|
|
213
|
+
export function useInlineHint(hint: ReactNode, withHelp = false): ReactNode {
|
|
221
214
|
const inline = useInlineFacts();
|
|
222
|
-
if (inline && isValidElement(hint) && hint.type === FieldHint) {
|
|
215
|
+
if ((inline || withHelp) && isValidElement(hint) && hint.type === FieldHint) {
|
|
223
216
|
const words = (hint.props as FieldHintProps).label;
|
|
224
217
|
if (words) return words;
|
|
225
218
|
}
|
|
226
219
|
return hint;
|
|
227
220
|
}
|
|
228
221
|
|
|
222
|
+
/* ── help (round 0.36, docs/text-size-harmonization.md §4, §10.23) ─────────── */
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* The doc every field's `help` prop points at.
|
|
226
|
+
*
|
|
227
|
+
* A field may carry two kinds of words (§10.23): a FACT — a format, a limit, a
|
|
228
|
+
* consequence — which stays visible, and HELP — why the field exists, how to choose,
|
|
229
|
+
* what the options mean — which the field is usable without and which may sit behind a
|
|
230
|
+
* "?". Until 0.36 a field had one slot, `hint`, so a field with both had to drop one or
|
|
231
|
+
* print a paragraph (Kurvenschmiede's "How it was measured", round 0.36 H). Now:
|
|
232
|
+
*
|
|
233
|
+
* - `hint` is the fact, the caption under the field, on its `aria-describedby`;
|
|
234
|
+
* - `help` is the help, a {@link HelpPopover} "?" on the label line (an unlabelled
|
|
235
|
+
* field's at its end edge, as a hint's), named "About <label>" (`common.aboutField`,
|
|
236
|
+
* from the label's text, else the `aria-label`, else `common.help`). Pass a
|
|
237
|
+
* `HelpPopover` as `help` to name it yourself ("What do the statuses mean?").
|
|
238
|
+
*
|
|
239
|
+
* The help's "?" is then the field's ONLY "?": a `FieldHint` passed as `hint` beside it
|
|
240
|
+
* draws none of its own and shows its words as the caption at every size, as it does at
|
|
241
|
+
* Large and on touch; any other `hint` is the caption too. Two "?" side by side would
|
|
242
|
+
* look the same and open different things.
|
|
243
|
+
*/
|
|
244
|
+
export interface FieldHelpProps {
|
|
245
|
+
/**
|
|
246
|
+
* Help the field is usable without — why it exists, how to choose, what the options
|
|
247
|
+
* mean — behind the field's one "?" on its label line: a {@link HelpPopover} named
|
|
248
|
+
* "About <label>" that opens on a tap (round 0.36, docs/text-size-harmonization.md §4).
|
|
249
|
+
* Pass a `HelpPopover` to name it yourself. `hint` stays the visible fact: with `help`
|
|
250
|
+
* set it is the caption under the field at every size, a `FieldHint` included.
|
|
251
|
+
*/
|
|
252
|
+
help?: ReactNode;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* The "?" for a field's `help` — the field's own name, "About <label>", in the reader's
|
|
257
|
+
* language. A component so that a field without `help` asks the labels nothing.
|
|
258
|
+
*/
|
|
259
|
+
function FieldHelp({ name, children }: { name: ReactNode; children: ReactNode }) {
|
|
260
|
+
const common = useKitLabels("common", DEFAULT_COMMON_LABELS);
|
|
261
|
+
const text = plainText(name);
|
|
262
|
+
return <HelpPopover label={text === undefined ? common.help : common.aboutField(text)}>{children}</HelpPopover>;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* A field's `help` as the "?" for its label line, or `undefined` when there is none. A
|
|
267
|
+
* {@link HelpPopover} is used as it is (it carries its own name); anything else is put
|
|
268
|
+
* in one named "About <name>" — `name` is the field's label, else its `aria-label`.
|
|
269
|
+
*/
|
|
270
|
+
export function fieldHelpMark(help: ReactNode, name: ReactNode): ReactNode | undefined {
|
|
271
|
+
if (!hasContent(help)) return undefined;
|
|
272
|
+
if (isValidElement(help) && help.type === HelpPopover) return help;
|
|
273
|
+
return <FieldHelp name={name}>{help}</FieldHelp>;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** What {@link useFieldHint} needs to draw a field's `help`. */
|
|
277
|
+
export interface FieldHelpSource {
|
|
278
|
+
/** The field's `help`. */
|
|
279
|
+
help?: ReactNode;
|
|
280
|
+
/** What names its "?": the field's label, else its `aria-label`. */
|
|
281
|
+
name?: ReactNode;
|
|
282
|
+
}
|
|
283
|
+
|
|
229
284
|
|
|
230
285
|
/**
|
|
231
286
|
* Whether a `hint` is a CAPTION (plain text: a non-empty string or a number) or
|
|
@@ -250,26 +305,43 @@ export interface FieldHintParts {
|
|
|
250
305
|
describedBy: string | undefined;
|
|
251
306
|
/** The caption's id while there is one. */
|
|
252
307
|
captionId: string | undefined;
|
|
253
|
-
/** The caption itself, or
|
|
254
|
-
captionText:
|
|
255
|
-
/**
|
|
256
|
-
*
|
|
308
|
+
/** The caption itself — a text hint, or any hint beside a `help` — or `undefined`. */
|
|
309
|
+
captionText: ReactNode | undefined;
|
|
310
|
+
/** What rides the label line — the `help`'s "?" ({@link fieldHelpMark}), else a
|
|
311
|
+
* non-text hint (a FieldHint) — or, on a field with no label line, the end edge
|
|
312
|
+
* outside the box. `undefined` when there is none. */
|
|
257
313
|
labelHint: ReactNode | undefined;
|
|
258
314
|
}
|
|
259
315
|
|
|
316
|
+
/**
|
|
317
|
+
* Whether a resolved `hint` goes under the field as its caption: text always (see
|
|
318
|
+
* {@link isTextHint}); with a `help` beside it, whatever it is — the label line's "?"
|
|
319
|
+
* is the help's (round 0.36, §4).
|
|
320
|
+
*/
|
|
321
|
+
export function isHintCaption(hint: ReactNode, withHelp: boolean): boolean {
|
|
322
|
+
return isTextHint(hint) || (withHelp && hasContent(hint));
|
|
323
|
+
}
|
|
324
|
+
|
|
260
325
|
/**
|
|
261
326
|
* Split a field's `hint` into the caption under it (attached with `aria-describedby`)
|
|
262
|
-
* or the "?" on its label line. See {@link isTextHint}.
|
|
327
|
+
* or the "?" on its label line. See {@link isTextHint}. With a `help` ({@link
|
|
328
|
+
* FieldHelpProps}), the help's "?" takes the label line and the hint is the caption.
|
|
263
329
|
*/
|
|
264
|
-
export function useFieldHint(
|
|
265
|
-
|
|
330
|
+
export function useFieldHint(
|
|
331
|
+
hintProp: ReactNode,
|
|
332
|
+
describedBy: string | undefined,
|
|
333
|
+
{ help, name }: FieldHelpSource = {},
|
|
334
|
+
): FieldHintParts {
|
|
335
|
+
const helpMark = fieldHelpMark(help, name);
|
|
336
|
+
const withHelp = helpMark !== undefined;
|
|
337
|
+
const hint = useInlineHint(hintProp, withHelp);
|
|
266
338
|
const captionId = useId();
|
|
267
|
-
const
|
|
339
|
+
const caption = isHintCaption(hint, withHelp);
|
|
268
340
|
return {
|
|
269
|
-
describedBy:
|
|
270
|
-
captionId:
|
|
271
|
-
captionText:
|
|
272
|
-
labelHint: !
|
|
341
|
+
describedBy: caption ? mergeDescribedBy(describedBy, captionId) : describedBy,
|
|
342
|
+
captionId: caption ? captionId : undefined,
|
|
343
|
+
captionText: caption ? hint : undefined,
|
|
344
|
+
labelHint: helpMark ?? (!caption && hasContent(hint) ? hint : undefined),
|
|
273
345
|
};
|
|
274
346
|
}
|
|
275
347
|
|
|
@@ -312,7 +384,7 @@ export function useFieldError(
|
|
|
312
384
|
invalid: boolean | undefined,
|
|
313
385
|
describedBy: string | undefined,
|
|
314
386
|
/** The caller's own `aria-invalid`. A form library sets THIS (see `@eifi1/ui-kit/rhf`
|
|
315
|
-
* `
|
|
387
|
+
* `RhfField`), not our `invalid` prop — and a field that announces invalid should
|
|
316
388
|
* look it too. */
|
|
317
389
|
ariaInvalid?: unknown,
|
|
318
390
|
): { isInvalid: boolean; describedBy: string | undefined; errorEl: ReactNode } {
|
|
@@ -589,24 +661,26 @@ export interface FieldMessages {
|
|
|
589
661
|
describedBy: string | undefined;
|
|
590
662
|
/** The caption and the error, for under the field; `null` when there is neither. */
|
|
591
663
|
below: ReactNode;
|
|
592
|
-
/**
|
|
593
|
-
* caption
|
|
664
|
+
/** What rides the LABEL line — the `help`'s "?", else a `FieldHint` — or `undefined`
|
|
665
|
+
* when the hint is a caption and there is no help. */
|
|
594
666
|
labelHint: ReactNode;
|
|
595
667
|
}
|
|
596
668
|
|
|
597
669
|
/**
|
|
598
|
-
* `hint` / `error` / `invalid` resolved the way `Select` resolves them —
|
|
670
|
+
* `hint` / `help` / `error` / `invalid` resolved the way `Select` resolves them —
|
|
599
671
|
* {@link useFieldHint} and {@link useFieldError} together, for a field that draws what
|
|
600
672
|
* goes under it in one place (a picker, a group, a field built on another).
|
|
601
673
|
*/
|
|
602
674
|
export function useFieldMessages({
|
|
603
675
|
hint,
|
|
676
|
+
help,
|
|
677
|
+
name,
|
|
604
678
|
error,
|
|
605
679
|
invalid,
|
|
606
680
|
describedBy,
|
|
607
681
|
ariaInvalid,
|
|
608
682
|
reasonId,
|
|
609
|
-
}: {
|
|
683
|
+
}: FieldHelpSource & {
|
|
610
684
|
hint?: ReactNode;
|
|
611
685
|
error?: ReactNode;
|
|
612
686
|
invalid?: boolean;
|
|
@@ -616,7 +690,7 @@ export function useFieldMessages({
|
|
|
616
690
|
* caption and before the error, as on Select. */
|
|
617
691
|
reasonId?: string | false;
|
|
618
692
|
}): FieldMessages {
|
|
619
|
-
const hintParts = useFieldHint(hint, describedBy);
|
|
693
|
+
const hintParts = useFieldHint(hint, describedBy, { help, name });
|
|
620
694
|
const field = useFieldError(error, invalid, mergeDescribedBy(hintParts.describedBy, reasonId), ariaInvalid);
|
|
621
695
|
return {
|
|
622
696
|
isInvalid: field.isInvalid,
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { useId } from "react";
|
|
2
|
-
import type {
|
|
3
|
-
import { LabelStrip, useFieldMessages } from "./field-parts";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* How far down the content starts, under the 11px label — see {@link FieldStripProps.pad}.
|
|
7
|
-
* Since 0.34 both are the one 20px strip.
|
|
8
|
-
*/
|
|
9
|
-
export type FieldStripPad = "clear" | "field";
|
|
2
|
+
import type { ComponentPropsWithRef, ReactNode } from "react";
|
|
3
|
+
import { LabelStrip, useFieldMessages, type FieldHelpProps } from "./field-parts";
|
|
10
4
|
|
|
11
5
|
/** What a {@link FieldStrip} hands render-prop children. */
|
|
12
6
|
export interface FieldStripIds {
|
|
@@ -19,7 +13,12 @@ export interface FieldStripIds {
|
|
|
19
13
|
describedBy: string | undefined;
|
|
20
14
|
}
|
|
21
15
|
|
|
22
|
-
|
|
16
|
+
/**
|
|
17
|
+
* A `div`'s props, `ref` included since 0.35 (round 0.35 R4, as Card and EmptyState took
|
|
18
|
+
* it in 0.34, API-2): the ref is the root — the group, or the plain box under
|
|
19
|
+
* `group={false}` — which a caller scrolls into view or measures.
|
|
20
|
+
*/
|
|
21
|
+
export interface FieldStripProps extends Omit<ComponentPropsWithRef<"div">, "children">, FieldHelpProps {
|
|
23
22
|
/** The 11px static label, on the line a labelled field's label sits on. */
|
|
24
23
|
label: ReactNode;
|
|
25
24
|
/**
|
|
@@ -37,21 +36,6 @@ export interface FieldStripProps extends Omit<ComponentPropsWithoutRef<"div">, "
|
|
|
37
36
|
* turns its map into a picture and drops its buttons, which no flag here could guess.
|
|
38
37
|
*/
|
|
39
38
|
disabled?: boolean;
|
|
40
|
-
/**
|
|
41
|
-
* @deprecated 0.34 — drop it; removed in 0.35. Both values are the same 20px strip
|
|
42
|
-
* since 0.34, and the prop does nothing; it stays so a caller that passes it still
|
|
43
|
-
* compiles.
|
|
44
|
-
*
|
|
45
|
-
* It chose between `"clear"` (20px) and `"field"` (16px: the strip plus a 26px
|
|
46
|
-
* bordered control made a labelled Input's 42px). The label row — the label and its
|
|
47
|
-
* "?" — ends 18px down, so over a 16px strip it crossed the content's top border by
|
|
48
|
-
* 2px (keksdose dev#593; the arithmetic is on `LABEL_STRIP_PAD` in field-parts.tsx).
|
|
49
|
-
* For a row of 42px fields, make the content 22px tall: 20 + 22 = 42, the shape
|
|
50
|
-
* ToggleGroup's `labelPlacement="strip"` has since 0.34.
|
|
51
|
-
*
|
|
52
|
-
* A `className` still merges after the strip's padding.
|
|
53
|
-
*/
|
|
54
|
-
pad?: FieldStripPad;
|
|
55
39
|
/**
|
|
56
40
|
* The wrapper is a `role="group"` named by the label (default), so a screen reader
|
|
57
41
|
* entering the map or the first button hears "Location, group" — what the visible
|
|
@@ -102,22 +86,23 @@ export interface FieldStripProps extends Omit<ComponentPropsWithoutRef<"div">, "
|
|
|
102
86
|
export function FieldStrip({
|
|
103
87
|
label,
|
|
104
88
|
hint,
|
|
89
|
+
help,
|
|
105
90
|
error,
|
|
106
91
|
disabled = false,
|
|
107
|
-
// Taken off so it never reaches the DOM; see `pad` (deprecated, one strip since 0.34).
|
|
108
|
-
pad: _pad,
|
|
109
92
|
group = true,
|
|
110
93
|
className,
|
|
111
94
|
children,
|
|
112
95
|
...rest
|
|
113
96
|
}: FieldStripProps) {
|
|
114
97
|
const labelId = useId();
|
|
115
|
-
const messages = useFieldMessages({ hint, error });
|
|
98
|
+
const messages = useFieldMessages({ hint, help, name: label, error });
|
|
116
99
|
const content = typeof children === "function" ? children({ labelId, describedBy: messages.describedBy }) : children;
|
|
117
100
|
// The caller's own description first, then the caption, then the error — the order
|
|
118
101
|
// every kit field reads them in.
|
|
119
102
|
const groupDescribedBy = [rest["aria-describedby"], messages.describedBy].filter(Boolean).join(" ") || undefined;
|
|
120
103
|
return (
|
|
104
|
+
// `rest` carries the caller's `ref` too (a plain prop in React 19): LabelStrip spreads
|
|
105
|
+
// its own rest onto the wrapper `<div>`, so the ref lands on the root.
|
|
121
106
|
<LabelStrip
|
|
122
107
|
{...rest}
|
|
123
108
|
{...(group
|
|
@@ -38,13 +38,6 @@ export interface FieldSyncLabels {
|
|
|
38
38
|
// Defined in ./field-sync-labels, which holds no component code (0.34, KS U8).
|
|
39
39
|
export { DEFAULT_FIELD_SYNC_LABELS };
|
|
40
40
|
|
|
41
|
-
/** @deprecated 0.34 — `useKitLabels("fieldSync", DEFAULT_FIELD_SYNC_LABELS, labels)`, which
|
|
42
|
-
* the provider reaches too, or the field's own `labels`; removed in 0.35 (refactor audit
|
|
43
|
-
* 2026-10, API-6a). A merge from before the provider, which no kit component calls. */
|
|
44
|
-
export function resolveFieldSyncLabels(labels?: Partial<FieldSyncLabels>): FieldSyncLabels {
|
|
45
|
-
return labels ? { ...DEFAULT_FIELD_SYNC_LABELS, ...labels } : DEFAULT_FIELD_SYNC_LABELS;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
41
|
export interface UseFieldSyncOptions<T> {
|
|
49
42
|
/** What the database currently holds. Changing it re-seeds a CLEAN field. */
|
|
50
43
|
value: T;
|
package/src/components/field.tsx
CHANGED
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
*
|
|
30
30
|
* Deliberately knows neither the wizard nor react-hook-form: `error` is a plain
|
|
31
31
|
* value. Pass `wizard.fieldErrors.iban`, a step-local error, or
|
|
32
|
-
* `fieldState.error?.message` from a `
|
|
33
|
-
* whichever of them gates the step, so a step can move between them without its
|
|
34
|
-
* fields changing. (Inside a react-hook-form form, `
|
|
35
|
-
*
|
|
32
|
+
* `fieldState.error?.message` from a react-hook-form `Controller` — the markup is the
|
|
33
|
+
* same whichever of them gates the step, so a step can move between them without its
|
|
34
|
+
* fields changing. (Inside a react-hook-form form, `RhfField` from `@eifi1/ui-kit/rhf`
|
|
35
|
+
* does the same job with the ids taken from the form.)
|
|
36
36
|
*
|
|
37
37
|
* The error is NOT `role="alert"`, for the reason the kit's `error` prop gives (see
|
|
38
38
|
* `useFieldError` in components/field-parts.tsx): it is read when focus reaches the control.
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
import { useId, type ReactNode } from "react";
|
|
41
41
|
import { cn } from "../lib/cn";
|
|
42
42
|
import { hasContent } from "../lib/presence";
|
|
43
|
-
import { useInlineHint } from "./field-parts";
|
|
43
|
+
import { fieldHelpMark, useInlineHint, type FieldHelpProps } from "./field-parts";
|
|
44
44
|
import { Label } from "./field-base";
|
|
45
45
|
|
|
46
46
|
/** What a `Field` hands its render-prop children, to spread on the control. */
|
|
@@ -91,7 +91,7 @@ const LABEL_VISIBILITY: Record<FieldLabelVisibility, string | undefined> = {
|
|
|
91
91
|
"below-lg": "lg:sr-only",
|
|
92
92
|
};
|
|
93
93
|
|
|
94
|
-
export interface FieldProps {
|
|
94
|
+
export interface FieldProps extends FieldHelpProps {
|
|
95
95
|
/** The label above the control. Omit it for a group whose control is labelled
|
|
96
96
|
* some other way; the hint and error still render. */
|
|
97
97
|
label?: ReactNode;
|
|
@@ -123,6 +123,7 @@ export function Field({
|
|
|
123
123
|
label,
|
|
124
124
|
required,
|
|
125
125
|
hint: hintProp,
|
|
126
|
+
help,
|
|
126
127
|
error,
|
|
127
128
|
htmlFor,
|
|
128
129
|
disabled,
|
|
@@ -138,7 +139,10 @@ export function Field({
|
|
|
138
139
|
const labelId = `${generated}-label`;
|
|
139
140
|
// §4: a FieldHint under the control is its words at Large and on a touch screen, not
|
|
140
141
|
// a lone "?" (DUP-2, refactor audit 2026-10). A HelpPopover stays a "?".
|
|
141
|
-
|
|
142
|
+
// With a `help` (0.36) its "?" follows the label, and a FieldHint is its words at
|
|
143
|
+
// every size: the help's is the field's only "?".
|
|
144
|
+
const helpMark = fieldHelpMark(help, label);
|
|
145
|
+
const hint = useInlineHint(hintProp, helpMark !== undefined);
|
|
142
146
|
const hasHint = hasContent(hint);
|
|
143
147
|
const hasError = hasContent(error);
|
|
144
148
|
const describedBy = [hasHint && hintId, hasError && errorId].filter(Boolean).join(" ");
|
|
@@ -148,6 +152,19 @@ export function Field({
|
|
|
148
152
|
"aria-invalid": hasError || undefined,
|
|
149
153
|
"aria-required": required || undefined,
|
|
150
154
|
};
|
|
155
|
+
const labelEl = label !== undefined && (
|
|
156
|
+
<Label
|
|
157
|
+
id={labelId}
|
|
158
|
+
htmlFor={id}
|
|
159
|
+
required={required}
|
|
160
|
+
disabled={disabled}
|
|
161
|
+
size={labelSize}
|
|
162
|
+
data-error={hasError || undefined}
|
|
163
|
+
className={cn("data-[error=true]:text-danger", LABEL_VISIBILITY[labelVisibility])}
|
|
164
|
+
>
|
|
165
|
+
{label}
|
|
166
|
+
</Label>
|
|
167
|
+
);
|
|
151
168
|
return (
|
|
152
169
|
<div
|
|
153
170
|
data-slot="field"
|
|
@@ -162,18 +179,14 @@ export function Field({
|
|
|
162
179
|
className,
|
|
163
180
|
)}
|
|
164
181
|
>
|
|
165
|
-
{
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
className={cn("data-[error=true]:text-danger", LABEL_VISIBILITY[labelVisibility])}
|
|
174
|
-
>
|
|
175
|
-
{label}
|
|
176
|
-
</Label>
|
|
182
|
+
{helpMark === undefined && labelEl}
|
|
183
|
+
{helpMark !== undefined && (
|
|
184
|
+
// The label and its "?" on one line; the "?" stays visible where the label is
|
|
185
|
+
// hidden (`labelVisibility`) — a hidden button would still take the focus.
|
|
186
|
+
<div className="flex items-center gap-1">
|
|
187
|
+
{labelEl}
|
|
188
|
+
<span className="flex shrink-0 items-center">{helpMark}</span>
|
|
189
|
+
</div>
|
|
177
190
|
)}
|
|
178
191
|
{typeof children === "function"
|
|
179
192
|
? children(control, { labelId: label !== undefined ? labelId : undefined })
|
|
@@ -174,14 +174,15 @@ export function FullBleedDialog({
|
|
|
174
174
|
// to whichever of them is topmost — one press dismissing the sheet AND the edit
|
|
175
175
|
// behind it was Keksdose live #309 (*"Mouse Back does not only close the select but
|
|
176
176
|
// also the whole edit or create dialog"*) on a different key.
|
|
177
|
-
useDismissLayer(open, requestClose);
|
|
177
|
+
const layer = useDismissLayer(open, requestClose);
|
|
178
178
|
const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
|
|
179
179
|
// The caller's handler first (keksdose's transaction-search keeps its list keys on
|
|
180
180
|
// the dialog); a `preventDefault()` IN THAT HANDLER claims Escape. Only there: a
|
|
181
181
|
// descendant's does not count. A SearchField in the header prevents Escape to stop
|
|
182
182
|
// Chromium clearing a type=search input, and in 0.8.0 that silently stopped Escape
|
|
183
|
-
// from closing the dialog (keksdose). The one rule `Modal` now shares
|
|
184
|
-
|
|
183
|
+
// from closing the dialog (keksdose). The one rule `Modal` now shares — as is this
|
|
184
|
+
// one: the handler sees Escape only while this dialog is the layer on top (0.35).
|
|
185
|
+
runOwnKeyDown(e, onKeyDown, layer);
|
|
185
186
|
takeEscape(e);
|
|
186
187
|
};
|
|
187
188
|
|
|
@@ -42,12 +42,14 @@ const HELP_WIDTH: RemLength = "20rem";
|
|
|
42
42
|
* new row on a phone). `useInlineHint` turns only a FieldHint into a caption, so this
|
|
43
43
|
* one stays on the label line at every size.
|
|
44
44
|
*
|
|
45
|
-
* **On a field
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
45
|
+
* **On a field: its `help`** (0.36, round 0.36 decision 1). Every kit field that takes a
|
|
46
|
+
* `hint` takes a `help` beside it, and the `@eifi1/ui-kit/rhf` bindings too: pass the
|
|
47
|
+
* help's words and the field draws this "?" on its label line (an unlabelled one at its
|
|
48
|
+
* end edge, outside the box), named "About <label>" — or pass a HelpPopover to name it
|
|
49
|
+
* yourself. `hint` stays the FACT, printed under the field; while `help` is set a
|
|
50
|
+
* FieldHint there draws no "?" of its own, so the field has one. Passed as `hint`, as in
|
|
51
|
+
* 0.34, it still rides the label line. It also stands on its own, beside a heading or a
|
|
52
|
+
* column title.
|
|
51
53
|
*
|
|
52
54
|
* **A popover, not a tooltip**: a tooltip bubble is for a line, and opens on hover a
|
|
53
55
|
* finger never makes. This is the kit {@link Popover}: it opens and closes on a tap or a
|
|
@@ -60,7 +62,7 @@ const HELP_WIDTH: RemLength = "20rem";
|
|
|
60
62
|
* accepted and cleared?", keksdose live #247); "!" is a warning.
|
|
61
63
|
*
|
|
62
64
|
* ```tsx
|
|
63
|
-
* <Select label="Status" hint={
|
|
65
|
+
* <Select label="Status" hint="Cleared and reconciled rows are locked." help={
|
|
64
66
|
* <HelpPopover label="What do the statuses mean?">
|
|
65
67
|
* Pending: … Accepted: … Cleared: … Reconciled: …
|
|
66
68
|
* </HelpPopover>
|
|
@@ -20,12 +20,13 @@ export interface HoverMenuProps extends Omit<ComponentPropsWithoutRef<"div">, "c
|
|
|
20
20
|
trigger: (state: { open: boolean; toggle: () => void; close: () => void }) => ReactNode;
|
|
21
21
|
children: (close: () => void) => ReactNode;
|
|
22
22
|
/**
|
|
23
|
-
* Which edge of the trigger the panel lines up with
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
* Which edge of the trigger the panel lines up with, by the reading direction: `end`
|
|
24
|
+
* is the right edge in LTR and the left in RTL. Default `end` — the same right-aligned
|
|
25
|
+
* panel as before in LTR, mirrored in RTL. The physical `left` / `right` went in 0.35
|
|
26
|
+
* (round 0.35 R1, refactor audit 2026-10, API-6e): `right` is `end` in a left-to-right
|
|
27
|
+
* page, `left` is `start`.
|
|
27
28
|
*/
|
|
28
|
-
align?: "start" | "end"
|
|
29
|
+
align?: "start" | "end";
|
|
29
30
|
panelClassName?: string;
|
|
30
31
|
/** Extra classes for the WRAPPER (the panel has {@link panelClassName}). */
|
|
31
32
|
className?: string;
|
|
@@ -34,14 +35,6 @@ export interface HoverMenuProps extends Omit<ComponentPropsWithoutRef<"div">, "c
|
|
|
34
35
|
ref?: Ref<HTMLDivElement>;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
/**
|
|
38
|
-
* @deprecated 0.34 — `"start"` / `"end"`, which follow the reading direction: `"right"`
|
|
39
|
-
* is `"end"` in a left-to-right page, the default; removed in 0.35 (refactor audit
|
|
40
|
-
* 2026-10, API-6e). The physical edges HoverMenu's `align` — and TopBarActionMenu's and
|
|
41
|
-
* FeedbackMenu's, which hand it on — still take.
|
|
42
|
-
*/
|
|
43
|
-
type PhysicalAlign = "left" | "right";
|
|
44
|
-
|
|
45
38
|
// Hovering waits briefly before opening so sweeping the cursor across a row of
|
|
46
39
|
// triggers doesn't flash menus; closing waits so the cursor can travel from
|
|
47
40
|
// trigger to panel. Click/keyboard toggling is instant (no "opening" phase).
|
|
@@ -50,7 +43,7 @@ const CLOSE_DELAY_MS = 120;
|
|
|
50
43
|
|
|
51
44
|
type Phase = "closed" | "opening" | "open" | "closing";
|
|
52
45
|
|
|
53
|
-
const ALIGN_CLASS = { start: "start-0", end: "end-0"
|
|
46
|
+
const ALIGN_CLASS = { start: "start-0", end: "end-0" } as const;
|
|
54
47
|
|
|
55
48
|
/** Explicit menu-item roles a caller may already have written. */
|
|
56
49
|
const ITEM_ROLES = '[role="menuitem"],[role="menuitemcheckbox"],[role="menuitemradio"]';
|
|
@@ -188,7 +181,7 @@ export function HoverMenu({
|
|
|
188
181
|
// DUP-1). Focus goes back to the trigger only when it was inside the menu: a panel
|
|
189
182
|
// opened by hover while the user is typing elsewhere must not yank the caret over
|
|
190
183
|
// here on the way out.
|
|
191
|
-
useDismissLayer(open, () => {
|
|
184
|
+
const layer = useDismissLayer(open, () => {
|
|
192
185
|
const hadFocus = wrapperRef.current?.contains(document.activeElement) ?? false;
|
|
193
186
|
close();
|
|
194
187
|
if (hadFocus) triggerEl()?.focus();
|
|
@@ -298,7 +291,10 @@ export function HoverMenu({
|
|
|
298
291
|
onMouseEnter={handleMouseEnter}
|
|
299
292
|
onMouseLeave={handleMouseLeave}
|
|
300
293
|
onKeyDown={(e) => {
|
|
301
|
-
|
|
294
|
+
// The caller's handler sees Escape only while this menu is the layer on top: a
|
|
295
|
+
// tooltip on one of its rows takes that press first (round 0.35 R2, the rule
|
|
296
|
+
// the dialogs got first). Every other key, and a closed menu's, as before.
|
|
297
|
+
runOwnKeyDown(e, rest.onKeyDown, layer);
|
|
302
298
|
// Focus on the trigger or in the menu: the key stops here, so a panel around
|
|
303
299
|
// the menu does not close with it.
|
|
304
300
|
if (open) takeEscape(e);
|
|
@@ -7,7 +7,7 @@ import { TILE_SIZE, TileRadioGroup } from "./tile-radio";
|
|
|
7
7
|
import type { TileItem, TileSize } from "./tile-radio";
|
|
8
8
|
import { hasContent } from "../lib/presence";
|
|
9
9
|
import { foldForSearch } from "../lib/text-match";
|
|
10
|
-
import { LabelStrip, useFieldMessages } from "./field-parts";
|
|
10
|
+
import { LabelStrip, useFieldMessages, type FieldHelpProps } from "./field-parts";
|
|
11
11
|
import { DEFAULT_ICON_PICKER_LABELS } from "./icon-picker-labels";
|
|
12
12
|
|
|
13
13
|
export interface IconPickerLabels {
|
|
@@ -52,7 +52,8 @@ export interface IconOption<T extends string> {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
export interface IconPickerProps<T extends string>
|
|
55
|
-
extends Omit<ComponentPropsWithRef<"div">, "onChange" | "children" | "defaultValue"
|
|
55
|
+
extends Omit<ComponentPropsWithRef<"div">, "onChange" | "children" | "defaultValue">,
|
|
56
|
+
FieldHelpProps {
|
|
56
57
|
options: IconOption<T>[];
|
|
57
58
|
/** The chosen icon, or `null` for none. */
|
|
58
59
|
value: T | null;
|
|
@@ -122,6 +123,7 @@ export function IconPicker<T extends string>({
|
|
|
122
123
|
labels,
|
|
123
124
|
label,
|
|
124
125
|
hint,
|
|
126
|
+
help,
|
|
125
127
|
className,
|
|
126
128
|
"aria-label": ariaLabel,
|
|
127
129
|
"aria-labelledby": ariaLabelledBy,
|
|
@@ -134,9 +136,12 @@ export function IconPicker<T extends string>({
|
|
|
134
136
|
const mixedId = useId();
|
|
135
137
|
const labelId = useId();
|
|
136
138
|
const labelled = hasContent(label);
|
|
137
|
-
// The label line's "?", or the caption under the grid (DUP-2). Only with a label
|
|
139
|
+
// The label line's "?", or the caption under the grid (DUP-2). Only with a label, the
|
|
140
|
+
// help's "?" too (0.36).
|
|
138
141
|
const messages = useFieldMessages({
|
|
139
142
|
hint: labelled ? hint : undefined,
|
|
143
|
+
help: labelled ? help : undefined,
|
|
144
|
+
name: label,
|
|
140
145
|
describedBy: ariaDescribedBy,
|
|
141
146
|
reasonId: mixed && mixedId,
|
|
142
147
|
});
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
useFieldHint,
|
|
35
35
|
useLockReason,
|
|
36
36
|
type DisabledReasonDisplay,
|
|
37
|
+
type FieldHelpProps,
|
|
37
38
|
} from "./field-parts";
|
|
38
39
|
import { hasContent } from "../lib/presence";
|
|
39
40
|
import { useCommitReason, type CommitScope } from "./write-lock";
|
|
@@ -47,7 +48,8 @@ const CREATE_ROW_CLASS = "flex items-center gap-2 font-medium text-brand";
|
|
|
47
48
|
/** `id` is the INPUT's and `onChange` is the field's — see {@link ComboboxProps}
|
|
48
49
|
* for why the div's spellings of them are omitted. */
|
|
49
50
|
export interface InlineEntityComboboxProps<V extends string | number, C extends ComboClearValue = null>
|
|
50
|
-
extends Omit<ComponentPropsWithoutRef<"div">, "id" | "onChange"
|
|
51
|
+
extends Omit<ComponentPropsWithoutRef<"div">, "id" | "onChange">,
|
|
52
|
+
FieldHelpProps {
|
|
51
53
|
/** Selected option id; `null` or `clearValue` when nothing is selected. */
|
|
52
54
|
value: V | C | null;
|
|
53
55
|
/** Required and unanswered — see {@link Combobox}'s `invalid`. */
|
|
@@ -83,7 +85,7 @@ export interface InlineEntityComboboxProps<V extends string | number, C extends
|
|
|
83
85
|
emptyLabel?: string;
|
|
84
86
|
closeLabel?: string;
|
|
85
87
|
/** The phone sheet's heading (and, as a string, its accessible name) for a field
|
|
86
|
-
* whose label is drawn by someone else — a
|
|
88
|
+
* whose label is drawn by someone else — a bound field's label;
|
|
87
89
|
* `RhfInlineEntityCombobox` hands its label over here (0.24). Default: `label`.
|
|
88
90
|
* See {@link Combobox}'s `sheetTitle`. */
|
|
89
91
|
sheetTitle?: ReactNode;
|
|
@@ -226,6 +228,7 @@ export function InlineEntityCombobox<V extends string | number, C extends ComboC
|
|
|
226
228
|
invalid,
|
|
227
229
|
error,
|
|
228
230
|
hint,
|
|
231
|
+
help,
|
|
229
232
|
ref,
|
|
230
233
|
"aria-label": ariaLabel,
|
|
231
234
|
// Off `rest` and onto the <input>, which is the combobox a reader meets: `Field`'s
|
|
@@ -239,7 +242,7 @@ export function InlineEntityCombobox<V extends string | number, C extends ComboC
|
|
|
239
242
|
// The clear value reads as "nothing selected", whichever one the caller picked —
|
|
240
243
|
// so from here down `value` is the id or `null`, as it always was.
|
|
241
244
|
const value: V | null = rawValue == null || rawValue === clearValue ? null : (rawValue as V);
|
|
242
|
-
const hintParts = useFieldHint(hint, ariaDescribedBy);
|
|
245
|
+
const hintParts = useFieldHint(hint, ariaDescribedBy, { help, name: label ?? ariaLabel });
|
|
243
246
|
const field = useFieldError(error, invalid, hintParts.describedBy, ariaInvalid);
|
|
244
247
|
const generated = useId();
|
|
245
248
|
const fieldId = id ?? generated;
|