@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 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/rhf/form-core.tsx"],"sourcesContent":["/**\n * The react-hook-form adapter: the five parts every form is built from, and the hook\n * they share. `@eifi1/ui-kit/rhf`.\n *\n * The kit's own module since 0.34 (refactor audit 2026-10, API-6f): the bound `Rhf*`\n * fields build on these parts, and import them from here. ./form is the public face —\n * `Form`, and until 0.35 the parts under their deprecated names, which no app imports.\n *\n * ```tsx\n * <Form {...form}>\n * <FormField control={form.control} name=\"amount\" render={({ field }) => (\n * <FormItem>\n * <FormLabel required>Amount</FormLabel>\n * <FormControl>\n * <NumberField value={field.value} onCommit={field.onChange} />\n * </FormControl>\n * <FormMessage />\n * </FormItem>\n * )} />\n * </Form>\n * ```\n *\n * The shape is shadcn's `form.tsx`, on purpose: Kastlan builds every form from that\n * file, so moving onto this one is an import line rather than a rewrite. What differs\n * is what the shadcn file gets wrong:\n *\n * - **`aria-describedby` names only what is on screen.** shadcn always points the\n * control at a description id, rendered or not, and at the message id whenever the\n * field has an error, whether a message was rendered for it or not. A reference to\n * a node that does not exist describes the field as nothing. Here the description\n * and the message say when they are mounted, and the control points at exactly\n * those.\n * - **Merged, never replaced.** A control that already carries its own\n * `aria-describedby` keeps it, first — the same rule as the kit's `error` prop\n * (see `useFieldError` in components/field-parts.tsx).\n * - **No Radix.** `FormControl` is a one-child `cloneElement`, not `Slot`, and the\n * label is the kit's own `Label` — the kit carries no Radix dependency and this\n * entry is not the place to start.\n *\n * ## Why this is its own entry\n *\n * The main barrel once shipped a react-hook-form hook (`use-rhf-wizard-step`) and\n * removed it: it made react-hook-form an install every consumer's typecheck paid for,\n * for a hook nobody called (see the wizard section of src/index.ts). This is the\n * answer to that, not a reversal of it. Nothing outside `src/rhf*` imports\n * react-hook-form — `__tests__/packaging-contract.test.ts` holds that — and the peer is\n * optional, so an app that does not use it installs nothing and imports nothing.\n *\n * ## Painting the field\n *\n * `FormControl` sets `aria-invalid` on its child. `NumberField` and the pickers paint\n * from that attribute; `Input`, `Select` and `Textarea` paint only from their\n * `invalid` prop (see its note in components/field-base.tsx: a bare attribute announces but\n * does not paint), so pass it from the render prop —\n * `<Input {...field} invalid={fieldState.invalid} />`. `FormControl` does not inject\n * `invalid` itself because its child may be a native element, which would print it\n * into the DOM as an unknown attribute.\n *\n * ## Clearing a picker: `null`, unless the picker is told otherwise\n *\n * Nothing here touches a value. `FormField` is `Controller`, so what a control hands\n * `field.onChange` is exactly what lands in the form — and what the entity pickers\n * hand it on a clear is `null`: `EntityCombobox`'s \"×\", `InlineEntityCombobox`'s \"×\"\n * and its emptied text. (`MultiEntityCombobox` and `MultiSelect` clear to `[]`.)\n *\n * A zod schema that spells \"no choice\" as `\"\"` (`z.string()`, or `z.literal(\"\")` in a\n * union) then fails on the `null`. Say so on the PICKER, not here:\n *\n * ```tsx\n * <EntityCombobox clearValue=\"\" value={field.value} onChange={field.onChange} … />\n * ```\n *\n * `clearValue` also types `onChange` (`(v: V | \"\") => void` rather than\n * `V | null`) and reads `\"\"` back as \"nothing selected\", so an initial `defaultValues`\n * of `\"\"` shows the placeholder rather than an unresolvable id. The adapter does not\n * coerce because it cannot see the schema: mapping `null` to `\"\"` for every field\n * would break every schema that wants `null` (`z.string().nullable()`), which is the\n * pickers' default for a reason — it is the one value no option can have.\n */\nimport {\n Children,\n cloneElement,\n createContext,\n isValidElement,\n useCallback,\n useContext,\n useId,\n useLayoutEffect,\n useMemo,\n useState,\n type ComponentProps,\n type ReactElement,\n} from \"react\";\nimport {\n Controller,\n FormProvider,\n useFormContext,\n useFormState,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\";\nimport { Label, type LabelProps } from \"../components/field-base\";\nimport { cn } from \"../lib/cn\";\n\n/** The form's `useForm()` return, spread in: `<Form {...form}>`. react-hook-form's own\n * `FormProvider`, under the name the shadcn file gave it. */\nexport const Form = FormProvider;\n\n// ── contexts ─────────────────────────────────────────────────────────────────\n\nconst FormFieldContext = createContext<{ name: string } | null>(null);\n\n/** The two optional nodes a control can be described by. */\ntype Described = \"description\" | \"message\";\n\ninterface FormItemContextValue {\n id: string;\n mounted: Record<Described, boolean>;\n mark: (slot: Described, on: boolean) => void;\n}\n\nconst FormItemContext = createContext<FormItemContextValue | null>(null);\n\n// ── FormField ────────────────────────────────────────────────────────────────\n\n/**\n * react-hook-form's `Controller`, with the field's name put in context for the parts\n * below it. Takes exactly `Controller`'s props.\n */\nexport function FormField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformedValues = TFieldValues,\n>(props: ControllerProps<TFieldValues, TName, TTransformedValues>) {\n const value = useMemo(() => ({ name: props.name as string }), [props.name]);\n return (\n <FormFieldContext.Provider value={value}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n );\n}\n\n// ── useFormField ─────────────────────────────────────────────────────────────\n\n/**\n * The ids and the state of the field around the caller: for a part of your own that\n * sits beside the kit's (a character counter that belongs in `aria-describedby`, a\n * label with a different look).\n *\n * Throws outside a `FormField` + `FormItem` pair. shadcn's version answered there with\n * ids like `undefined-form-item`, which label nothing and fail nowhere.\n */\nexport function useFormField() {\n const field = useContext(FormFieldContext);\n const item = useContext(FormItemContext);\n if (!field) throw new Error(\"useFormField must be used inside <FormField>.\");\n if (!item) throw new Error(\"useFormField must be used inside <FormItem>.\");\n const { getFieldState } = useFormContext();\n // Subscribes this part to the field's state, so a label or message re-renders when\n // the field's error changes without the whole form doing so.\n const formState = useFormState({ name: field.name });\n const state = getFieldState(field.name, formState);\n const formDescriptionId = `${item.id}-description`;\n const formMessageId = `${item.id}-message`;\n const describedBy = [\n item.mounted.description && formDescriptionId,\n item.mounted.message && formMessageId,\n ]\n .filter(Boolean)\n .join(\" \");\n return {\n id: item.id,\n name: field.name,\n formItemId: `${item.id}-control`,\n formDescriptionId,\n formMessageId,\n /** The ids of the description and message that are actually rendered, or\n * `undefined` when neither is. */\n describedBy: describedBy || undefined,\n ...state,\n };\n}\n\n// ── FormItem ─────────────────────────────────────────────────────────────────\n\nexport type FormItemProps = ComponentProps<\"div\">;\n\n/** One field's box: mints the id its label, control, description and message share. */\nexport function FormItem({ className, ...rest }: FormItemProps) {\n const id = useId();\n const [mounted, setMounted] = useState<Record<Described, boolean>>({\n description: false,\n message: false,\n });\n const mark = useCallback(\n (slot: Described, on: boolean) =>\n setMounted((prev) => (prev[slot] === on ? prev : { ...prev, [slot]: on })),\n [],\n );\n const value = useMemo(() => ({ id, mounted, mark }), [id, mounted, mark]);\n return (\n <FormItemContext.Provider value={value}>\n {/* `content-start`: stretched to a taller neighbour's height in a grid row, the\n item gave the extra to its rows and its control sat lower (showcase audit). */}\n <div data-slot=\"form-item\" {...rest} className={cn(\"grid content-start gap-1\", className)} />\n </FormItemContext.Provider>\n );\n}\n\n/** Report a describing node's presence to the item, so the control points at it only\n * while it is on screen. A layout effect, so the reference lands before paint. */\nfunction useDescribes(slot: Described, on: boolean) {\n const item = useContext(FormItemContext);\n const mark = item?.mark;\n useLayoutEffect(() => {\n if (!on || !mark) return;\n mark(slot, true);\n return () => mark(slot, false);\n }, [slot, on, mark]);\n}\n\n// ── FormLabel ────────────────────────────────────────────────────────────────\n\nexport type FormLabelProps = LabelProps;\n\n/**\n * The kit's {@link Label}, bound to the control by `htmlFor` and turned to the danger\n * colour while the field is invalid. `required` draws the kit's `aria-hidden` mark:\n * whether the field is required is the control's to announce.\n */\nexport function FormLabel({ className, ...rest }: FormLabelProps) {\n const { error, formItemId } = useFormField();\n return (\n <Label\n data-slot=\"form-label\"\n data-error={error ? true : undefined}\n htmlFor={formItemId}\n {...rest}\n className={cn(\"data-[error=true]:text-danger\", className)}\n />\n );\n}\n\n// ── FormControl ──────────────────────────────────────────────────────────────\n\nexport interface FormControlProps {\n /** Exactly one element: the kit field, or a native one. It receives `id`,\n * `aria-describedby` and `aria-invalid`. */\n children: ReactElement;\n}\n\ntype AriaProps = {\n id?: string;\n \"aria-describedby\"?: string;\n \"aria-invalid\"?: ComponentProps<\"input\">[\"aria-invalid\"];\n};\n\n/**\n * Wires its one child to the item: the `id` the label points at, `aria-describedby`\n * naming the rendered description and message, and `aria-invalid` while the field has\n * an error.\n *\n * The child's own values win where it has them (an explicit `id`, a set\n * `aria-invalid`), as they did under Radix `Slot`; its own `aria-describedby` is\n * merged in front of the item's rather than replaced.\n */\nexport function FormControl({ children }: FormControlProps) {\n const { invalid, formItemId, describedBy } = useFormField();\n const child = Children.only(children);\n if (!isValidElement<AriaProps>(child)) return child;\n const own = child.props;\n const merged = [own[\"aria-describedby\"], describedBy].filter(Boolean).join(\" \");\n return cloneElement(child, {\n id: own.id ?? formItemId,\n \"aria-describedby\": merged || undefined,\n \"aria-invalid\": own[\"aria-invalid\"] ?? (invalid || undefined),\n });\n}\n\n// ── FormDescription / FormMessage ────────────────────────────────────────────\n\nexport type FormDescriptionProps = ComponentProps<\"p\">;\n\n/** Standing advice under the field (\"at least twelve characters\"). */\nexport function FormDescription({ className, ...rest }: FormDescriptionProps) {\n const { formDescriptionId } = useFormField();\n useDescribes(\"description\", true);\n return (\n <p\n data-slot=\"form-description\"\n {...rest}\n id={formDescriptionId}\n className={cn(\"text-caption leading-tight text-muted\", className)}\n />\n );\n}\n\nexport type FormMessageProps = ComponentProps<\"p\">;\n\n/**\n * The field's error message, from the form — the kit renders no string of its own\n * here; the schema or the `rules` carry the words. Without an error it renders its\n * `children`, if any, and otherwise nothing.\n *\n * Deliberately NOT `role=\"alert\"`, for the reason the kit's `error` prop gives: the\n * message is read when focus reaches the control, which is where a field's own error\n * is wanted, and an alert would interrupt on every keystroke of a form that\n * re-validates as you type.\n */\nexport function FormMessage({ className, children, ...rest }: FormMessageProps) {\n const { error, formMessageId } = useFormField();\n const body = error ? String(error.message ?? \"\") : children;\n const shown = body !== undefined && body !== null && body !== false && body !== \"\";\n useDescribes(\"message\", shown);\n if (!shown) return null;\n return (\n <p\n data-slot=\"form-message\"\n {...rest}\n id={formMessageId}\n className={cn(\"text-caption leading-tight text-danger\", className)}\n >\n {body}\n </p>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/rhf/form-core.tsx"],"sourcesContent":["/**\n * The react-hook-form adapter: the five parts every bound field is built from, and the\n * hook they share. Behind `@eifi1/ui-kit/rhf`, which exports `Form` alone of them.\n *\n * The kit's own module since 0.34 (refactor audit 2026-10, API-6f): the bound `Rhf*`\n * fields and `RhfField` build on these parts, and import them from here. ./form is the\n * public face — `Form`; the parts left the public surface in 0.35 (deprecated in 0.34),\n * when no app imported them any more.\n *\n * ```tsx\n * <Form {...form}>\n * <FormField control={form.control} name=\"amount\" render={({ field }) => (\n * <FormItem>\n * <FormLabel required>Amount</FormLabel>\n * <FormControl>\n * <NumberField value={field.value} onCommit={field.onChange} />\n * </FormControl>\n * <FormMessage />\n * </FormItem>\n * )} />\n * </Form>\n * ```\n *\n * The shape is shadcn's `form.tsx`, on purpose: Kastlan builds every form from that\n * file, so moving onto this one is an import line rather than a rewrite. What differs\n * is what the shadcn file gets wrong:\n *\n * - **`aria-describedby` names only what is on screen.** shadcn always points the\n * control at a description id, rendered or not, and at the message id whenever the\n * field has an error, whether a message was rendered for it or not. A reference to\n * a node that does not exist describes the field as nothing. Here the description\n * and the message say when they are mounted, and the control points at exactly\n * those.\n * - **Merged, never replaced.** A control that already carries its own\n * `aria-describedby` keeps it, first — the same rule as the kit's `error` prop\n * (see `useFieldError` in components/field-parts.tsx).\n * - **No Radix.** `FormControl` is a one-child `cloneElement`, not `Slot`, and the\n * label is the kit's own `Label` — the kit carries no Radix dependency and this\n * entry is not the place to start.\n *\n * ## Why this is its own entry\n *\n * The main barrel once shipped a react-hook-form hook (`use-rhf-wizard-step`) and\n * removed it: it made react-hook-form an install every consumer's typecheck paid for,\n * for a hook nobody called (see the wizard section of src/index.ts). This is the\n * answer to that, not a reversal of it. Nothing outside `src/rhf*` imports\n * react-hook-form — `__tests__/packaging-contract.test.ts` holds that — and the peer is\n * optional, so an app that does not use it installs nothing and imports nothing.\n *\n * ## Painting the field\n *\n * `FormControl` sets `aria-invalid` on its child. `NumberField` and the pickers paint\n * from that attribute; `Input`, `Select` and `Textarea` paint only from their\n * `invalid` prop (see its note in components/field-base.tsx: a bare attribute announces but\n * does not paint), so pass it from the render prop —\n * `<Input {...field} invalid={fieldState.invalid} />`. `FormControl` does not inject\n * `invalid` itself because its child may be a native element, which would print it\n * into the DOM as an unknown attribute.\n *\n * ## Clearing a picker: `null`, unless the picker is told otherwise\n *\n * Nothing here touches a value. `FormField` is `Controller`, so what a control hands\n * `field.onChange` is exactly what lands in the form — and what the entity pickers\n * hand it on a clear is `null`: `EntityCombobox`'s \"×\", `InlineEntityCombobox`'s \"×\"\n * and its emptied text. (`MultiEntityCombobox` and `MultiSelect` clear to `[]`.)\n *\n * A zod schema that spells \"no choice\" as `\"\"` (`z.string()`, or `z.literal(\"\")` in a\n * union) then fails on the `null`. Say so on the PICKER, not here:\n *\n * ```tsx\n * <EntityCombobox clearValue=\"\" value={field.value} onChange={field.onChange} … />\n * ```\n *\n * `clearValue` also types `onChange` (`(v: V | \"\") => void` rather than\n * `V | null`) and reads `\"\"` back as \"nothing selected\", so an initial `defaultValues`\n * of `\"\"` shows the placeholder rather than an unresolvable id. The adapter does not\n * coerce because it cannot see the schema: mapping `null` to `\"\"` for every field\n * would break every schema that wants `null` (`z.string().nullable()`), which is the\n * pickers' default for a reason — it is the one value no option can have.\n */\nimport {\n Children,\n cloneElement,\n createContext,\n isValidElement,\n useCallback,\n useContext,\n useId,\n useLayoutEffect,\n useMemo,\n useState,\n type ComponentProps,\n type ReactElement,\n} from \"react\";\nimport {\n Controller,\n FormProvider,\n useFormContext,\n useFormState,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\";\nimport { Label, type LabelProps } from \"../components/field-base\";\nimport { cn } from \"../lib/cn\";\n\n/** The form's `useForm()` return, spread in: `<Form {...form}>`. react-hook-form's own\n * `FormProvider`, under the name the shadcn file gave it. */\nexport const Form = FormProvider;\n\n// ── contexts ─────────────────────────────────────────────────────────────────\n\nconst FormFieldContext = createContext<{ name: string } | null>(null);\n\n/** The two optional nodes a control can be described by. */\ntype Described = \"description\" | \"message\";\n\ninterface FormItemContextValue {\n id: string;\n mounted: Record<Described, boolean>;\n mark: (slot: Described, on: boolean) => void;\n}\n\nconst FormItemContext = createContext<FormItemContextValue | null>(null);\n\n// ── FormField ────────────────────────────────────────────────────────────────\n\n/**\n * react-hook-form's `Controller`, with the field's name put in context for the parts\n * below it. Takes exactly `Controller`'s props.\n */\nexport function FormField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformedValues = TFieldValues,\n>(props: ControllerProps<TFieldValues, TName, TTransformedValues>) {\n const value = useMemo(() => ({ name: props.name as string }), [props.name]);\n return (\n <FormFieldContext.Provider value={value}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n );\n}\n\n// ── useFormField ─────────────────────────────────────────────────────────────\n\n/**\n * The ids and the state of the field around the caller: for a part of your own that\n * sits beside the kit's (a character counter that belongs in `aria-describedby`, a\n * label with a different look).\n *\n * Throws outside a `FormField` + `FormItem` pair. shadcn's version answered there with\n * ids like `undefined-form-item`, which label nothing and fail nowhere.\n */\nexport function useFormField() {\n const field = useContext(FormFieldContext);\n const item = useContext(FormItemContext);\n if (!field) throw new Error(\"useFormField must be used inside <FormField>.\");\n if (!item) throw new Error(\"useFormField must be used inside <FormItem>.\");\n const { getFieldState } = useFormContext();\n // Subscribes this part to the field's state, so a label or message re-renders when\n // the field's error changes without the whole form doing so.\n const formState = useFormState({ name: field.name });\n const state = getFieldState(field.name, formState);\n const formDescriptionId = `${item.id}-description`;\n const formMessageId = `${item.id}-message`;\n const describedBy = [\n item.mounted.description && formDescriptionId,\n item.mounted.message && formMessageId,\n ]\n .filter(Boolean)\n .join(\" \");\n return {\n id: item.id,\n name: field.name,\n formItemId: `${item.id}-control`,\n formDescriptionId,\n formMessageId,\n /** The ids of the description and message that are actually rendered, or\n * `undefined` when neither is. */\n describedBy: describedBy || undefined,\n ...state,\n };\n}\n\n// ── FormItem ─────────────────────────────────────────────────────────────────\n\nexport type FormItemProps = ComponentProps<\"div\">;\n\n/** One field's box: mints the id its label, control, description and message share. */\nexport function FormItem({ className, ...rest }: FormItemProps) {\n const id = useId();\n const [mounted, setMounted] = useState<Record<Described, boolean>>({\n description: false,\n message: false,\n });\n const mark = useCallback(\n (slot: Described, on: boolean) =>\n setMounted((prev) => (prev[slot] === on ? prev : { ...prev, [slot]: on })),\n [],\n );\n const value = useMemo(() => ({ id, mounted, mark }), [id, mounted, mark]);\n return (\n <FormItemContext.Provider value={value}>\n {/* `content-start`: stretched to a taller neighbour's height in a grid row, the\n item gave the extra to its rows and its control sat lower (showcase audit). */}\n <div data-slot=\"form-item\" {...rest} className={cn(\"grid content-start gap-1\", className)} />\n </FormItemContext.Provider>\n );\n}\n\n/** Report a describing node's presence to the item, so the control points at it only\n * while it is on screen. A layout effect, so the reference lands before paint. */\nfunction useDescribes(slot: Described, on: boolean) {\n const item = useContext(FormItemContext);\n const mark = item?.mark;\n useLayoutEffect(() => {\n if (!on || !mark) return;\n mark(slot, true);\n return () => mark(slot, false);\n }, [slot, on, mark]);\n}\n\n// ── FormLabel ────────────────────────────────────────────────────────────────\n\nexport type FormLabelProps = LabelProps;\n\n/**\n * The kit's {@link Label}, bound to the control by `htmlFor` and turned to the danger\n * colour while the field is invalid. `required` draws the kit's `aria-hidden` mark:\n * whether the field is required is the control's to announce.\n */\nexport function FormLabel({ className, ...rest }: FormLabelProps) {\n const { error, formItemId } = useFormField();\n return (\n <Label\n data-slot=\"form-label\"\n data-error={error ? true : undefined}\n htmlFor={formItemId}\n {...rest}\n className={cn(\"data-[error=true]:text-danger\", className)}\n />\n );\n}\n\n// ── FormControl ──────────────────────────────────────────────────────────────\n\nexport interface FormControlProps {\n /** Exactly one element: the kit field, or a native one. It receives `id`,\n * `aria-describedby` and `aria-invalid`. */\n children: ReactElement;\n}\n\ntype AriaProps = {\n id?: string;\n \"aria-describedby\"?: string;\n \"aria-invalid\"?: ComponentProps<\"input\">[\"aria-invalid\"];\n};\n\n/**\n * Wires its one child to the item: the `id` the label points at, `aria-describedby`\n * naming the rendered description and message, and `aria-invalid` while the field has\n * an error.\n *\n * The child's own values win where it has them (an explicit `id`, a set\n * `aria-invalid`), as they did under Radix `Slot`; its own `aria-describedby` is\n * merged in front of the item's rather than replaced.\n */\nexport function FormControl({ children }: FormControlProps) {\n const { invalid, formItemId, describedBy } = useFormField();\n const child = Children.only(children);\n if (!isValidElement<AriaProps>(child)) return child;\n const own = child.props;\n const merged = [own[\"aria-describedby\"], describedBy].filter(Boolean).join(\" \");\n return cloneElement(child, {\n id: own.id ?? formItemId,\n \"aria-describedby\": merged || undefined,\n \"aria-invalid\": own[\"aria-invalid\"] ?? (invalid || undefined),\n });\n}\n\n// ── FormDescription / FormMessage ────────────────────────────────────────────\n\nexport type FormDescriptionProps = ComponentProps<\"p\">;\n\n/** Standing advice under the field (\"at least twelve characters\"). */\nexport function FormDescription({ className, ...rest }: FormDescriptionProps) {\n const { formDescriptionId } = useFormField();\n useDescribes(\"description\", true);\n return (\n <p\n data-slot=\"form-description\"\n {...rest}\n id={formDescriptionId}\n className={cn(\"text-caption leading-tight text-muted\", className)}\n />\n );\n}\n\nexport type FormMessageProps = ComponentProps<\"p\">;\n\n/**\n * The field's error message, from the form — the kit renders no string of its own\n * here; the schema or the `rules` carry the words. Without an error it renders its\n * `children`, if any, and otherwise nothing.\n *\n * Deliberately NOT `role=\"alert\"`, for the reason the kit's `error` prop gives: the\n * message is read when focus reaches the control, which is where a field's own error\n * is wanted, and an alert would interrupt on every keystroke of a form that\n * re-validates as you type.\n */\nexport function FormMessage({ className, children, ...rest }: FormMessageProps) {\n const { error, formMessageId } = useFormField();\n const body = error ? String(error.message ?? \"\") : children;\n const shown = body !== undefined && body !== null && body !== false && body !== \"\";\n useDescribes(\"message\", shown);\n if (!shown) return null;\n return (\n <p\n data-slot=\"form-message\"\n {...rest}\n id={formMessageId}\n className={cn(\"text-caption leading-tight text-danger\", className)}\n >\n {body}\n </p>\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/rhf/form.d.ts
CHANGED
|
@@ -1,41 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `Form
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* `Form` — the public face of ./form-core, where the shadcn scaffold the bound fields are
|
|
3
|
+
* built from lives (its header has the whole story: what differs from shadcn's file, why
|
|
4
|
+
* /rhf is its own entry, how a picker clears).
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* The scaffold itself (`FormField`, `useFormField`, `FormItem`, `FormLabel`, `FormControl`,
|
|
7
|
+
* `FormDescription`, `FormMessage` and five props types) was public until 0.35 (refactor
|
|
8
|
+
* audit 2026-10, API-6f; deprecated in 0.34): no app builds a form from it any more.
|
|
7
9
|
* kastlan, the one /rhf consumer, uses `Form`, the bound `Rhf*` fields and `RhfField` for
|
|
8
|
-
* a control of its own
|
|
9
|
-
* surface in 0.35. The bound fields import the parts from the core, so the removal is
|
|
10
|
-
* the block below.
|
|
10
|
+
* a control of its own — the same parts, folded into one element.
|
|
11
11
|
*/
|
|
12
|
-
import * as core from "./form-core.js";
|
|
13
12
|
export { Form } from "./form-core.js";
|
|
14
|
-
/** @deprecated 0.34 — the bound `Rhf*` fields, or `RhfField` for a control of your own;
|
|
15
|
-
* removed in 0.35 (API-6f). */
|
|
16
|
-
export declare const FormField: typeof core.FormField;
|
|
17
|
-
/** @deprecated 0.34 — `RhfField`, which reads the field's ids itself; removed in 0.35
|
|
18
|
-
* (API-6f). */
|
|
19
|
-
export declare const useFormField: typeof core.useFormField;
|
|
20
|
-
/** @deprecated 0.34 — the bound `Rhf*` fields, or `RhfField`; removed in 0.35 (API-6f). */
|
|
21
|
-
export declare const FormItem: typeof core.FormItem;
|
|
22
|
-
/** @deprecated 0.34 — the bound fields' and `RhfField`'s `label`; removed in 0.35 (API-6f). */
|
|
23
|
-
export declare const FormLabel: typeof core.FormLabel;
|
|
24
|
-
/** @deprecated 0.34 — `RhfField`, which wires its control the same way; removed in 0.35
|
|
25
|
-
* (API-6f). */
|
|
26
|
-
export declare const FormControl: typeof core.FormControl;
|
|
27
|
-
/** @deprecated 0.34 — the bound fields' and `RhfField`'s `hint`; removed in 0.35 (API-6f). */
|
|
28
|
-
export declare const FormDescription: typeof core.FormDescription;
|
|
29
|
-
/** @deprecated 0.34 — the bound fields and `RhfField`, which show the error themselves;
|
|
30
|
-
* removed in 0.35 (API-6f). */
|
|
31
|
-
export declare const FormMessage: typeof core.FormMessage;
|
|
32
|
-
/** @deprecated 0.34 — goes with `FormItem`; removed in 0.35 (API-6f). */
|
|
33
|
-
export type FormItemProps = core.FormItemProps;
|
|
34
|
-
/** @deprecated 0.34 — goes with `FormLabel`; removed in 0.35 (API-6f). */
|
|
35
|
-
export type FormLabelProps = core.FormLabelProps;
|
|
36
|
-
/** @deprecated 0.34 — goes with `FormControl`; removed in 0.35 (API-6f). */
|
|
37
|
-
export type FormControlProps = core.FormControlProps;
|
|
38
|
-
/** @deprecated 0.34 — goes with `FormDescription`; removed in 0.35 (API-6f). */
|
|
39
|
-
export type FormDescriptionProps = core.FormDescriptionProps;
|
|
40
|
-
/** @deprecated 0.34 — goes with `FormMessage`; removed in 0.35 (API-6f). */
|
|
41
|
-
export type FormMessageProps = core.FormMessageProps;
|
package/dist/rhf/form.js
CHANGED
|
@@ -1,21 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import * as core from "./form-core.js";
|
|
3
2
|
import { Form } from "./form-core.js";
|
|
4
|
-
const FormField = core.FormField;
|
|
5
|
-
const useFormField = core.useFormField;
|
|
6
|
-
const FormItem = core.FormItem;
|
|
7
|
-
const FormLabel = core.FormLabel;
|
|
8
|
-
const FormControl = core.FormControl;
|
|
9
|
-
const FormDescription = core.FormDescription;
|
|
10
|
-
const FormMessage = core.FormMessage;
|
|
11
3
|
export {
|
|
12
|
-
Form
|
|
13
|
-
FormControl,
|
|
14
|
-
FormDescription,
|
|
15
|
-
FormField,
|
|
16
|
-
FormItem,
|
|
17
|
-
FormLabel,
|
|
18
|
-
FormMessage,
|
|
19
|
-
useFormField
|
|
4
|
+
Form
|
|
20
5
|
};
|
|
21
6
|
//# sourceMappingURL=form.js.map
|
package/dist/rhf/form.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/rhf/form.tsx"],"sourcesContent":["/**\n * `Form
|
|
1
|
+
{"version":3,"sources":["../../src/rhf/form.tsx"],"sourcesContent":["/**\n * `Form` — the public face of ./form-core, where the shadcn scaffold the bound fields are\n * built from lives (its header has the whole story: what differs from shadcn's file, why\n * /rhf is its own entry, how a picker clears).\n *\n * The scaffold itself (`FormField`, `useFormField`, `FormItem`, `FormLabel`, `FormControl`,\n * `FormDescription`, `FormMessage` and five props types) was public until 0.35 (refactor\n * audit 2026-10, API-6f; deprecated in 0.34): no app builds a form from it any more.\n * kastlan, the one /rhf consumer, uses `Form`, the bound `Rhf*` fields and `RhfField` for\n * a control of its own — the same parts, folded into one element.\n */\nexport { Form } from \"./form-core\";\n"],"mappings":";AAWA,SAAS,YAAY;","names":[]}
|
package/dist/rhf/line-items.d.ts
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* `summary`, `fieldLabels`, `narrowColumns`, `removePlacement` and `removeAlign` pass
|
|
28
28
|
* through to {@link LineItems}. With
|
|
29
29
|
* `fieldLabels="floating"` a cell's `fieldLabel` is the column's name; the bound
|
|
30
|
-
* fields' own `label` is a
|
|
30
|
+
* fields' own `label` is a label ABOVE the control, so for the floating
|
|
31
31
|
* one render the kit field through `RhfField`:
|
|
32
32
|
* `render={({ field, invalid }) => <Input label={fieldLabel} aria-label={label} {...field} invalid={invalid} />}`.
|
|
33
33
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/rhf/line-items.tsx"],"sourcesContent":["/**\n * {@link LineItems} over react-hook-form's `useFieldArray`. `@eifi1/ui-kit/rhf`.\n *\n * ```tsx\n * <RhfLineItems\n * name=\"components\"\n * newItem={() => ({ type: \"net_rent\", amount: null, validFrom: \"\" })}\n * minItems={1}\n * columns={[\n * { key: \"type\", header: \"Type\", render: ({ name, label }) => (\n * <RhfSelect name={`${name}.type`} options={TYPES} aria-label={label} />\n * ) },\n * { key: \"amount\", header: \"Amount\", width: \"8rem\", align: \"end\", render: ({ name, label }) => (\n * <RhfMoneyField name={`${name}.amount`} aria-label={label} />\n * ) },\n * ]}\n * totals={{ amount: formatMoney(total) }}\n * />\n * ```\n *\n * The rows are the array's `fields` (keyed by their `id`, as react-hook-form asks),\n * Add appends `newItem()`, remove is `remove(index)`, and an error on the array\n * itself — the `rules` here, or a resolver's `lines: \"At least two lines\"` — is the\n * list's `error`. Each cell's `render` gets `name`, the row's path\n * (`\"components.2\"`), to bind its field to.\n *\n * `summary`, `fieldLabels`, `narrowColumns`, `removePlacement` and `removeAlign` pass\n * through to {@link LineItems}. With\n * `fieldLabels=\"floating\"` a cell's `fieldLabel` is the column's name; the bound\n * fields' own `label` is a
|
|
1
|
+
{"version":3,"sources":["../../src/rhf/line-items.tsx"],"sourcesContent":["/**\n * {@link LineItems} over react-hook-form's `useFieldArray`. `@eifi1/ui-kit/rhf`.\n *\n * ```tsx\n * <RhfLineItems\n * name=\"components\"\n * newItem={() => ({ type: \"net_rent\", amount: null, validFrom: \"\" })}\n * minItems={1}\n * columns={[\n * { key: \"type\", header: \"Type\", render: ({ name, label }) => (\n * <RhfSelect name={`${name}.type`} options={TYPES} aria-label={label} />\n * ) },\n * { key: \"amount\", header: \"Amount\", width: \"8rem\", align: \"end\", render: ({ name, label }) => (\n * <RhfMoneyField name={`${name}.amount`} aria-label={label} />\n * ) },\n * ]}\n * totals={{ amount: formatMoney(total) }}\n * />\n * ```\n *\n * The rows are the array's `fields` (keyed by their `id`, as react-hook-form asks),\n * Add appends `newItem()`, remove is `remove(index)`, and an error on the array\n * itself — the `rules` here, or a resolver's `lines: \"At least two lines\"` — is the\n * list's `error`. Each cell's `render` gets `name`, the row's path\n * (`\"components.2\"`), to bind its field to.\n *\n * `summary`, `fieldLabels`, `narrowColumns`, `removePlacement` and `removeAlign` pass\n * through to {@link LineItems}. With\n * `fieldLabels=\"floating\"` a cell's `fieldLabel` is the column's name; the bound\n * fields' own `label` is a label ABOVE the control, so for the floating\n * one render the kit field through `RhfField`:\n * `render={({ field, invalid }) => <Input label={fieldLabel} aria-label={label} {...field} invalid={invalid} />}`.\n */\nimport type { ReactNode } from \"react\";\nimport {\n useFieldArray,\n useFormState,\n type FieldArray,\n type FieldArrayPath,\n type FieldArrayWithId,\n type FieldValues,\n type UseFieldArrayProps,\n} from \"react-hook-form\";\nimport {\n LineItems,\n type LineItemCellContext,\n type LineItemsColumn,\n type LineItemsProps,\n} from \"../components/line-items\";\n\n/** A cell's context, with the row's path in the form. */\nexport interface RhfLineItemCellContext<TItem, TArrayName extends string>\n extends LineItemCellContext<TItem> {\n /** The row's path: `${name}.${index}` — bind the cell's field to\n * `` `${name}.amount` ``. */\n name: `${TArrayName}.${number}`;\n}\n\nexport interface RhfLineItemsColumn<TItem, TArrayName extends string>\n extends Omit<LineItemsColumn<TItem>, \"render\"> {\n render: (ctx: RhfLineItemCellContext<TItem, TArrayName>) => ReactNode;\n}\n\nexport interface RhfLineItemsProps<\n TFieldValues extends FieldValues = FieldValues,\n TArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,\n TTransformed = TFieldValues,\n> extends Omit<\n LineItemsProps<FieldArrayWithId<TFieldValues, TArrayName, \"id\">>,\n \"items\" | \"columns\" | \"onAdd\" | \"onRemove\" | \"getKey\"\n > {\n name: TArrayName;\n /** `form.control`. Optional under `<Form {...form}>`. */\n control?: UseFieldArrayProps<TFieldValues, TArrayName, \"id\", TTransformed>[\"control\"];\n /** `useFieldArray`'s `rules` (`minLength`, `validate` …); its message is the list's\n * error. */\n rules?: UseFieldArrayProps<TFieldValues, TArrayName, \"id\", TTransformed>[\"rules\"];\n columns: readonly RhfLineItemsColumn<FieldArrayWithId<TFieldValues, TArrayName, \"id\">, TArrayName>[];\n /** A new row's values. Omitted: no add button. */\n newItem?: () => FieldArray<TFieldValues, TArrayName>;\n /** `false`: no remove buttons. Default `true`. */\n removable?: boolean;\n}\n\n/** The message of an error at `path` in react-hook-form's errors tree: the array's\n * own (`root`, from `rules`) or one a resolver put on the array. */\nfunction arrayError(errors: unknown, path: string): string | undefined {\n let node: unknown = errors;\n for (const key of path.split(\".\")) {\n if (node === null || typeof node !== \"object\") return undefined;\n node = (node as Record<string, unknown>)[key];\n }\n if (node === null || typeof node !== \"object\") return undefined;\n const { root, message } = node as { root?: { message?: unknown }; message?: unknown };\n const text = root?.message ?? message;\n return typeof text === \"string\" && text !== \"\" ? text : undefined;\n}\n\n/** {@link LineItems} bound to a field array. See the module note. */\nexport function RhfLineItems<\n TFieldValues extends FieldValues = FieldValues,\n TArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>,\n TTransformed = TFieldValues,\n>({\n name,\n control,\n rules,\n columns,\n newItem,\n removable = true,\n error,\n ...rest\n}: RhfLineItemsProps<TFieldValues, TArrayName, TTransformed>) {\n const { fields, append, remove } = useFieldArray<TFieldValues, TArrayName, \"id\", TTransformed>({\n control,\n name,\n rules,\n });\n const { errors } = useFormState({ control, name: name as never });\n const bound: LineItemsColumn<FieldArrayWithId<TFieldValues, TArrayName, \"id\">>[] = columns.map(\n ({ render, ...column }) => ({\n ...column,\n render: (ctx) => render({ ...ctx, name: `${name}.${ctx.index}` as `${TArrayName}.${number}` }),\n }),\n );\n return (\n <LineItems\n {...rest}\n items={fields}\n columns={bound}\n getKey={(field) => field.id}\n onAdd={newItem ? () => append(newItem()) : undefined}\n onRemove={removable ? (index) => remove(index) : undefined}\n error={error ?? arrayError(errors, name)}\n />\n );\n}\n"],"mappings":";AA8HI;AA5FJ;AAAA,EACE;AAAA,EACA;AAAA,OAMK;AACP;AAAA,EACE;AAAA,OAIK;AAsCP,SAAS,WAAW,QAAiB,MAAkC;AACrE,MAAI,OAAgB;AACpB,aAAW,OAAO,KAAK,MAAM,GAAG,GAAG;AACjC,QAAI,SAAS,QAAQ,OAAO,SAAS,SAAU,QAAO;AACtD,WAAQ,KAAiC,GAAG;AAAA,EAC9C;AACA,MAAI,SAAS,QAAQ,OAAO,SAAS,SAAU,QAAO;AACtD,QAAM,EAAE,MAAM,QAAQ,IAAI;AAC1B,QAAM,OAAO,MAAM,WAAW;AAC9B,SAAO,OAAO,SAAS,YAAY,SAAS,KAAK,OAAO;AAC1D;AAGO,SAAS,aAId;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA,GAAG;AACL,GAA8D;AAC5D,QAAM,EAAE,QAAQ,QAAQ,OAAO,IAAI,cAA4D;AAAA,IAC7F;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,QAAM,EAAE,OAAO,IAAI,aAAa,EAAE,SAAS,KAAoB,CAAC;AAChE,QAAM,QAA6E,QAAQ;AAAA,IACzF,CAAC,EAAE,QAAQ,GAAG,OAAO,OAAO;AAAA,MAC1B,GAAG;AAAA,MACH,QAAQ,CAAC,QAAQ,OAAO,EAAE,GAAG,KAAK,MAAM,GAAG,IAAI,IAAI,IAAI,KAAK,GAAgC,CAAC;AAAA,IAC/F;AAAA,EACF;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,OAAO;AAAA,MACP,SAAS;AAAA,MACT,QAAQ,CAAC,UAAU,MAAM;AAAA,MACzB,OAAO,UAAU,MAAM,OAAO,QAAQ,CAAC,IAAI;AAAA,MAC3C,UAAU,YAAY,CAAC,UAAU,OAAO,KAAK,IAAI;AAAA,MACjD,OAAO,SAAS,WAAW,QAAQ,IAAI;AAAA;AAAA,EACzC;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/rhf/use-rhf-wizard-step.ts"],"sourcesContent":["/**\n * The bridge between a react-hook-form step and the wizard's Next gate.\n * `@eifi1/ui-kit/rhf`.\n *\n * ```tsx\n * function AddressStep({ onUpdate }: { onUpdate: (v: Address) => void }) {\n * const form = useForm<Address>({ defaultValues });\n * useRhfWizardStep(form, { onValid: onUpdate });\n * return <Form {...form}>…</Form>;\n * }\n * ```\n *\n * Inside a `<StepperNav>` the hook registers the step's validator with the wizard, so\n * Next (and Finish on a form-bearing last step) runs it: on success the values go to\n * `onValid` and the wizard advances; on failure
|
|
1
|
+
{"version":3,"sources":["../../src/rhf/use-rhf-wizard-step.ts"],"sourcesContent":["/**\n * The bridge between a react-hook-form step and the wizard's Next gate.\n * `@eifi1/ui-kit/rhf`.\n *\n * ```tsx\n * function AddressStep({ onUpdate }: { onUpdate: (v: Address) => void }) {\n * const form = useForm<Address>({ defaultValues });\n * useRhfWizardStep(form, { onValid: onUpdate });\n * return <Form {...form}>…</Form>;\n * }\n * ```\n *\n * Inside a `<StepperNav>` the hook registers the step's validator with the wizard, so\n * Next (and Finish on a form-bearing last step) runs it: on success the values go to\n * `onValid` and the wizard advances; on failure the bound fields show their inline\n * messages, react-hook-form focuses the first field in error, and the wizard stays\n * put — and, since the result carries no per-field errors, says its \"fill in the\n * required fields\" line so the button did not seem to do nothing. It also RETURNS the\n * validator, for a nav of your own outside `<StepperNav>` (where there is no wizard\n * context to register with, so nothing is registered).\n *\n * Two modes:\n *\n * - **The whole form** (no `fields`): `form.handleSubmit`, exactly as kastlan's\n * `use-rhf-wizard-step.ts` — every rule and the resolver run, `onValid` receives\n * the TRANSFORMED values (a zod `.transform()` included), and focus follows the\n * form's own `shouldFocusError` (on by default).\n * - **Some fields** (`fields: [\"iban\", \"bic\"]`): `form.trigger(fields)`, for a wizard\n * that keeps one form across several steps, each of which validates only what it\n * shows. The first of those fields in error is focused (`shouldFocus`; the control\n * has to take `field.ref`), errors on fields of later steps are not raised, and\n * `onValid` receives `form.getValues()` — the untransformed values, because a\n * resolver's output is only produced for the whole form.\n *\n * Both callbacks are read through refs, so the validator is registered once per form\n * however the caller writes them (an inline `(v) => onUpdate(v)` is the usual case).\n *\n * The positional `useRhfWizardStep(form, onValid)` of the hook kastlan kept is the\n * whole-form mode, and still accepted.\n *\n * Why it lives here and not in `@eifi1/ui-kit/wizard`: it imports react-hook-form,\n * which only this entry may (see packaging-contract).\n */\nimport { useCallback, useEffect, useRef } from \"react\";\nimport type { FieldPath, FieldValues, UseFormReturn } from \"react-hook-form\";\nimport { useOptionalWizardContext } from \"../wizard/wizard-context\";\n\nexport type RhfWizardStepOptions<\n TFieldValues extends FieldValues,\n TTransformed = TFieldValues,\n> =\n | {\n /** Validate only these fields — the step's share of a form that spans steps. */\n fields: readonly FieldPath<TFieldValues>[];\n /** Called with `form.getValues()` when the fields pass, before the wizard\n * advances. */\n onValid?: (values: TFieldValues) => void;\n }\n | {\n /** Omitted: validate the whole form through `handleSubmit`. */\n fields?: undefined;\n /** Called with the form's (transformed) values when it passes, before the\n * wizard advances. */\n onValid?: (values: TTransformed) => void;\n };\n\n/**\n * Connects `form` to the wizard's step validation and returns the step's validator.\n * See the module note for the two modes.\n */\nexport function useRhfWizardStep<\n TFieldValues extends FieldValues,\n TContext = unknown,\n TTransformed = TFieldValues,\n>(\n form: UseFormReturn<TFieldValues, TContext, TTransformed>,\n options?:\n | RhfWizardStepOptions<TFieldValues, TTransformed>\n | ((values: TTransformed) => void),\n): () => Promise<boolean> {\n const opts = typeof options === \"function\" ? { onValid: options } : (options ?? {});\n const optsRef = useRef(opts);\n useEffect(() => {\n optsRef.current = opts;\n });\n\n const validate = useCallback(async (): Promise<boolean> => {\n const current = optsRef.current;\n if (current.fields) {\n const ok = await form.trigger([...current.fields], { shouldFocus: true });\n if (ok) current.onValid?.(form.getValues());\n return ok;\n }\n const onValid = current.onValid as ((values: TTransformed) => void) | undefined;\n let ok = false;\n await form.handleSubmit(\n (values) => {\n ok = true;\n onValid?.(values);\n },\n () => {\n ok = false;\n },\n )();\n return ok;\n }, [form]);\n\n const wizard = useOptionalWizardContext();\n const register = wizard?.registerStepValidate;\n useEffect(() => register?.(validate), [register, validate]);\n\n return validate;\n}\n"],"mappings":";AA2CA,SAAS,aAAa,WAAW,cAAc;AAE/C,SAAS,gCAAgC;AAyBlC,SAAS,iBAKd,MACA,SAGwB;AACxB,QAAM,OAAO,OAAO,YAAY,aAAa,EAAE,SAAS,QAAQ,IAAK,WAAW,CAAC;AACjF,QAAM,UAAU,OAAO,IAAI;AAC3B,YAAU,MAAM;AACd,YAAQ,UAAU;AAAA,EACpB,CAAC;AAED,QAAM,WAAW,YAAY,YAA8B;AACzD,UAAM,UAAU,QAAQ;AACxB,QAAI,QAAQ,QAAQ;AAClB,YAAMA,MAAK,MAAM,KAAK,QAAQ,CAAC,GAAG,QAAQ,MAAM,GAAG,EAAE,aAAa,KAAK,CAAC;AACxE,UAAIA,IAAI,SAAQ,UAAU,KAAK,UAAU,CAAC;AAC1C,aAAOA;AAAA,IACT;AACA,UAAM,UAAU,QAAQ;AACxB,QAAI,KAAK;AACT,UAAM,KAAK;AAAA,MACT,CAAC,WAAW;AACV,aAAK;AACL,kBAAU,MAAM;AAAA,MAClB;AAAA,MACA,MAAM;AACJ,aAAK;AAAA,MACP;AAAA,IACF,EAAE;AACF,WAAO;AAAA,EACT,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,SAAS,yBAAyB;AACxC,QAAM,WAAW,QAAQ;AACzB,YAAU,MAAM,WAAW,QAAQ,GAAG,CAAC,UAAU,QAAQ,CAAC;AAE1D,SAAO;AACT;","names":["ok"]}
|
package/dist/rhf.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/rhf.ts"],"sourcesContent":["// `@eifi1/ui-kit/rhf` — the react-hook-form adapter: Form and the bound Rhf* fields (and\n// RhfField as the escape hatch). The shadcn scaffold (FormField
|
|
1
|
+
{"version":3,"sources":["../src/rhf.ts"],"sourcesContent":["// `@eifi1/ui-kit/rhf` — the react-hook-form adapter: Form and the bound Rhf* fields (and\n// RhfField as the escape hatch). The shadcn scaffold they are built from (FormField,\n// FormItem, FormLabel, FormControl, FormDescription, FormMessage, useFormField) left the\n// surface in 0.35 (refactor audit 2026-10, API-6f; deprecated in 0.34).\n//\n// The only entry point in the package that requires `react-hook-form`, and an optional\n// peer for that reason: an app without a form library installs nothing for it. NOT\n// re-exported from the main barrel, which would make the peer everyone's — the reason\n// the barrel dropped its last react-hook-form import (see the wizard section of\n// src/index.ts). The packaging contract test holds that line.\nexport * from \"./rhf/form\";\n// The react-hook-form bridge to the wizard's Next gate (useWizard lives in /wizard).\nexport * from \"./rhf/use-rhf-wizard-step\";\n// Bound fields — one line per field (RhfTextField, RhfNumberField, RhfIntegerField, RhfMoneyField,\n// RhfDateField, RhfTextarea, RhfSelect, RhfCheckbox, RhfCombobox, RhfTextCombobox; 0.22: RhfTimeInput,\n// RhfDateRangePicker, RhfToggleGroup, RhfIbanInput, RhfPhoneInput; 0.23: RhfCountrySelect,\n// RhfMonthPicker; 0.24: RhfInlineEntityCombobox)\n// and RhfField, the shell they are built on.\nexport * from \"./rhf/fields\";\n// LineItems over useFieldArray.\nexport * from \"./rhf/line-items\";\n"],"mappings":";AAUA,cAAc;AAEd,cAAc;AAMd,cAAc;AAEd,cAAc;","names":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
const DEFAULT_DEVICE_RESET_LABELS = {
|
|
3
|
+
title: "Reset this device",
|
|
4
|
+
description: "Puts this device's appearance, and the way its tables and panels were left, back to the defaults. Your account, your data and your sign-in are not touched.",
|
|
5
|
+
action: "Reset this device's settings",
|
|
6
|
+
confirmTitle: "Reset this device's settings?",
|
|
7
|
+
confirmBody: "Theme, colours, text size, contrast and language go back to their defaults here, and tables and panels open as they first did. Where your account has a language, a text size or a contrast, this device follows it again. Your account and your other devices stay as they are.",
|
|
8
|
+
confirmAction: "Reset",
|
|
9
|
+
done: "This device's settings are back to their defaults.",
|
|
10
|
+
keywords: "reset defaults device restore appearance tables layout"
|
|
11
|
+
};
|
|
12
|
+
export {
|
|
13
|
+
DEFAULT_DEVICE_RESET_LABELS
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=device-reset-setting-labels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/settings/device-reset-setting-labels.ts"],"sourcesContent":["// The English words of ./device-reset-setting, in a module with no component code: the\n// English catalogue (src/i18n/defaults.ts) imports them without the component, so `en`\n// loads as one chunk like the other languages (0.34, KS U8). ./device-reset-setting\n// re-exports them.\n\nimport type { DeviceResetLabels } from \"./device-reset-setting\";\n\n/** docs/settings-harmonization.md §11.3, word for word. */\nexport const DEFAULT_DEVICE_RESET_LABELS: DeviceResetLabels = {\n title: \"Reset this device\",\n description:\n \"Puts this device's appearance, and the way its tables and panels were left, back to the defaults. Your account, your data and your sign-in are not touched.\",\n action: \"Reset this device's settings\",\n confirmTitle: \"Reset this device's settings?\",\n confirmBody:\n \"Theme, colours, text size, contrast and language go back to their defaults here, and tables and panels open as they first did. Where your account has a language, a text size or a contrast, this device follows it again. Your account and your other devices stay as they are.\",\n confirmAction: \"Reset\",\n done: \"This device's settings are back to their defaults.\",\n keywords: \"reset defaults device restore appearance tables layout\",\n};\n"],"mappings":";AAQO,MAAM,8BAAiD;AAAA,EAC5D,OAAO;AAAA,EACP,aACE;AAAA,EACF,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,aACE;AAAA,EACF,eAAe;AAAA,EACf,MAAM;AAAA,EACN,UAAU;AACZ;","names":[]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { type LabelOverride } from "../i18n/kit-labels.js";
|
|
3
|
+
import { type SettingsSectionProps } from "./settings-section.js";
|
|
4
|
+
import { DEFAULT_DEVICE_RESET_LABELS } from "./device-reset-setting-labels.js";
|
|
5
|
+
/** Every string {@link DeviceResetSetting} renders — the `deviceReset` namespace of
|
|
6
|
+
* `<UiKitProvider labels>`, overridable per instance through `labels`
|
|
7
|
+
* (docs/settings-harmonization.md §11.3). The confirm's Cancel is `confirmDialog.cancel`. */
|
|
8
|
+
export interface DeviceResetLabels {
|
|
9
|
+
/** The card's title, and the app's catalogue entry's. */
|
|
10
|
+
title: string;
|
|
11
|
+
/** The line under it: what goes back, and that the account is not touched. */
|
|
12
|
+
description: string;
|
|
13
|
+
/** The button that asks first. */
|
|
14
|
+
action: string;
|
|
15
|
+
/** The question it asks. */
|
|
16
|
+
confirmTitle: string;
|
|
17
|
+
/** What goes, what follows the account again, and what stays. */
|
|
18
|
+
confirmBody: string;
|
|
19
|
+
/** The button that answers it. */
|
|
20
|
+
confirmAction: string;
|
|
21
|
+
/** The toast once it is done. */
|
|
22
|
+
done: string;
|
|
23
|
+
/** For the app's catalogue entry (`keywords`); the card never reads it. */
|
|
24
|
+
keywords: string;
|
|
25
|
+
}
|
|
26
|
+
export { DEFAULT_DEVICE_RESET_LABELS };
|
|
27
|
+
/** The card's DOM id: its catalogue entry's `anchor`, the `?focus=` target. */
|
|
28
|
+
export declare const DEVICE_RESET_ANCHOR = "settings-device-reset";
|
|
29
|
+
export interface DeviceResetSettingProps extends Omit<SettingsSectionProps, "anchor" | "title" | "description" | "children" | "onReset"> {
|
|
30
|
+
/** The app's sentence after the kit's description: what of its own goes back, and what
|
|
31
|
+
* stays (keksdose: the date format, the feature set and the gestures go; presentation
|
|
32
|
+
* mode and the home position stay). */
|
|
33
|
+
description?: ReactNode;
|
|
34
|
+
labels?: LabelOverride<DeviceResetLabels>;
|
|
35
|
+
/** Runs after the reset and before the toast, with the keys reset or removed. */
|
|
36
|
+
onReset?: (keys: string[]) => void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* "Reset this device's settings" (docs/settings-harmonization.md §11): the LAST card of
|
|
40
|
+
* the appearance group. It puts this device's appearance — theme, palette, language, text
|
|
41
|
+
* size, contrast and the app's own appearance choices — and its views — table views, the
|
|
42
|
+
* sidebar, folded groups, saved filters — back to what a new device gets, through
|
|
43
|
+
* {@link resetDeviceSettings}. The account, the sign-in, the session and anything waiting
|
|
44
|
+
* to be sent are never touched: they never join the registry.
|
|
45
|
+
*
|
|
46
|
+
* - **A confirm, not an undo** (§11.2 decision 9): `useConfirm` in the neutral tone,
|
|
47
|
+
* then a toast. An app mounts a `ConfirmProvider` and a `Toaster` already.
|
|
48
|
+
* - **Not a commit**: nothing is written to the account, so a demo or a lapsed plan's
|
|
49
|
+
* write lock does not disable it (decision 3).
|
|
50
|
+
* - **Live, no reload** (decision 10): each registered store resets through its own
|
|
51
|
+
* setter; the card stays where it is.
|
|
52
|
+
*
|
|
53
|
+
* The app adds the catalogue entry, `{ id: "device_reset", group: "appearance", anchor:
|
|
54
|
+
* DEVICE_RESET_ANCHOR, title, keywords }` (`title` and `keywords` from these labels), last
|
|
55
|
+
* in its appearance group: inside a `SettingsLayout`, `SettingsSection` throws in
|
|
56
|
+
* development without it.
|
|
57
|
+
*/
|
|
58
|
+
export declare function DeviceResetSetting({ description, labels: labelsProp, onReset, ...rest }: DeviceResetSettingProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useKitLabels } from "../i18n/kit-labels.js";
|
|
4
|
+
import { resetDeviceSettings } from "../lib/device-settings.js";
|
|
5
|
+
import { Button } from "../components/button.js";
|
|
6
|
+
import { useConfirm } from "../components/confirm-dialog.js";
|
|
7
|
+
import { toast } from "../components/toast.js";
|
|
8
|
+
import { SettingsSection } from "./settings-section.js";
|
|
9
|
+
import { DEFAULT_DEVICE_RESET_LABELS } from "./device-reset-setting-labels.js";
|
|
10
|
+
const DEVICE_RESET_ANCHOR = "settings-device-reset";
|
|
11
|
+
function DeviceResetSetting({
|
|
12
|
+
description,
|
|
13
|
+
labels: labelsProp,
|
|
14
|
+
onReset,
|
|
15
|
+
...rest
|
|
16
|
+
}) {
|
|
17
|
+
const labels = useKitLabels("deviceReset", DEFAULT_DEVICE_RESET_LABELS, labelsProp);
|
|
18
|
+
const confirm = useConfirm();
|
|
19
|
+
const reset = async () => {
|
|
20
|
+
const ok = await confirm({
|
|
21
|
+
title: labels.confirmTitle,
|
|
22
|
+
body: labels.confirmBody,
|
|
23
|
+
confirmLabel: labels.confirmAction,
|
|
24
|
+
tone: "neutral"
|
|
25
|
+
});
|
|
26
|
+
if (!ok) return;
|
|
27
|
+
const keys = resetDeviceSettings();
|
|
28
|
+
onReset?.(keys);
|
|
29
|
+
toast.success(labels.done);
|
|
30
|
+
};
|
|
31
|
+
return /* @__PURE__ */ jsx(
|
|
32
|
+
SettingsSection,
|
|
33
|
+
{
|
|
34
|
+
...rest,
|
|
35
|
+
anchor: DEVICE_RESET_ANCHOR,
|
|
36
|
+
title: labels.title,
|
|
37
|
+
description: description != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38
|
+
labels.description,
|
|
39
|
+
" ",
|
|
40
|
+
description
|
|
41
|
+
] }) : labels.description,
|
|
42
|
+
children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => void reset(), children: labels.action }) })
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
DEFAULT_DEVICE_RESET_LABELS,
|
|
48
|
+
DEVICE_RESET_ANCHOR,
|
|
49
|
+
DeviceResetSetting
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=device-reset-setting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/settings/device-reset-setting.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\n\nimport { useKitLabels, type LabelOverride } from \"../i18n/kit-labels\";\nimport { resetDeviceSettings } from \"../lib/device-settings\";\nimport { Button } from \"../components/button\";\nimport { useConfirm } from \"../components/confirm-dialog\";\nimport { toast } from \"../components/toast\";\nimport { SettingsSection, type SettingsSectionProps } from \"./settings-section\";\nimport { DEFAULT_DEVICE_RESET_LABELS } from \"./device-reset-setting-labels\";\n\n/* ── Labels ──────────────────────────────────────────────────────────────── */\n\n/** Every string {@link DeviceResetSetting} renders — the `deviceReset` namespace of\n * `<UiKitProvider labels>`, overridable per instance through `labels`\n * (docs/settings-harmonization.md §11.3). The confirm's Cancel is `confirmDialog.cancel`. */\nexport interface DeviceResetLabels {\n /** The card's title, and the app's catalogue entry's. */\n title: string;\n /** The line under it: what goes back, and that the account is not touched. */\n description: string;\n /** The button that asks first. */\n action: string;\n /** The question it asks. */\n confirmTitle: string;\n /** What goes, what follows the account again, and what stays. */\n confirmBody: string;\n /** The button that answers it. */\n confirmAction: string;\n /** The toast once it is done. */\n done: string;\n /** For the app's catalogue entry (`keywords`); the card never reads it. */\n keywords: string;\n}\n\n// Defined in ./device-reset-setting-labels, which holds no component code.\nexport { DEFAULT_DEVICE_RESET_LABELS };\n\n/* ── The card ────────────────────────────────────────────────────────────── */\n\n/** The card's DOM id: its catalogue entry's `anchor`, the `?focus=` target. */\nexport const DEVICE_RESET_ANCHOR = \"settings-device-reset\";\n\n// `onReset` is the card's own: the DOM's form-reset handler never fires on a div.\nexport interface DeviceResetSettingProps\n extends Omit<SettingsSectionProps, \"anchor\" | \"title\" | \"description\" | \"children\" | \"onReset\"> {\n /** The app's sentence after the kit's description: what of its own goes back, and what\n * stays (keksdose: the date format, the feature set and the gestures go; presentation\n * mode and the home position stay). */\n description?: ReactNode;\n labels?: LabelOverride<DeviceResetLabels>;\n /** Runs after the reset and before the toast, with the keys reset or removed. */\n onReset?: (keys: string[]) => void;\n}\n\n/**\n * \"Reset this device's settings\" (docs/settings-harmonization.md §11): the LAST card of\n * the appearance group. It puts this device's appearance — theme, palette, language, text\n * size, contrast and the app's own appearance choices — and its views — table views, the\n * sidebar, folded groups, saved filters — back to what a new device gets, through\n * {@link resetDeviceSettings}. The account, the sign-in, the session and anything waiting\n * to be sent are never touched: they never join the registry.\n *\n * - **A confirm, not an undo** (§11.2 decision 9): `useConfirm` in the neutral tone,\n * then a toast. An app mounts a `ConfirmProvider` and a `Toaster` already.\n * - **Not a commit**: nothing is written to the account, so a demo or a lapsed plan's\n * write lock does not disable it (decision 3).\n * - **Live, no reload** (decision 10): each registered store resets through its own\n * setter; the card stays where it is.\n *\n * The app adds the catalogue entry, `{ id: \"device_reset\", group: \"appearance\", anchor:\n * DEVICE_RESET_ANCHOR, title, keywords }` (`title` and `keywords` from these labels), last\n * in its appearance group: inside a `SettingsLayout`, `SettingsSection` throws in\n * development without it.\n */\nexport function DeviceResetSetting({\n description,\n labels: labelsProp,\n onReset,\n ...rest\n}: DeviceResetSettingProps) {\n const labels = useKitLabels(\"deviceReset\", DEFAULT_DEVICE_RESET_LABELS, labelsProp);\n const confirm = useConfirm();\n\n const reset = async () => {\n const ok = await confirm({\n title: labels.confirmTitle,\n body: labels.confirmBody,\n confirmLabel: labels.confirmAction,\n tone: \"neutral\",\n });\n if (!ok) return;\n const keys = resetDeviceSettings();\n onReset?.(keys);\n toast.success(labels.done);\n };\n\n return (\n <SettingsSection\n {...rest}\n anchor={DEVICE_RESET_ANCHOR}\n title={labels.title}\n description={\n description != null ? (\n <>\n {labels.description} {description}\n </>\n ) : (\n labels.description\n )\n }\n >\n <div>\n <Button variant=\"secondary\" onClick={() => void reset()}>\n {labels.action}\n </Button>\n </div>\n </SettingsSection>\n );\n}\n"],"mappings":";AAuGU,mBASF,KATE;AArGV,SAAS,oBAAwC;AACjD,SAAS,2BAA2B;AACpC,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,uBAAkD;AAC3D,SAAS,mCAAmC;AAgCrC,MAAM,sBAAsB;AAkC5B,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA,QAAQ;AAAA,EACR;AAAA,EACA,GAAG;AACL,GAA4B;AAC1B,QAAM,SAAS,aAAa,eAAe,6BAA6B,UAAU;AAClF,QAAM,UAAU,WAAW;AAE3B,QAAM,QAAQ,YAAY;AACxB,UAAM,KAAK,MAAM,QAAQ;AAAA,MACvB,OAAO,OAAO;AAAA,MACd,MAAM,OAAO;AAAA,MACb,cAAc,OAAO;AAAA,MACrB,MAAM;AAAA,IACR,CAAC;AACD,QAAI,CAAC,GAAI;AACT,UAAM,OAAO,oBAAoB;AACjC,cAAU,IAAI;AACd,UAAM,QAAQ,OAAO,IAAI;AAAA,EAC3B;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,QAAQ;AAAA,MACR,OAAO,OAAO;AAAA,MACd,aACE,eAAe,OACb,iCACG;AAAA,eAAO;AAAA,QAAY;AAAA,QAAE;AAAA,SACxB,IAEA,OAAO;AAAA,MAIX,8BAAC,SACC,8BAAC,UAAO,SAAQ,aAAY,SAAS,MAAM,KAAK,MAAM,GACnD,iBAAO,QACV,GACF;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
package/dist/shell/app-shell.js
CHANGED
|
@@ -8,6 +8,7 @@ import { cn } from "../lib/cn.js";
|
|
|
8
8
|
import { scrollIntoStrip, useStripFade } from "../lib/strip-fade.js";
|
|
9
9
|
import { dirOf } from "../lib/direction.js";
|
|
10
10
|
import { readStored, writeStored } from "../lib/safe-storage.js";
|
|
11
|
+
import { registerDeviceSetting } from "../lib/device-settings.js";
|
|
11
12
|
import { Tooltip } from "../components/tooltip.js";
|
|
12
13
|
import { pickLinkRenderer } from "../components/text-link.js";
|
|
13
14
|
import { DialogFrame } from "../components/dialog-frame.js";
|
|
@@ -101,6 +102,10 @@ function AppShell({
|
|
|
101
102
|
useEffect(() => {
|
|
102
103
|
if (collapseStorageKey !== null) writeStored(collapseStorageKey, collapsed ? "1" : "0");
|
|
103
104
|
}, [collapsed, collapseStorageKey]);
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (collapseStorageKey === null) return;
|
|
107
|
+
return registerDeviceSetting({ key: collapseStorageKey, kind: "view", reset: () => setCollapsed(false) });
|
|
108
|
+
}, [collapseStorageKey]);
|
|
104
109
|
const iconOnly = collapsed && !large;
|
|
105
110
|
return (
|
|
106
111
|
// The caller's attributes go on the shell's own root, never on the `data-tour="nav"`
|