@eifi1/ui-kit 0.11.0 → 0.12.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 +57 -32
- package/dist/chart.d.ts +3 -1
- package/dist/chart.js +2 -0
- package/dist/chart.js.map +1 -1
- package/dist/components/account-settings-labels.d.ts +105 -0
- package/dist/components/account-settings-labels.js +81 -0
- package/dist/components/account-settings-labels.js.map +1 -0
- package/dist/components/account-settings.d.ts +36 -52
- package/dist/components/account-settings.js +44 -8
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/amount-input.d.ts +24 -4
- package/dist/components/amount-input.js +5 -2
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/authed-image.d.ts +68 -0
- package/dist/components/authed-image.js +117 -0
- package/dist/components/authed-image.js.map +1 -0
- package/dist/components/breadcrumbs.d.ts +2 -1
- package/dist/components/breadcrumbs.js +5 -2
- package/dist/components/breadcrumbs.js.map +1 -1
- package/dist/components/button-group.d.ts +51 -2
- package/dist/components/button-group.js +5 -1
- package/dist/components/button-group.js.map +1 -1
- package/dist/components/calculator.d.ts +15 -4
- package/dist/components/calendar-heatmap.d.ts +41 -3
- package/dist/components/calendar-heatmap.js +48 -7
- package/dist/components/calendar-heatmap.js.map +1 -1
- package/dist/components/chip.d.ts +2 -1
- package/dist/components/chip.js +6 -3
- package/dist/components/chip.js.map +1 -1
- package/dist/components/choice-card.d.ts +35 -3
- package/dist/components/choice-card.js +83 -25
- package/dist/components/choice-card.js.map +1 -1
- package/dist/components/combobox-core.js +2 -0
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +2 -2
- package/dist/components/combobox.js +31 -9
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/copy-button.d.ts +51 -70
- package/dist/components/copy-button.js +1 -1
- package/dist/components/copy-button.js.map +1 -1
- package/dist/components/data-table-cells.d.ts +63 -0
- package/dist/components/data-table-cells.js +64 -0
- package/dist/components/data-table-cells.js.map +1 -0
- package/dist/components/data-table-filter-popover.d.ts +1 -1
- package/dist/components/data-table-filters.d.ts +1 -1
- package/dist/components/data-table-filters.js +31 -1
- package/dist/components/data-table-filters.js.map +1 -1
- package/dist/components/data-table-labels.d.ts +13 -0
- package/dist/components/data-table-labels.js +8 -1
- package/dist/components/data-table-labels.js.map +1 -1
- package/dist/components/data-table.d.ts +1 -1
- package/dist/components/data-table.js +102 -12
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +3 -1
- package/dist/components/date-picker.js +15 -2
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/description-list.d.ts +23 -3
- package/dist/components/description-list.js +23 -3
- package/dist/components/description-list.js.map +1 -1
- package/dist/components/dialog-frame.d.ts +1 -0
- package/dist/components/entity-combobox.d.ts +1 -1
- package/dist/components/entity-combobox.js +18 -3
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/error-boundary.d.ts +92 -0
- package/dist/components/error-boundary.js +111 -0
- package/dist/components/error-boundary.js.map +1 -0
- package/dist/components/field.d.ts +30 -4
- package/dist/components/field.js +40 -17
- package/dist/components/field.js.map +1 -1
- package/dist/components/file-button.d.ts +50 -208
- package/dist/components/file-dropzone.d.ts +49 -2
- package/dist/components/floating-panel.d.ts +13 -4
- package/dist/components/floating-panel.js +7 -3
- package/dist/components/floating-panel.js.map +1 -1
- package/dist/components/form-actions.d.ts +53 -0
- package/dist/components/form-actions.js +98 -0
- package/dist/components/form-actions.js.map +1 -0
- package/dist/components/image-grid.d.ts +67 -0
- package/dist/components/image-grid.js +112 -0
- package/dist/components/image-grid.js.map +1 -0
- package/dist/components/lightbox.d.ts +104 -0
- package/dist/components/lightbox.js +229 -0
- package/dist/components/lightbox.js.map +1 -0
- package/dist/components/line-items.d.ts +114 -0
- package/dist/components/line-items.js +238 -0
- package/dist/components/line-items.js.map +1 -0
- package/dist/components/list.d.ts +23 -2
- package/dist/components/list.js +32 -13
- package/dist/components/list.js.map +1 -1
- package/dist/components/loading-state.d.ts +24 -0
- package/dist/components/loading-state.js +32 -0
- package/dist/components/loading-state.js.map +1 -0
- package/dist/components/menu-item.d.ts +2 -1
- package/dist/components/menu-item.js +5 -1
- package/dist/components/menu-item.js.map +1 -1
- package/dist/components/mini-calendar.d.ts +13 -1
- package/dist/components/mini-calendar.js +46 -2
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/modal.d.ts +20 -1
- package/dist/components/modal.js +26 -2
- package/dist/components/modal.js.map +1 -1
- package/dist/components/month-picker.d.ts +21 -1
- package/dist/components/month-picker.js +139 -26
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.d.ts +1 -1
- package/dist/components/multi-entity-combobox.js +19 -3
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/nav-pills.d.ts +2 -1
- package/dist/components/nav-pills.js +5 -1
- package/dist/components/nav-pills.js.map +1 -1
- package/dist/components/number-field.d.ts +24 -5
- package/dist/components/number-field.js +5 -7
- package/dist/components/number-field.js.map +1 -1
- package/dist/components/number-input.d.ts +25 -5
- package/dist/components/number-input.js +7 -1
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +15 -4
- package/dist/components/passkeys-setting.d.ts +67 -0
- package/dist/components/passkeys-setting.js +214 -0
- package/dist/components/passkeys-setting.js.map +1 -0
- package/dist/components/picker-sheet.js +2 -1
- package/dist/components/picker-sheet.js.map +1 -1
- package/dist/components/pie-chart-labels.d.ts +20 -0
- package/dist/components/pie-chart-labels.js +12 -0
- package/dist/components/pie-chart-labels.js.map +1 -0
- package/dist/components/pie-chart.d.ts +101 -0
- package/dist/components/pie-chart.js +283 -0
- package/dist/components/pie-chart.js.map +1 -0
- package/dist/components/progress-bar.d.ts +44 -3
- package/dist/components/progress-bar.js +58 -22
- package/dist/components/progress-bar.js.map +1 -1
- package/dist/components/qr-code.d.ts +34 -0
- package/dist/components/qr-code.js +57 -0
- package/dist/components/qr-code.js.map +1 -0
- package/dist/components/search-field.d.ts +15 -3
- package/dist/components/search-field.js +5 -1
- package/dist/components/search-field.js.map +1 -1
- package/dist/components/settings-fields.d.ts +49 -1
- package/dist/components/signed-amount.d.ts +121 -0
- package/dist/components/signed-amount.js +152 -0
- package/dist/components/signed-amount.js.map +1 -0
- package/dist/components/skeleton.d.ts +10 -3
- package/dist/components/skeleton.js +12 -2
- package/dist/components/skeleton.js.map +1 -1
- package/dist/components/stat-tile.d.ts +2 -1
- package/dist/components/stat-tile.js +5 -2
- package/dist/components/stat-tile.js.map +1 -1
- package/dist/components/table.d.ts +39 -5
- package/dist/components/table.js +45 -11
- package/dist/components/table.js.map +1 -1
- package/dist/components/text-link.d.ts +176 -0
- package/dist/components/text-link.js +109 -0
- package/dist/components/text-link.js.map +1 -0
- package/dist/components/time-input.d.ts +49 -1
- package/dist/components/toggle-group.d.ts +13 -0
- package/dist/components/toggle-group.js +35 -6
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle-legend.d.ts +36 -3
- package/dist/components/toggle-legend.js +49 -0
- package/dist/components/toggle-legend.js.map +1 -1
- package/dist/components/ui.d.ts +51 -779
- package/dist/components/ui.js +215 -23
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-table-state.d.ts +3 -52
- package/dist/components/use-table-state.js +128 -30
- package/dist/components/use-table-state.js.map +1 -1
- package/dist/{data-table-filters-Dh9uF_S-.d.ts → data-table-Drun8Fk9.d.ts} +305 -61
- package/dist/data-table.d.ts +2 -1
- package/dist/data-table.js +5 -1
- package/dist/data-table.js.map +1 -1
- package/dist/feedback/feedback-dialog.d.ts +26 -3
- package/dist/feedback/feedback-dialog.js +16 -2
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-thread.d.ts +133 -0
- package/dist/feedback/feedback-thread.js +237 -0
- package/dist/feedback/feedback-thread.js.map +1 -0
- package/dist/feedback.d.ts +2 -1
- package/dist/feedback.js +1 -0
- package/dist/feedback.js.map +1 -1
- package/dist/hooks/use-authed-src.d.ts +71 -0
- package/dist/hooks/use-authed-src.js +63 -0
- package/dist/hooks/use-authed-src.js.map +1 -0
- package/dist/hooks/use-file-drop.d.ts +49 -2
- package/dist/hooks/use-hotkey.d.ts +59 -0
- package/dist/hooks/use-hotkey.js +105 -0
- package/dist/hooks/use-hotkey.js.map +1 -0
- package/dist/hooks/use-search-param-state.d.ts +83 -0
- package/dist/hooks/use-search-param-state.js +94 -0
- package/dist/hooks/use-search-param-state.js.map +1 -0
- package/dist/i18n/defaults.d.ts +15 -4
- package/dist/i18n/defaults.js +31 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +46 -312
- package/dist/i18n/kit-labels.js +20 -5
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/de-CH-informal.d.ts +15 -4
- package/dist/i18n/locales/de-CH.d.ts +15 -4
- package/dist/i18n/locales/de-informal.d.ts +15 -4
- package/dist/i18n/locales/de.d.ts +15 -4
- package/dist/i18n/locales/de.js +156 -3
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +15 -4
- package/dist/i18n/locales/es.js +153 -3
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +15 -4
- package/dist/i18n/locales/fr.js +153 -3
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +15 -4
- package/dist/i18n/locales/hu.js +153 -3
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +15 -4
- package/dist/i18n/locales/it.js +153 -3
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +15 -4
- package/dist/i18n/locales/zh.js +153 -3
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.d.ts +37 -17
- package/dist/index.js +40 -1
- package/dist/index.js.map +1 -1
- package/dist/kit-labels-v3biUF1L.d.ts +1645 -0
- package/dist/lib/format.d.ts +144 -0
- package/dist/lib/format.js +149 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/qr-encode.d.ts +44 -0
- package/dist/lib/qr-encode.js +338 -0
- package/dist/lib/qr-encode.js.map +1 -0
- package/dist/rhf/fields.d.ts +241 -0
- package/dist/rhf/fields.js +601 -0
- package/dist/rhf/fields.js.map +1 -0
- package/dist/rhf/form.d.ts +49 -1
- package/dist/rhf/line-items.d.ts +31 -0
- package/dist/rhf/line-items.js +59 -0
- package/dist/rhf/line-items.js.map +1 -0
- package/dist/rhf.d.ts +61 -1
- package/dist/rhf.js +2 -0
- package/dist/rhf.js.map +1 -1
- package/dist/shell/app-shell.d.ts +99 -2
- package/dist/shell/app-shell.js +58 -3
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/auth-layout.d.ts +74 -0
- package/dist/shell/auth-layout.js +97 -0
- package/dist/shell/auth-layout.js.map +1 -0
- package/dist/shell/top-bar-brand.d.ts +81 -0
- package/dist/shell/top-bar-brand.js +47 -0
- package/dist/shell/top-bar-brand.js.map +1 -0
- package/dist/shell/topbar-action-menu.d.ts +12 -1
- package/dist/shell/topbar-action-menu.js +16 -1
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell.d.ts +56 -1
- package/dist/shell.js +2 -0
- package/dist/shell.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +48 -1
- package/dist/wizard/wizard-context.d.ts +24 -1
- package/dist/wizard/wizard-context.js +19 -2
- package/dist/wizard/wizard-context.js.map +1 -1
- package/dist/wizard/wizard-step.d.ts +20 -5
- package/dist/wizard/wizard-step.js +16 -3
- package/dist/wizard/wizard-step.js.map +1 -1
- package/dist/wizard.d.ts +50 -3
- package/package.json +1 -1
- package/src/chart.ts +4 -0
- package/src/components/account-settings-labels.ts +190 -0
- package/src/components/account-settings.tsx +110 -63
- package/src/components/amount-input.tsx +13 -1
- package/src/components/authed-image.tsx +190 -0
- package/src/components/breadcrumbs.tsx +8 -2
- package/src/components/button-group.tsx +7 -2
- package/src/components/calendar-heatmap.tsx +105 -10
- package/src/components/chip.tsx +8 -4
- package/src/components/choice-card.tsx +136 -25
- package/src/components/combobox-core.tsx +5 -0
- package/src/components/combobox.tsx +31 -9
- package/src/components/copy-button.tsx +3 -2
- package/src/components/data-table-cells.tsx +119 -0
- package/src/components/data-table-filters.ts +77 -0
- package/src/components/data-table-labels.ts +23 -0
- package/src/components/data-table.tsx +224 -13
- package/src/components/date-picker.tsx +19 -3
- package/src/components/description-list.tsx +52 -3
- package/src/components/entity-combobox.tsx +18 -3
- package/src/components/error-boundary.tsx +216 -0
- package/src/components/field.tsx +56 -5
- package/src/components/floating-panel.tsx +20 -7
- package/src/components/form-actions.tsx +191 -0
- package/src/components/image-grid.tsx +181 -0
- package/src/components/lightbox.tsx +374 -0
- package/src/components/line-items.tsx +385 -0
- package/src/components/list.tsx +65 -16
- package/src/components/loading-state.tsx +47 -0
- package/src/components/menu-item.tsx +7 -2
- package/src/components/mini-calendar.tsx +72 -3
- package/src/components/modal.tsx +61 -3
- package/src/components/month-picker.tsx +181 -26
- package/src/components/multi-entity-combobox.tsx +19 -3
- package/src/components/nav-pills.tsx +8 -1
- package/src/components/number-field.tsx +15 -10
- package/src/components/number-input.tsx +16 -1
- package/src/components/passkeys-setting.tsx +331 -0
- package/src/components/picker-sheet.tsx +7 -1
- package/src/components/pie-chart-labels.ts +32 -0
- package/src/components/pie-chart.tsx +479 -0
- package/src/components/progress-bar.tsx +129 -19
- package/src/components/qr-code.tsx +83 -0
- package/src/components/search-field.tsx +20 -4
- package/src/components/signed-amount.tsx +286 -0
- package/src/components/skeleton.tsx +21 -3
- package/src/components/stat-tile.tsx +8 -2
- package/src/components/table.tsx +102 -13
- package/src/components/text-link.tsx +248 -0
- package/src/components/toggle-group.tsx +58 -10
- package/src/components/toggle-legend.tsx +87 -2
- package/src/components/ui.tsx +426 -36
- package/src/components/use-table-state.ts +265 -33
- package/src/data-table.ts +10 -0
- package/src/feedback/feedback-dialog.tsx +42 -3
- package/src/feedback/feedback-thread.tsx +434 -0
- package/src/feedback.ts +1 -0
- package/src/hooks/use-authed-src.ts +161 -0
- package/src/hooks/use-hotkey.ts +172 -0
- package/src/hooks/use-search-param-state.ts +187 -0
- package/src/i18n/defaults.ts +30 -0
- package/src/i18n/kit-labels.tsx +102 -8
- package/src/i18n/locales/de.ts +153 -0
- package/src/i18n/locales/es.ts +150 -0
- package/src/i18n/locales/fr.ts +153 -0
- package/src/i18n/locales/hu.ts +151 -0
- package/src/i18n/locales/it.ts +151 -0
- package/src/i18n/locales/zh.ts +150 -0
- package/src/index.ts +59 -0
- package/src/lib/format.ts +325 -0
- package/src/lib/qr-encode.ts +420 -0
- package/src/rhf/fields.tsx +1054 -0
- package/src/rhf/line-items.tsx +130 -0
- package/src/rhf.ts +6 -0
- package/src/shell/app-shell.tsx +147 -2
- package/src/shell/auth-layout.tsx +190 -0
- package/src/shell/top-bar-brand.tsx +76 -0
- package/src/shell/topbar-action-menu.tsx +21 -0
- package/src/shell.ts +2 -0
- package/src/wizard/wizard-context.tsx +41 -1
- package/src/wizard/wizard-step.tsx +43 -6
- package/tokens.css +12 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/rhf/fields.tsx"],"sourcesContent":["/**\n * Bound fields: one line per field of a react-hook-form form. `@eifi1/ui-kit/rhf`.\n *\n * ```tsx\n * <Form {...form}>\n * <RhfTextField name=\"name\" label=\"Name\" hint=\"As on the lease\" required\n * rules={{ required: \"Enter a name\" }} />\n * <RhfMoneyField name=\"rent\" label=\"Net rent\" currency=\"CHF\" />\n * <RhfDateField name=\"start\" label=\"Start\" />\n * <RhfSelect name=\"type\" label=\"Type\" options={TYPES} />\n * <RhfCombobox name=\"tenantId\" label=\"Tenant\" options={tenants} clearable />\n * <RhfCheckbox name=\"isDefault\" label=\"Default account\" />\n * </Form>\n * ```\n *\n * Each folds the `FormField → FormItem → FormLabel → FormControl → field →\n * FormDescription → FormMessage` scaffold (see ./form) into one element, the way\n * kastlan's shared/components/form/fields.tsx does for its forms — with what that file\n * left out:\n *\n * - **The red border.** Every field gets `invalid` from the field state, so an errored\n * field PAINTS as well as announces. kastlan's number, money, date and entity fields\n * passed only `aria-invalid` through `FormControl`, or nothing, and `Input`, `Select`\n * and `Textarea` paint only from the prop (see the note in ./form).\n * - **Focus on error.** `field.ref` reaches the focusable element — the element itself\n * where the kit field forwards a ref, a focus handle on it where it does not (the\n * number field, the pickers) — so `handleSubmit` and `trigger(…, { shouldFocus })`\n * land the caret on the first field in error.\n * - **`control` is optional**: under `<Form {...form}>` the fields find the form\n * through react-hook-form's context. Pass it for the field's value types\n * (`control={form.control}` checks `name` against the form's values).\n *\n * The common props: `name`, `control`, `label` (a {@link FormLabel} above the field;\n * omitted, none — then give the field an `aria-label`), `hint` (standing advice under\n * the field, attached to it with `aria-describedby`), `required` (the label's mark,\n * and `aria-required` where the control takes it — validation is `rules`' or the\n * resolver's), `rules`, `disabled`, and `className` for the item's box.\n *\n * {@link RhfField} is the shell they are all built on, for a control the kit does not\n * ship (an address autocomplete): it takes a `render` and wires the rest.\n */\nimport { useLayoutEffect, useRef, useState, type ReactElement, type ReactNode } from \"react\";\nimport type {\n ControllerFieldState,\n ControllerProps,\n ControllerRenderProps,\n FieldPath,\n FieldValues,\n} from \"react-hook-form\";\nimport { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, useFormField } from \"./form\";\nimport { Input, Select, Textarea, type InputProps, type SelectProps, type TextareaProps } from \"../components/ui\";\nimport { NumberField, type NumberFieldProps } from \"../components/number-field\";\nimport { AmountInput } from \"../components/amount-input\";\nimport { DatePicker, type DatePickerProps } from \"../components/date-picker\";\nimport { Checkbox, type CheckboxProps } from \"../components/checkbox\";\nimport { EntityCombobox, type EntityComboboxProps } from \"../components/entity-combobox\";\nimport { Combobox, type ComboboxProps } from \"../components/combobox\";\nimport type { ComboClearValue } from \"../components/combobox-core\";\nimport { cn } from \"../lib/cn\";\n\n// ── the shell ────────────────────────────────────────────────────────────────\n\n/** What every bound field takes. */\nexport interface RhfFieldBaseProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n> {\n name: TName;\n /** `form.control`. Optional under `<Form {...form}>`; pass it to type-check `name`. */\n control?: ControllerProps<TFieldValues, TName, TTransformed>[\"control\"];\n /** react-hook-form's `rules` (`required`, `min`, `validate` …). */\n rules?: ControllerProps<TFieldValues, TName, TTransformed>[\"rules\"];\n /** A {@link FormLabel} above the field. Omitted: no label — name the control with\n * an `aria-label` instead. */\n label?: ReactNode;\n /** Standing advice under the field (\"As printed on the card\"), attached to the\n * control with `aria-describedby`. */\n hint?: ReactNode;\n /** Draws the label's required mark and sets `aria-required` where the control\n * takes it. Whether the field IS required is `rules`' or the resolver's to say. */\n required?: boolean;\n /** Disables the field — through react-hook-form, so its value is left out of the\n * submitted values as a disabled input's would be. */\n disabled?: boolean;\n /** Classes for the item's box (a `grid gap-1`). */\n className?: string;\n}\n\n/** What {@link RhfField}'s `render` receives. */\nexport interface RhfFieldRenderContext<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> {\n field: ControllerRenderProps<TFieldValues, TName>;\n fieldState: ControllerFieldState;\n /** The field has an error: pass it to the control's `invalid` so it paints. */\n invalid: boolean;\n /** The error's message, if any. */\n error: string | undefined;\n /** The control's id, which the label points at. `FormControl` sets it on the\n * rendered element already; this is for a control that routes it elsewhere. */\n id: string;\n /** The label's id, for a control that is named with `aria-labelledby`. */\n labelId: string;\n /** The ids of the rendered hint and message, if any. */\n describedBy: string | undefined;\n}\n\nexport interface RhfFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n> extends RhfFieldBaseProps<TFieldValues, TName, TTransformed> {\n /** The control. Wrapped in {@link FormControl} (its `id`, `aria-describedby` and\n * `aria-invalid`) unless `asControl` is false. */\n render: (ctx: RhfFieldRenderContext<TFieldValues, TName>) => ReactElement;\n /** `false`: render the control as is, for one that wires its own ids from the\n * context. Default `true`. */\n asControl?: boolean;\n /** `false`: no {@link FormMessage}, for a control that renders its own error (its\n * `error` prop). Default `true`. */\n message?: boolean;\n /** `false`: no {@link FormLabel}, for a control that carries its label itself (a\n * checkbox). Default `true`. */\n showLabel?: boolean;\n}\n\nfunction hasContent(node: ReactNode): boolean {\n return node !== undefined && node !== null && node !== false && node !== \"\";\n}\n\n/** The label, with an id the control can be named by. Inside the item, so it can read\n * the item's id. */\nfunction RhfLabel({ required, children }: { required?: boolean; children: ReactNode }) {\n const { id } = useFormField();\n return (\n <FormLabel id={`${id}-label`} required={required}>\n {children}\n </FormLabel>\n );\n}\n\nfunction ControlSlot<TFieldValues extends FieldValues, TName extends FieldPath<TFieldValues>>({\n field,\n fieldState,\n render,\n asControl,\n}: {\n field: ControllerRenderProps<TFieldValues, TName>;\n fieldState: ControllerFieldState;\n render: RhfFieldProps<TFieldValues, TName>[\"render\"];\n asControl: boolean;\n}) {\n const { id, formItemId, describedBy } = useFormField();\n const element = render({\n field,\n fieldState,\n invalid: fieldState.invalid,\n error: fieldState.error?.message,\n id: formItemId,\n labelId: `${id}-label`,\n describedBy,\n });\n return asControl ? <FormControl>{element}</FormControl> : element;\n}\n\n/**\n * The shell every bound field is built on: label, control, hint and message around\n * a `render` of your own.\n *\n * ```tsx\n * <RhfField name=\"address\" label=\"Address\" render={({ field, invalid }) => (\n * <AddressAutocomplete value={field.value ?? \"\"} onChange={field.onChange} invalid={invalid} />\n * )} />\n * ```\n */\nexport function RhfField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n>({\n name,\n control,\n rules,\n label,\n hint,\n required,\n disabled,\n className,\n render,\n asControl = true,\n message = true,\n showLabel = true,\n}: RhfFieldProps<TFieldValues, TName, TTransformed>) {\n return (\n <FormField\n control={control}\n name={name}\n rules={rules}\n disabled={disabled}\n render={({ field, fieldState }) => (\n <FormItem className={className}>\n {showLabel && hasContent(label) && <RhfLabel required={required}>{label}</RhfLabel>}\n <ControlSlot field={field} fieldState={fieldState} render={render} asControl={asControl} />\n {hasContent(hint) && <FormDescription>{hint}</FormDescription>}\n {message && <FormMessage />}\n </FormItem>\n )}\n />\n );\n}\n\n/**\n * Hands react-hook-form a focus handle for a control that forwards no ref: its\n * `shouldFocusError` calls `focus()` on whatever `field.ref` was given. `find` runs at\n * focus time, so it sees the element as it is then.\n */\nfunction useFocusHandle(ref: ControllerRenderProps[\"ref\"], find: () => HTMLElement | null | undefined) {\n const findRef = useRef(find);\n useLayoutEffect(() => {\n findRef.current = find;\n });\n useLayoutEffect(() => {\n ref({ focus: () => findRef.current()?.focus() });\n }, [ref]);\n}\n\n// ── text ─────────────────────────────────────────────────────────────────────\n\ntype OwnInputProps = Omit<\n InputProps,\n \"name\" | \"value\" | \"defaultValue\" | \"onChange\" | \"onBlur\" | \"ref\" | \"label\" | \"error\" | \"invalid\" | \"className\" | \"disabled\" | \"required\"\n>;\n\nexport type RhfTextFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> & OwnInputProps;\n\n/** A text {@link Input} — `type` for email, tel, password, url. Stores the string. */\nexport function RhfTextField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n>({\n name,\n control,\n rules,\n label,\n hint,\n required,\n disabled,\n className,\n ...inputProps\n}: RhfTextFieldProps<TFieldValues, TName, TTransformed>) {\n return (\n <RhfField\n {...{ name, control, rules, label, hint, required, disabled, className }}\n render={({ field, invalid }) => (\n <Input\n aria-required={required || undefined}\n {...inputProps}\n name={field.name}\n ref={field.ref}\n value={(field.value ?? \"\") as string}\n onChange={field.onChange}\n onBlur={field.onBlur}\n disabled={field.disabled}\n invalid={invalid}\n />\n )}\n />\n );\n}\n\ntype OwnTextareaProps = Omit<\n TextareaProps,\n \"name\" | \"value\" | \"defaultValue\" | \"onChange\" | \"onBlur\" | \"ref\" | \"label\" | \"error\" | \"invalid\" | \"className\" | \"disabled\" | \"required\"\n> & {\n /** Classes for the `<textarea>`. */\n inputClassName?: string;\n};\n\nexport type RhfTextareaProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> & OwnTextareaProps;\n\n/** A multi-line {@link Textarea}; takes `rows`. Stores the string. */\nexport function RhfTextarea<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n>({\n name,\n control,\n rules,\n label,\n hint,\n required,\n disabled,\n className,\n inputClassName,\n ...areaProps\n}: RhfTextareaProps<TFieldValues, TName, TTransformed>) {\n return (\n <RhfField\n {...{ name, control, rules, label, hint, required, disabled, className }}\n render={({ field, invalid }) => (\n <Textarea\n aria-required={required || undefined}\n {...areaProps}\n className={inputClassName}\n name={field.name}\n ref={field.ref}\n value={(field.value ?? \"\") as string}\n onChange={field.onChange}\n onBlur={field.onBlur}\n disabled={field.disabled}\n invalid={invalid}\n />\n )}\n />\n );\n}\n\n// ── numbers ──────────────────────────────────────────────────────────────────\n\n/** A form value → the number field's `number | null`. Defaults hold `\"\"`, `null`, a\n * number, or a numeric string. */\nfunction toNumber(value: unknown): number | null {\n if (value === null || value === undefined || value === \"\") return null;\n const n = typeof value === \"number\" ? value : Number(String(value).replace(\",\", \".\"));\n return Number.isFinite(n) ? n : null;\n}\n\nexport type RhfNumberFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> &\n Pick<\n NumberFieldProps,\n | \"digits\"\n | \"min\"\n | \"max\"\n | \"step\"\n | \"calculator\"\n | \"unit\"\n | \"unitPlacement\"\n | \"placeholder\"\n | \"inputClassName\"\n | \"locale\"\n | \"ariaLabel\"\n | \"autoFocus\"\n > & {\n /** What an emptied field stores. Default `null`; `\"\"` for a schema written\n * against a native number input (`z.coerce.number()` over `\"\"`). */\n emptyValue?: null | \"\";\n /** `false`: an emptied field snaps back to its last number instead of storing\n * `emptyValue`. Default `true`. */\n nullable?: boolean;\n };\n\n/**\n * The kit's {@link NumberField}: a parsed, rounded (`digits`) and clamped (`min` /\n * `max`) number, committed on blur or Enter in the locale's decimal mark. Stores a\n * number, or `emptyValue` when emptied.\n */\nexport function RhfNumberField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n>({\n name,\n control,\n rules,\n label,\n hint,\n required,\n disabled,\n className,\n emptyValue = null,\n nullable = true,\n ...numberProps\n}: RhfNumberFieldProps<TFieldValues, TName, TTransformed>) {\n return (\n <RhfField\n {...{ name, control, rules, label, hint, required, disabled, className }}\n render={({ field, invalid, id }) => (\n // FormControl clones this element with `id` / `aria-describedby` /\n // `aria-invalid`, which NumberControl hands on to the field.\n <NumberControl\n field={field as unknown as ControllerRenderProps}\n invalid={invalid}\n required={required}\n id={id}\n emptyValue={emptyValue}\n nullable={nullable}\n numberProps={numberProps}\n />\n )}\n />\n );\n}\n\nfunction NumberControl({\n field,\n invalid,\n required,\n id,\n emptyValue,\n nullable,\n numberProps,\n ...aria\n}: {\n field: ControllerRenderProps;\n invalid: boolean;\n required?: boolean;\n id: string;\n emptyValue: null | \"\";\n nullable: boolean;\n numberProps: Omit<RhfNumberFieldProps, keyof RhfFieldBaseProps | \"emptyValue\" | \"nullable\">;\n \"aria-describedby\"?: string;\n \"aria-invalid\"?: NumberFieldProps[\"aria-invalid\"];\n}) {\n // NumberField forwards no ref; it routes `id` to its <input>, where the handle\n // finds it.\n useFocusHandle(field.ref, () => document.getElementById(id));\n return (\n <NumberField\n {...numberProps}\n aria-describedby={aria[\"aria-describedby\"]}\n aria-invalid={aria[\"aria-invalid\"]}\n aria-required={required || undefined}\n id={id}\n value={toNumber(field.value)}\n onCommit={(n) => {\n field.onChange(n ?? emptyValue);\n field.onBlur();\n }}\n nullable={nullable}\n disabled={field.disabled}\n invalid={invalid}\n />\n );\n}\n\n// ── money ────────────────────────────────────────────────────────────────────\n\nexport type RhfMoneyFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> & {\n placeholder?: string;\n /** The currency chip's code (\"CHF\"). */\n currency?: string;\n /** Makes the chip a currency picker. Bind it to another field with\n * `useController`, or to state. */\n onCurrencyChange?: (code: string) => void;\n /** Colours the figure for the direction of money. */\n tone?: \"neutral\" | \"outflow\" | \"inflow\";\n align?: \"start\" | \"center\";\n ariaLabel?: string;\n autoFocus?: boolean;\n /**\n * What the form stores: `\"number\"` (default) — `12.5`, or `emptyValue` while the\n * field is empty — or `\"string\"`, the field's own text (\"12.50\") for a schema that\n * parses it itself. A half-typed sum (\"12+\") leaves the stored number as it was\n * until it resolves.\n */\n valueAs?: \"number\" | \"string\";\n /** What an emptied field stores when `valueAs` is `\"number\"`. Default `null`. */\n emptyValue?: null | \"\";\n};\n\n/** The amount a text reads as, or `undefined` for a draft that is not one yet. */\nfunction parseAmount(text: string): number | null | undefined {\n const trimmed = text.trim();\n if (trimmed === \"\") return null;\n if (!/^-?\\d*[.,]?\\d*$/.test(trimmed)) return undefined;\n const n = Number(trimmed.replace(\",\", \".\"));\n return Number.isFinite(n) ? n : undefined;\n}\n\nfunction MoneyControl({\n field,\n invalid,\n required,\n id,\n describedBy,\n props,\n}: {\n field: ControllerRenderProps;\n invalid: boolean;\n required?: boolean;\n id: string;\n describedBy: string | undefined;\n props: Omit<RhfMoneyFieldProps, keyof RhfFieldBaseProps>;\n}) {\n const { valueAs = \"number\", emptyValue = null, ariaLabel, ...amountProps } = props;\n const value: unknown = field.value;\n const external = value === null || value === undefined ? \"\" : String(value);\n // The text being typed. A stored NUMBER cannot hold \"12.\" or \"12+5\", so the draft\n // lives here and is re-read from the form only when the form's value moves away\n // from what the draft already says (a reset, a setValue).\n const [draft, setDraft] = useState(external);\n const [seen, setSeen] = useState<unknown>(value);\n if (seen !== value) {\n setSeen(value);\n const current = valueAs === \"string\" ? draft : parseAmount(draft);\n const same = valueAs === \"string\" ? current === external : current === toNumber(value);\n if (!same) setDraft(external);\n }\n const input = useRef<HTMLInputElement | null>(null);\n // AmountInput reports no blur, and react-hook-form needs one to mark the field\n // touched: listen on its <input>.\n const onBlur = field.onBlur;\n useLayoutEffect(() => {\n const el = input.current;\n if (!el) return;\n el.addEventListener(\"blur\", onBlur);\n return () => el.removeEventListener(\"blur\", onBlur);\n }, [onBlur]);\n return (\n <div>\n <AmountInput\n {...amountProps}\n ariaLabel={ariaLabel}\n id={id}\n aria-describedby={describedBy}\n aria-required={required || undefined}\n ref={(el) => {\n input.current = el;\n field.ref(el);\n }}\n value={draft}\n disabled={field.disabled}\n invalid={invalid}\n onChange={(text) => {\n setDraft(text);\n if (valueAs === \"string\") {\n field.onChange(text);\n return;\n }\n const parsed = parseAmount(text);\n if (parsed === undefined) return;\n field.onChange(parsed ?? emptyValue);\n }}\n />\n </div>\n );\n}\n\n/**\n * The kit's {@link AmountInput}: a money figure with its currency chip and the\n * calculator (\"1200+80\" resolves on blur or Enter). Stores a number by default — see\n * `valueAs`.\n */\nexport function RhfMoneyField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n>({\n name,\n control,\n rules,\n label,\n hint,\n required,\n disabled,\n className,\n ...amountProps\n}: RhfMoneyFieldProps<TFieldValues, TName, TTransformed>) {\n return (\n <RhfField\n {...{ name, control, rules, label, hint, required, disabled, className }}\n asControl={false}\n render={({ field, invalid, id, describedBy }) => (\n <MoneyControl\n field={field as unknown as ControllerRenderProps}\n invalid={invalid}\n required={required}\n id={id}\n describedBy={describedBy}\n props={amountProps}\n />\n )}\n />\n );\n}\n\n// ── date ─────────────────────────────────────────────────────────────────────\n\nexport type RhfDateFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> &\n Omit<DatePickerProps, \"value\" | \"onChange\" | \"label\" | \"invalid\" | \"disabled\" | \"className\" | \"id\"> & {\n /** Classes for the picker. Default `w-full`. */\n inputClassName?: string;\n /** What a cleared date stores. Default `\"\"`, the empty ISO string; `null` for a\n * nullable schema. */\n emptyValue?: \"\" | null;\n };\n\nfunction DateControl({\n field,\n invalid,\n required,\n id,\n emptyValue,\n inputClassName,\n pickerProps,\n ...aria\n}: {\n field: ControllerRenderProps;\n invalid: boolean;\n required?: boolean;\n id: string;\n emptyValue: \"\" | null;\n inputClassName?: string;\n pickerProps: Omit<DatePickerProps, \"value\" | \"onChange\" | \"label\" | \"invalid\" | \"disabled\" | \"className\" | \"id\">;\n \"aria-describedby\"?: string;\n \"aria-invalid\"?: DatePickerProps[\"aria-invalid\"];\n}) {\n useFocusHandle(field.ref, () => document.getElementById(id));\n const value: unknown = field.value;\n return (\n <DatePicker\n {...pickerProps}\n {...aria}\n aria-required={required || undefined}\n id={id}\n value={typeof value === \"string\" ? value : \"\"}\n onChange={(iso) => {\n field.onChange(iso === \"\" ? emptyValue : iso);\n field.onBlur();\n }}\n disabled={field.disabled}\n invalid={invalid}\n className={inputClassName ?? \"w-full\"}\n />\n );\n}\n\n/** The kit's {@link DatePicker}, holding an ISO `\"YYYY-MM-DD\"` string. */\nexport function RhfDateField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n>({\n name,\n control,\n rules,\n label,\n hint,\n required,\n disabled,\n className,\n inputClassName,\n emptyValue = \"\",\n ...pickerProps\n}: RhfDateFieldProps<TFieldValues, TName, TTransformed>) {\n return (\n <RhfField\n {...{ name, control, rules, label, hint, required, disabled, className }}\n render={({ field, invalid, id }) => (\n // FormControl clones this element with `aria-describedby` / `aria-invalid`,\n // which DateControl hands on to the picker's trigger.\n <DateControl\n field={field as unknown as ControllerRenderProps}\n invalid={invalid}\n required={required}\n id={id}\n emptyValue={emptyValue}\n inputClassName={inputClassName}\n pickerProps={pickerProps}\n />\n )}\n />\n );\n}\n\n// ── select ───────────────────────────────────────────────────────────────────\n\nexport interface RhfSelectOption {\n value: string | number;\n label: ReactNode;\n disabled?: boolean;\n}\n\nexport type RhfSelectProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> &\n Pick<SelectProps, \"size\" | \"autoFocus\" | \"aria-label\"> & {\n /** The options, as data. Or pass `<option>` children. */\n options?: readonly RhfSelectOption[];\n children?: ReactNode;\n /** A first, empty option (\"Choose…\"), selected while the value is empty. */\n placeholder?: string;\n /** Store `Number(value)` rather than the option's string. An empty choice still\n * stores `\"\"`. */\n valueAsNumber?: boolean;\n /** Classes for the select. Default `w-full`. */\n selectClassName?: string;\n };\n\n/** A native {@link Select}, from `options` or `<option>` children. */\nexport function RhfSelect<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n>({\n name,\n control,\n rules,\n label,\n hint,\n required,\n disabled,\n className,\n options,\n children,\n placeholder,\n valueAsNumber,\n selectClassName,\n ...selectProps\n}: RhfSelectProps<TFieldValues, TName, TTransformed>) {\n return (\n <RhfField\n {...{ name, control, rules, label, hint, required, disabled, className }}\n render={({ field, invalid }) => (\n <Select\n aria-required={required || undefined}\n {...selectProps}\n className={cn(\"w-full\", selectClassName)}\n name={field.name}\n ref={field.ref}\n value={(field.value ?? \"\") as string | number}\n onChange={(e) => {\n const raw = e.target.value;\n field.onChange(valueAsNumber && raw !== \"\" ? Number(raw) : raw);\n }}\n onBlur={field.onBlur}\n disabled={field.disabled}\n invalid={invalid}\n >\n {placeholder !== undefined && <option value=\"\">{placeholder}</option>}\n {options\n ? options.map((o) => (\n <option key={String(o.value)} value={o.value} disabled={o.disabled}>\n {o.label}\n </option>\n ))\n : children}\n </Select>\n )}\n />\n );\n}\n\n// ── checkbox ─────────────────────────────────────────────────────────────────\n\nexport type RhfCheckboxProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> &\n Pick<CheckboxProps, \"inputClassName\" | \"autoFocus\" | \"aria-label\">;\n\n/**\n * The kit's {@link Checkbox}, label beside the box and `hint` under it (the\n * checkbox's own `description`). Stores a boolean. `required` is the native one here\n * — see Checkbox — so a `<form>` refuses to submit it unticked.\n */\nexport function RhfCheckbox<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n>({\n name,\n control,\n rules,\n label,\n hint,\n required,\n disabled,\n className,\n ...boxProps\n}: RhfCheckboxProps<TFieldValues, TName, TTransformed>) {\n return (\n <RhfField\n {...{ name, control, rules, required, disabled, className }}\n showLabel={false}\n render={({ field, invalid }) => (\n <Checkbox\n {...boxProps}\n ref={field.ref}\n name={field.name}\n checked={Boolean(field.value)}\n onCheckedChange={field.onChange}\n onBlur={field.onBlur}\n disabled={field.disabled}\n required={required}\n invalid={invalid}\n label={label}\n description={hint}\n />\n )}\n />\n );\n}\n\n// ── comboboxes ───────────────────────────────────────────────────────────────\n\nexport type RhfComboboxProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n V extends string | number = string | number,\n TTransformed = TFieldValues,\n> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> &\n Pick<\n EntityComboboxProps<V>,\n | \"options\"\n | \"loadOptions\"\n | \"loading\"\n | \"placeholder\"\n | \"searchPlaceholder\"\n | \"emptyLabel\"\n | \"clearable\"\n | \"clearLabel\"\n | \"onCreate\"\n | \"createLabel\"\n | \"filter\"\n | \"minChars\"\n | \"debounceMs\"\n > & {\n /** What a clear stores — the picker's `clearValue`. Default `null`; `\"\"` for a\n * schema that spells \"no choice\" as an empty string. */\n clearValue?: ComboClearValue;\n /** Classes for the picker. */\n comboClassName?: string;\n };\n\nfunction EntityControl<V extends string | number>({\n field,\n invalid,\n required,\n error,\n id,\n describedBy,\n clearValue,\n comboClassName,\n comboProps,\n}: {\n field: ControllerRenderProps;\n invalid: boolean;\n required?: boolean;\n error: string | undefined;\n id: string;\n describedBy: string | undefined;\n clearValue: ComboClearValue;\n comboClassName?: string;\n comboProps: Omit<RhfComboboxProps<FieldValues, string, V>, keyof RhfFieldBaseProps | \"clearValue\" | \"comboClassName\">;\n}) {\n const box = useRef<HTMLDivElement>(null);\n // EntityCombobox puts `id` and the ARIA below on its trigger, so the label's\n // `htmlFor` names it, the hint describes it and the focus handle finds it by id.\n useFocusHandle(field.ref, () => document.getElementById(id));\n // EntityCombobox reports no blur: focus leaving the picker marks the field touched.\n const onBlur = field.onBlur;\n useLayoutEffect(() => {\n const el = box.current;\n if (!el) return;\n el.addEventListener(\"focusout\", onBlur);\n return () => el.removeEventListener(\"focusout\", onBlur);\n }, [onBlur]);\n const value: unknown = field.value;\n return (\n <div ref={box}>\n <EntityCombobox<V, ComboClearValue>\n {...comboProps}\n className={comboClassName}\n id={id}\n aria-describedby={describedBy}\n aria-required={required || undefined}\n value={(value ?? null) as V | ComboClearValue | null}\n clearValue={clearValue}\n onChange={(v) => field.onChange(v)}\n disabled={field.disabled}\n invalid={invalid}\n // Its own message, which it merges into the trigger's aria-describedby after\n // the hint.\n error={error}\n />\n </div>\n );\n}\n\n/**\n * The kit's {@link EntityCombobox}: an id-keyed pick from `options` or `loadOptions`.\n * Stores the option's `value`, or `clearValue` on a clear (only offered with\n * `clearable`).\n */\nexport function RhfCombobox<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n V extends string | number = string | number,\n TTransformed = TFieldValues,\n>({\n name,\n control,\n rules,\n label,\n hint,\n required,\n disabled,\n className,\n clearValue = null,\n comboClassName,\n ...comboProps\n}: RhfComboboxProps<TFieldValues, TName, V, TTransformed>) {\n return (\n <RhfField\n {...{ name, control, rules, label, hint, required, disabled, className }}\n asControl={false}\n message={false}\n render={({ field, invalid, error, id, describedBy }) => (\n <EntityControl<V>\n field={field as unknown as ControllerRenderProps}\n invalid={invalid}\n required={required}\n error={error}\n id={id}\n describedBy={describedBy}\n clearValue={clearValue}\n comboClassName={comboClassName}\n comboProps={comboProps}\n />\n )}\n />\n );\n}\n\nexport type RhfTextComboboxProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n> = RhfFieldBaseProps<TFieldValues, TName, TTransformed> &\n Pick<\n ComboboxProps,\n | \"options\"\n | \"placeholder\"\n | \"groupBy\"\n | \"maxSuggestions\"\n | \"searchPlaceholder\"\n | \"createLabel\"\n | \"optionAdornment\"\n | \"autoFocus\"\n | \"aria-label\"\n > & {\n /** Classes for the combobox. */\n comboClassName?: string;\n };\n\n/**\n * The kit's free-text {@link Combobox}: type anything, or pick one of `options`.\n * Stores the string.\n */\nexport function RhfTextCombobox<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformed = TFieldValues,\n>({\n name,\n control,\n rules,\n label,\n hint,\n required,\n disabled,\n className,\n comboClassName,\n ...comboProps\n}: RhfTextComboboxProps<TFieldValues, TName, TTransformed>) {\n return (\n <RhfField\n {...{ name, control, rules, label, hint, required, disabled, className }}\n asControl={false}\n message={false}\n render={({ field, invalid, error, id, describedBy }) => (\n <TextComboControl\n field={field as unknown as ControllerRenderProps}\n invalid={invalid}\n required={required}\n error={error}\n id={id}\n describedBy={describedBy}\n className={comboClassName}\n comboProps={comboProps}\n />\n )}\n />\n );\n}\n\nfunction TextComboControl({\n field,\n invalid,\n required,\n error,\n id,\n describedBy,\n className,\n comboProps,\n}: {\n field: ControllerRenderProps;\n invalid: boolean;\n required?: boolean;\n error: string | undefined;\n id: string;\n describedBy: string | undefined;\n className?: string;\n comboProps: Omit<RhfTextComboboxProps, keyof RhfFieldBaseProps | \"comboClassName\">;\n}) {\n // The combobox routes `id` and its ARIA to its <input>, so the label's `htmlFor`\n // names it, the hint describes it and the focus handle finds it; the error is its\n // own `error` prop, which it merges in after the hint.\n useFocusHandle(field.ref, () => document.getElementById(id));\n const value: unknown = field.value;\n return (\n <Combobox\n {...comboProps}\n id={id}\n aria-describedby={describedBy}\n aria-required={required || undefined}\n className={className}\n value={typeof value === \"string\" ? value : value == null ? \"\" : String(value)}\n onChange={field.onChange}\n onBlur={field.onBlur}\n disabled={field.disabled}\n invalid={invalid}\n error={error}\n />\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/rhf/form.d.ts
CHANGED
|
@@ -2,10 +2,58 @@ import * as react from 'react';
|
|
|
2
2
|
import { ReactElement, ComponentProps } from 'react';
|
|
3
3
|
import * as react_hook_form from 'react-hook-form';
|
|
4
4
|
import { FieldValues, FieldPath, ControllerProps } from 'react-hook-form';
|
|
5
|
-
import { LabelProps } from '../
|
|
5
|
+
import { aB as LabelProps } from '../kit-labels-v3biUF1L.js';
|
|
6
|
+
import '../components/data-table-labels.js';
|
|
7
|
+
import '../components/mini-calendar.js';
|
|
8
|
+
import '../components/calendar-heatmap.js';
|
|
9
|
+
import '../components/popover.js';
|
|
10
|
+
import '../components/chip.js';
|
|
11
|
+
import 'lucide-react';
|
|
12
|
+
import '../components/field-sync.js';
|
|
6
13
|
import '../components/tooltip.js';
|
|
7
14
|
import '../hooks/use-anchored-rect.js';
|
|
8
15
|
import '../lib/clipping.js';
|
|
16
|
+
import '../wizard/types.js';
|
|
17
|
+
import '../tour/tour.js';
|
|
18
|
+
import '../search/command-palette.js';
|
|
19
|
+
import '../search/global-search.js';
|
|
20
|
+
import '../search/search-index.js';
|
|
21
|
+
import '../components/month-picker.js';
|
|
22
|
+
import '../components/page-contents.js';
|
|
23
|
+
import '../components/series-chart-labels.js';
|
|
24
|
+
import '../components/pie-chart-labels.js';
|
|
25
|
+
import '../components/sparkline.js';
|
|
26
|
+
import '../components/stat-tile.js';
|
|
27
|
+
import '../components/signature-pad.js';
|
|
28
|
+
import '../components/password-strength.js';
|
|
29
|
+
import '../components/danger-confirm.js';
|
|
30
|
+
import '../components/swatch-picker.js';
|
|
31
|
+
import '../components/tile-radio.js';
|
|
32
|
+
import '../components/icon-picker.js';
|
|
33
|
+
import '../components/dialog-frame.js';
|
|
34
|
+
import '../components/modal.js';
|
|
35
|
+
import '../hooks/use-search-param-state.js';
|
|
36
|
+
import '../components/measured-grid.js';
|
|
37
|
+
import '../feedback/feedback-attachment.js';
|
|
38
|
+
import '../feedback/feedback-dialog.js';
|
|
39
|
+
import '../feedback/feedback-thread.js';
|
|
40
|
+
import '../feedback/feedback-inbox.js';
|
|
41
|
+
import '../components/account-settings-labels.js';
|
|
42
|
+
import '../components/confirm-dialog.js';
|
|
43
|
+
import '../components/floating-panel.js';
|
|
44
|
+
import '../components/bulk-action-bar.js';
|
|
45
|
+
import '../components/list.js';
|
|
46
|
+
import '../components/breadcrumbs.js';
|
|
47
|
+
import '../components/toast.js';
|
|
48
|
+
import '../components/description-list.js';
|
|
49
|
+
import '../components/line-items.js';
|
|
50
|
+
import '../components/progress-bar.js';
|
|
51
|
+
import '../components/signed-amount.js';
|
|
52
|
+
import '../components/error-boundary.js';
|
|
53
|
+
import '../components/authed-image.js';
|
|
54
|
+
import '../hooks/use-authed-src.js';
|
|
55
|
+
import '../components/image-grid.js';
|
|
56
|
+
import '../components/lightbox.js';
|
|
9
57
|
|
|
10
58
|
/** The form's `useForm()` return, spread in: `<Form {...form}>`. react-hook-form's own
|
|
11
59
|
* `FormProvider`, under the name the shadcn file gave it. */
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { FieldValues, FieldArrayPath, FieldArrayWithId, UseFieldArrayProps, FieldArray } from 'react-hook-form';
|
|
4
|
+
import { LineItemCellContext, LineItemsProps, LineItemsColumn } from '../components/line-items.js';
|
|
5
|
+
|
|
6
|
+
/** A cell's context, with the row's path in the form. */
|
|
7
|
+
interface RhfLineItemCellContext<TItem, TArrayName extends string> extends LineItemCellContext<TItem> {
|
|
8
|
+
/** The row's path: `${name}.${index}` — bind the cell's field to
|
|
9
|
+
* `` `${name}.amount` ``. */
|
|
10
|
+
name: `${TArrayName}.${number}`;
|
|
11
|
+
}
|
|
12
|
+
interface RhfLineItemsColumn<TItem, TArrayName extends string> extends Omit<LineItemsColumn<TItem>, "render"> {
|
|
13
|
+
render: (ctx: RhfLineItemCellContext<TItem, TArrayName>) => ReactNode;
|
|
14
|
+
}
|
|
15
|
+
interface RhfLineItemsProps<TFieldValues extends FieldValues = FieldValues, TArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>, TTransformed = TFieldValues> extends Omit<LineItemsProps<FieldArrayWithId<TFieldValues, TArrayName, "id">>, "items" | "columns" | "onAdd" | "onRemove" | "getKey"> {
|
|
16
|
+
name: TArrayName;
|
|
17
|
+
/** `form.control`. Optional under `<Form {...form}>`. */
|
|
18
|
+
control?: UseFieldArrayProps<TFieldValues, TArrayName, "id", TTransformed>["control"];
|
|
19
|
+
/** `useFieldArray`'s `rules` (`minLength`, `validate` …); its message is the list's
|
|
20
|
+
* error. */
|
|
21
|
+
rules?: UseFieldArrayProps<TFieldValues, TArrayName, "id", TTransformed>["rules"];
|
|
22
|
+
columns: readonly RhfLineItemsColumn<FieldArrayWithId<TFieldValues, TArrayName, "id">, TArrayName>[];
|
|
23
|
+
/** A new row's values. Omitted: no add button. */
|
|
24
|
+
newItem?: () => FieldArray<TFieldValues, TArrayName>;
|
|
25
|
+
/** `false`: no remove buttons. Default `true`. */
|
|
26
|
+
removable?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** {@link LineItems} bound to a field array. See the module note. */
|
|
29
|
+
declare function RhfLineItems<TFieldValues extends FieldValues = FieldValues, TArrayName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>, TTransformed = TFieldValues>({ name, control, rules, columns, newItem, removable, error, ...rest }: RhfLineItemsProps<TFieldValues, TArrayName, TTransformed>): react.JSX.Element;
|
|
30
|
+
|
|
31
|
+
export { type RhfLineItemCellContext, RhfLineItems, type RhfLineItemsColumn, type RhfLineItemsProps };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import {
|
|
4
|
+
useFieldArray,
|
|
5
|
+
useFormState
|
|
6
|
+
} from "react-hook-form";
|
|
7
|
+
import {
|
|
8
|
+
LineItems
|
|
9
|
+
} from "../components/line-items.js";
|
|
10
|
+
function arrayError(errors, path) {
|
|
11
|
+
let node = errors;
|
|
12
|
+
for (const key of path.split(".")) {
|
|
13
|
+
if (node === null || typeof node !== "object") return void 0;
|
|
14
|
+
node = node[key];
|
|
15
|
+
}
|
|
16
|
+
if (node === null || typeof node !== "object") return void 0;
|
|
17
|
+
const { root, message } = node;
|
|
18
|
+
const text = root?.message ?? message;
|
|
19
|
+
return typeof text === "string" && text !== "" ? text : void 0;
|
|
20
|
+
}
|
|
21
|
+
function RhfLineItems({
|
|
22
|
+
name,
|
|
23
|
+
control,
|
|
24
|
+
rules,
|
|
25
|
+
columns,
|
|
26
|
+
newItem,
|
|
27
|
+
removable = true,
|
|
28
|
+
error,
|
|
29
|
+
...rest
|
|
30
|
+
}) {
|
|
31
|
+
const { fields, append, remove } = useFieldArray({
|
|
32
|
+
control,
|
|
33
|
+
name,
|
|
34
|
+
rules
|
|
35
|
+
});
|
|
36
|
+
const { errors } = useFormState({ control, name });
|
|
37
|
+
const bound = columns.map(
|
|
38
|
+
({ render, ...column }) => ({
|
|
39
|
+
...column,
|
|
40
|
+
render: (ctx) => render({ ...ctx, name: `${name}.${ctx.index}` })
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
return /* @__PURE__ */ jsx(
|
|
44
|
+
LineItems,
|
|
45
|
+
{
|
|
46
|
+
...rest,
|
|
47
|
+
items: fields,
|
|
48
|
+
columns: bound,
|
|
49
|
+
getKey: (field) => field.id,
|
|
50
|
+
onAdd: newItem ? () => append(newItem()) : void 0,
|
|
51
|
+
onRemove: removable ? (index) => remove(index) : void 0,
|
|
52
|
+
error: error ?? arrayError(errors, name)
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
export {
|
|
57
|
+
RhfLineItems
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=line-items.js.map
|
|
@@ -0,0 +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`} ariaLabel={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 */\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":";AAuHI;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":[]}
|
package/dist/rhf.d.ts
CHANGED
|
@@ -1,8 +1,68 @@
|
|
|
1
1
|
export { Form, FormControl, FormControlProps, FormDescription, FormDescriptionProps, FormField, FormItem, FormItemProps, FormLabel, FormLabelProps, FormMessage, FormMessageProps, useFormField } from './rhf/form.js';
|
|
2
2
|
export { RhfWizardStepOptions, useRhfWizardStep } from './rhf/use-rhf-wizard-step.js';
|
|
3
|
+
export { RhfCheckbox, RhfCheckboxProps, RhfCombobox, RhfComboboxProps, RhfDateField, RhfDateFieldProps, RhfField, RhfFieldBaseProps, RhfFieldProps, RhfFieldRenderContext, RhfMoneyField, RhfMoneyFieldProps, RhfNumberField, RhfNumberFieldProps, RhfSelect, RhfSelectOption, RhfSelectProps, RhfTextCombobox, RhfTextComboboxProps, RhfTextField, RhfTextFieldProps, RhfTextarea, RhfTextareaProps } from './rhf/fields.js';
|
|
4
|
+
export { RhfLineItemCellContext, RhfLineItems, RhfLineItemsColumn, RhfLineItemsProps } from './rhf/line-items.js';
|
|
3
5
|
import 'react';
|
|
4
6
|
import 'react-hook-form';
|
|
5
|
-
import './
|
|
7
|
+
import './kit-labels-v3biUF1L.js';
|
|
8
|
+
import './components/data-table-labels.js';
|
|
9
|
+
import './components/mini-calendar.js';
|
|
10
|
+
import './components/calendar-heatmap.js';
|
|
11
|
+
import './components/popover.js';
|
|
12
|
+
import './components/chip.js';
|
|
13
|
+
import 'lucide-react';
|
|
14
|
+
import './components/field-sync.js';
|
|
6
15
|
import './components/tooltip.js';
|
|
7
16
|
import './hooks/use-anchored-rect.js';
|
|
8
17
|
import './lib/clipping.js';
|
|
18
|
+
import './wizard/types.js';
|
|
19
|
+
import './tour/tour.js';
|
|
20
|
+
import './search/command-palette.js';
|
|
21
|
+
import './search/global-search.js';
|
|
22
|
+
import './search/search-index.js';
|
|
23
|
+
import './components/month-picker.js';
|
|
24
|
+
import './components/page-contents.js';
|
|
25
|
+
import './components/series-chart-labels.js';
|
|
26
|
+
import './components/pie-chart-labels.js';
|
|
27
|
+
import './components/sparkline.js';
|
|
28
|
+
import './components/stat-tile.js';
|
|
29
|
+
import './components/signature-pad.js';
|
|
30
|
+
import './components/password-strength.js';
|
|
31
|
+
import './components/danger-confirm.js';
|
|
32
|
+
import './components/swatch-picker.js';
|
|
33
|
+
import './components/tile-radio.js';
|
|
34
|
+
import './components/icon-picker.js';
|
|
35
|
+
import './components/dialog-frame.js';
|
|
36
|
+
import './components/modal.js';
|
|
37
|
+
import './hooks/use-search-param-state.js';
|
|
38
|
+
import './components/measured-grid.js';
|
|
39
|
+
import './feedback/feedback-attachment.js';
|
|
40
|
+
import './feedback/feedback-dialog.js';
|
|
41
|
+
import './feedback/feedback-thread.js';
|
|
42
|
+
import './feedback/feedback-inbox.js';
|
|
43
|
+
import './components/account-settings-labels.js';
|
|
44
|
+
import './components/confirm-dialog.js';
|
|
45
|
+
import './components/floating-panel.js';
|
|
46
|
+
import './components/bulk-action-bar.js';
|
|
47
|
+
import './components/list.js';
|
|
48
|
+
import './components/breadcrumbs.js';
|
|
49
|
+
import './components/toast.js';
|
|
50
|
+
import './components/description-list.js';
|
|
51
|
+
import './components/line-items.js';
|
|
52
|
+
import './components/progress-bar.js';
|
|
53
|
+
import './components/signed-amount.js';
|
|
54
|
+
import './components/error-boundary.js';
|
|
55
|
+
import './components/authed-image.js';
|
|
56
|
+
import './hooks/use-authed-src.js';
|
|
57
|
+
import './components/image-grid.js';
|
|
58
|
+
import './components/lightbox.js';
|
|
59
|
+
import './components/number-field.js';
|
|
60
|
+
import './components/number-input.js';
|
|
61
|
+
import './components/calculator.js';
|
|
62
|
+
import './components/numpad-sheet.js';
|
|
63
|
+
import './components/date-picker.js';
|
|
64
|
+
import './components/checkbox.js';
|
|
65
|
+
import './components/entity-combobox.js';
|
|
66
|
+
import './components/combobox-core.js';
|
|
67
|
+
import './hooks/use-anchored-panel.js';
|
|
68
|
+
import './components/combobox.js';
|
package/dist/rhf.js
CHANGED
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, FormField, FormItem,\n// FormLabel, FormControl, FormDescription, FormMessage and useFormField.\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"],"mappings":";AAQA,cAAc;AAEd,cAAc;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/rhf.ts"],"sourcesContent":["// `@eifi1/ui-kit/rhf` — the react-hook-form adapter: Form, FormField, FormItem,\n// FormLabel, FormControl, FormDescription, FormMessage and useFormField.\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, RhfMoneyField,\n// RhfDateField, RhfTextarea, RhfSelect, RhfCheckbox, RhfCombobox, RhfTextCombobox)\n// and RhfField, the shell they are built on.\nexport * from \"./rhf/fields\";\n// LineItems over useFieldArray.\nexport * from \"./rhf/line-items\";\n"],"mappings":";AAQA,cAAc;AAEd,cAAc;AAId,cAAc;AAEd,cAAc;","names":[]}
|
|
@@ -1,6 +1,57 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
3
3
|
import { LucideIcon } from 'lucide-react';
|
|
4
|
+
import { ax as KitLinkComponent } from '../kit-labels-v3biUF1L.js';
|
|
5
|
+
import '../components/data-table-labels.js';
|
|
6
|
+
import '../components/mini-calendar.js';
|
|
7
|
+
import '../components/calendar-heatmap.js';
|
|
8
|
+
import '../components/popover.js';
|
|
9
|
+
import '../components/chip.js';
|
|
10
|
+
import '../components/field-sync.js';
|
|
11
|
+
import '../components/tooltip.js';
|
|
12
|
+
import '../hooks/use-anchored-rect.js';
|
|
13
|
+
import '../lib/clipping.js';
|
|
14
|
+
import '../wizard/types.js';
|
|
15
|
+
import '../tour/tour.js';
|
|
16
|
+
import '../search/command-palette.js';
|
|
17
|
+
import '../search/global-search.js';
|
|
18
|
+
import '../search/search-index.js';
|
|
19
|
+
import '../components/month-picker.js';
|
|
20
|
+
import '../components/page-contents.js';
|
|
21
|
+
import '../components/series-chart-labels.js';
|
|
22
|
+
import '../components/pie-chart-labels.js';
|
|
23
|
+
import '../components/sparkline.js';
|
|
24
|
+
import '../components/stat-tile.js';
|
|
25
|
+
import '../components/signature-pad.js';
|
|
26
|
+
import '../components/password-strength.js';
|
|
27
|
+
import '../components/danger-confirm.js';
|
|
28
|
+
import '../components/swatch-picker.js';
|
|
29
|
+
import '../components/tile-radio.js';
|
|
30
|
+
import '../components/icon-picker.js';
|
|
31
|
+
import '../components/dialog-frame.js';
|
|
32
|
+
import '../components/modal.js';
|
|
33
|
+
import '../hooks/use-search-param-state.js';
|
|
34
|
+
import '../components/measured-grid.js';
|
|
35
|
+
import '../feedback/feedback-attachment.js';
|
|
36
|
+
import '../feedback/feedback-dialog.js';
|
|
37
|
+
import '../feedback/feedback-thread.js';
|
|
38
|
+
import '../feedback/feedback-inbox.js';
|
|
39
|
+
import '../components/account-settings-labels.js';
|
|
40
|
+
import '../components/confirm-dialog.js';
|
|
41
|
+
import '../components/floating-panel.js';
|
|
42
|
+
import '../components/bulk-action-bar.js';
|
|
43
|
+
import '../components/list.js';
|
|
44
|
+
import '../components/breadcrumbs.js';
|
|
45
|
+
import '../components/toast.js';
|
|
46
|
+
import '../components/description-list.js';
|
|
47
|
+
import '../components/line-items.js';
|
|
48
|
+
import '../components/progress-bar.js';
|
|
49
|
+
import '../components/signed-amount.js';
|
|
50
|
+
import '../components/error-boundary.js';
|
|
51
|
+
import '../components/authed-image.js';
|
|
52
|
+
import '../hooks/use-authed-src.js';
|
|
53
|
+
import '../components/image-grid.js';
|
|
54
|
+
import '../components/lightbox.js';
|
|
4
55
|
|
|
5
56
|
interface AppShellSubItem {
|
|
6
57
|
to: string;
|
|
@@ -35,6 +86,45 @@ interface AppShellNavItem {
|
|
|
35
86
|
* bottom bar ignores sub-items and links to `to`. */
|
|
36
87
|
items?: AppShellSubItem[];
|
|
37
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* One entry of the sidebar's bottom area ({@link AppShellProps.sidebarFooterItems}) —
|
|
91
|
+
* the version link and the legal links kastlan hand-built in `sidebarFooter`.
|
|
92
|
+
*
|
|
93
|
+
* - `link` (default): one link. Expanded it shows `icon` + `text` (default `label`),
|
|
94
|
+
* with `hint` as a tooltip if given; collapsed it is the icon alone, named and
|
|
95
|
+
* tooltipped by `label`.
|
|
96
|
+
* - `links`: a small group — the legal links. Expanded, a `<nav>` named `label` holding
|
|
97
|
+
* the links as a wrapping row of small text; collapsed, ONE icon link to `to` (default
|
|
98
|
+
* the first link's), named and tooltipped by `label`, since a column of icons for
|
|
99
|
+
* "Imprint", "Privacy" and "Terms" would say nothing an icon can.
|
|
100
|
+
*/
|
|
101
|
+
type AppShellSidebarFooterItem = {
|
|
102
|
+
kind?: "link";
|
|
103
|
+
key: string;
|
|
104
|
+
to: string;
|
|
105
|
+
icon: LucideIcon;
|
|
106
|
+
/** The link's name, and the tooltip when collapsed ("What's new · v1.4.0"). */
|
|
107
|
+
label: string;
|
|
108
|
+
/** Visible text when expanded ("Kastlan v1.4.0"). Default `label`. */
|
|
109
|
+
text?: ReactNode;
|
|
110
|
+
/** A tooltip on the expanded link ("What's new"). */
|
|
111
|
+
hint?: string;
|
|
112
|
+
/** Leaves the app: a plain `<a target="_blank" rel="noopener noreferrer">`. */
|
|
113
|
+
external?: boolean;
|
|
114
|
+
} | {
|
|
115
|
+
kind: "links";
|
|
116
|
+
key: string;
|
|
117
|
+
icon: LucideIcon;
|
|
118
|
+
/** The group's name — its `<nav>` label, and the collapsed icon's name ("Legal"). */
|
|
119
|
+
label: string;
|
|
120
|
+
/** The collapsed icon's target. Default the first link's `to`. */
|
|
121
|
+
to?: string;
|
|
122
|
+
links: {
|
|
123
|
+
to: string;
|
|
124
|
+
label: string;
|
|
125
|
+
external?: boolean;
|
|
126
|
+
}[];
|
|
127
|
+
};
|
|
38
128
|
/**
|
|
39
129
|
* Exported and `<div>`-shaped. This is the outermost element of every consuming app, so
|
|
40
130
|
* there is nothing above it to hang an id, a landmark label or a `data-tour` anchor on —
|
|
@@ -53,6 +143,13 @@ interface AppShellProps extends ComponentPropsWithoutRef<"div"> {
|
|
|
53
143
|
/** Extra sidebar content above the collapse toggle (e.g. a version link).
|
|
54
144
|
* Receives the collapsed state so it can render compact vs. full. */
|
|
55
145
|
sidebarFooter?: (collapsed: boolean) => ReactNode;
|
|
146
|
+
/** The sidebar's bottom area as data — a version link, the legal links — drawn full
|
|
147
|
+
* when expanded and as icon + tooltip when collapsed. Rendered above
|
|
148
|
+
* `sidebarFooter`, which stays for anything the data cannot describe. */
|
|
149
|
+
sidebarFooterItems?: AppShellSidebarFooterItem[];
|
|
150
|
+
/** The router link for `sidebarFooterItems`. Default: the provider's
|
|
151
|
+
* `linkComponent`, else react-router's `Link`. */
|
|
152
|
+
renderLink?: KitLinkComponent;
|
|
56
153
|
/** localStorage key for the persisted collapse state. */
|
|
57
154
|
collapseStorageKey?: string;
|
|
58
155
|
/** Default: `appShell.collapse` from the {@link UiKitProvider}, else English. */
|
|
@@ -100,6 +197,6 @@ interface AppShellProps extends ComponentPropsWithoutRef<"div"> {
|
|
|
100
197
|
* `NavLink`; domain-free — nav items, brand, footer and the top bar's actions
|
|
101
198
|
* are all supplied by the app.
|
|
102
199
|
*/
|
|
103
|
-
declare function AppShell({ nav, topBar, children, footer, sidebarFooter, collapseStorageKey: collapseStorageKeyProp, collapseLabel, expandLabel, subNav, mobileSubNav, toggleGroupLabel, embedded: embeddedProp, className, ...rest }: AppShellProps): react.JSX.Element;
|
|
200
|
+
declare function AppShell({ nav, topBar, children, footer, sidebarFooter, sidebarFooterItems, renderLink, collapseStorageKey: collapseStorageKeyProp, collapseLabel, expandLabel, subNav, mobileSubNav, toggleGroupLabel, embedded: embeddedProp, className, ...rest }: AppShellProps): react.JSX.Element;
|
|
104
201
|
|
|
105
|
-
export { AppShell, type AppShellNavItem, type AppShellProps, type AppShellSubItem };
|
|
202
|
+
export { AppShell, type AppShellNavItem, type AppShellProps, type AppShellSidebarFooterItem, type AppShellSubItem };
|
package/dist/shell/app-shell.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { createContext, useCallback, useContext, useEffect, useId, useRef, useState } from "react";
|
|
4
4
|
import { createPortal } from "react-dom";
|
|
5
|
-
import { NavLink, matchPath, useLocation } from "react-router";
|
|
5
|
+
import { Link, NavLink, matchPath, useLocation } from "react-router";
|
|
6
6
|
import { ChevronRight, PanelLeftClose, PanelLeftOpen } from "lucide-react";
|
|
7
7
|
import { cn } from "../lib/cn.js";
|
|
8
8
|
import { dirOf } from "../lib/direction.js";
|
|
9
9
|
import { readStored, writeStored } from "../lib/safe-storage.js";
|
|
10
10
|
import { Tooltip } from "../components/tooltip.js";
|
|
11
|
+
import { pickLinkRenderer } from "../components/text-link.js";
|
|
11
12
|
import { useAnchoredRect } from "../hooks/use-anchored-rect.js";
|
|
12
13
|
import { useEscapeKey } from "../hooks/use-dismiss.js";
|
|
13
14
|
import { useMediaQuery } from "../hooks/use-media-query.js";
|
|
14
|
-
import { DEFAULT_APP_SHELL_LABELS, useKitLabels } from "../i18n/kit-labels.js";
|
|
15
|
+
import { DEFAULT_APP_SHELL_LABELS, useKitLabels, useKitLink } from "../i18n/kit-labels.js";
|
|
15
16
|
const AppShellNesting = createContext(false);
|
|
16
17
|
function useNavHeightVar(ref, shellRef, embedded) {
|
|
17
18
|
const isMdUp = useMediaQuery("(min-width: 768px)", false);
|
|
@@ -41,6 +42,8 @@ function AppShell({
|
|
|
41
42
|
children,
|
|
42
43
|
footer,
|
|
43
44
|
sidebarFooter,
|
|
45
|
+
sidebarFooterItems,
|
|
46
|
+
renderLink,
|
|
44
47
|
collapseStorageKey: collapseStorageKeyProp,
|
|
45
48
|
collapseLabel,
|
|
46
49
|
expandLabel,
|
|
@@ -115,6 +118,7 @@ function AppShell({
|
|
|
115
118
|
},
|
|
116
119
|
item.to
|
|
117
120
|
)) }) }),
|
|
121
|
+
!!sidebarFooterItems?.length && /* @__PURE__ */ jsx(SidebarFooterItems, { items: sidebarFooterItems, collapsed, renderLink }),
|
|
118
122
|
sidebarFooter?.(collapsed),
|
|
119
123
|
/* @__PURE__ */ jsx("div", { className: "border-t border-[var(--border)] p-2", children: collapsed ? /* @__PURE__ */ jsx(Tooltip, { label: labels.expand, side: "end", portal: true, className: "block", children: /* @__PURE__ */ jsx(
|
|
120
124
|
"button",
|
|
@@ -180,6 +184,57 @@ function AppShell({
|
|
|
180
184
|
) })
|
|
181
185
|
);
|
|
182
186
|
}
|
|
187
|
+
const routerLink = ({ href, ...p }) => /* @__PURE__ */ jsx(Link, { to: href, ...p });
|
|
188
|
+
const plainLink = ({ children, ...p }) => /* @__PURE__ */ jsx("a", { ...p, children });
|
|
189
|
+
const FOOTER_ICON_LINK = "flex min-h-8 items-center justify-center rounded-md text-[var(--text-muted)] hover:bg-[var(--bg-hover)] hover:text-[var(--text-secondary)]";
|
|
190
|
+
function RenderedLink({ render, ...props }) {
|
|
191
|
+
return render(props);
|
|
192
|
+
}
|
|
193
|
+
function SidebarFooterItems({
|
|
194
|
+
items,
|
|
195
|
+
collapsed,
|
|
196
|
+
renderLink
|
|
197
|
+
}) {
|
|
198
|
+
const kitLink = useKitLink();
|
|
199
|
+
const linkTo = (to, external, { children, ...props }) => {
|
|
200
|
+
const InApp = pickLinkRenderer(renderLink, kitLink ?? routerLink, to) ?? plainLink;
|
|
201
|
+
return external ? /* @__PURE__ */ jsx("a", { href: to, target: "_blank", rel: "noopener noreferrer", ...props, children }) : /* @__PURE__ */ jsx(RenderedLink, { render: InApp, href: to, ...props, children });
|
|
202
|
+
};
|
|
203
|
+
return /* @__PURE__ */ jsx("div", { "data-slot": "sidebar-footer-items", className: cn("px-2 py-1", collapsed ? "space-y-1" : "space-y-1.5"), children: items.map((item) => {
|
|
204
|
+
if (collapsed) {
|
|
205
|
+
const to = item.kind === "links" ? item.to ?? item.links[0]?.to : item.to;
|
|
206
|
+
if (!to) return null;
|
|
207
|
+
const external = item.kind === "links" ? item.links.find((l) => l.to === to)?.external : item.external;
|
|
208
|
+
return /* @__PURE__ */ jsx(Tooltip, { label: item.label, side: "end", portal: true, className: "block", children: linkTo(to, external, {
|
|
209
|
+
"aria-label": item.label,
|
|
210
|
+
className: FOOTER_ICON_LINK,
|
|
211
|
+
children: /* @__PURE__ */ jsx(item.icon, { className: "size-4", "aria-hidden": true })
|
|
212
|
+
}) }, item.key);
|
|
213
|
+
}
|
|
214
|
+
if (item.kind === "links") {
|
|
215
|
+
return /* @__PURE__ */ jsx(
|
|
216
|
+
"nav",
|
|
217
|
+
{
|
|
218
|
+
"aria-label": item.label,
|
|
219
|
+
className: "flex flex-wrap justify-center gap-x-3 gap-y-0.5 text-[11px] text-[var(--text-muted)]",
|
|
220
|
+
children: item.links.map((l) => /* @__PURE__ */ jsx("span", { children: linkTo(l.to, l.external, {
|
|
221
|
+
className: "rounded-sm hover:text-[var(--text-secondary)] hover:underline",
|
|
222
|
+
children: l.label
|
|
223
|
+
}) }, l.to))
|
|
224
|
+
},
|
|
225
|
+
item.key
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
const link = linkTo(item.to, item.external, {
|
|
229
|
+
className: cn(FOOTER_ICON_LINK, "gap-1.5 text-xs font-medium"),
|
|
230
|
+
children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
231
|
+
/* @__PURE__ */ jsx(item.icon, { className: "size-3.5 shrink-0", "aria-hidden": true }),
|
|
232
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: item.text ?? item.label })
|
|
233
|
+
] })
|
|
234
|
+
});
|
|
235
|
+
return item.hint ? /* @__PURE__ */ jsx(Tooltip, { label: item.hint, side: "top", portal: true, className: "block", children: link }, item.key) : /* @__PURE__ */ jsx("div", { children: link }, item.key);
|
|
236
|
+
}) });
|
|
237
|
+
}
|
|
183
238
|
function MobileNavItem({ item }) {
|
|
184
239
|
const subActive = useSubItemActive(item);
|
|
185
240
|
return /* @__PURE__ */ jsxs(
|