@uniform-ts/core 0.0.5 → 0.0.7
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 +14 -14
- package/dist/field-DPgaGkOL.d.mts +730 -0
- package/dist/field-DPgaGkOL.d.ts +730 -0
- package/dist/index.d.mts +8 -717
- package/dist/index.d.ts +8 -717
- package/dist/index.js +21 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +21 -12
- package/dist/index.mjs.map +1 -1
- package/dist/locales/en.d.mts +8 -0
- package/dist/locales/en.d.ts +8 -0
- package/dist/locales/en.js +24 -0
- package/dist/locales/en.js.map +1 -0
- package/dist/locales/en.mjs +22 -0
- package/dist/locales/en.mjs.map +1 -0
- package/dist/locales/es.d.mts +8 -0
- package/dist/locales/es.d.ts +8 -0
- package/dist/locales/es.js +24 -0
- package/dist/locales/es.js.map +1 -0
- package/dist/locales/es.mjs +22 -0
- package/dist/locales/es.mjs.map +1 -0
- package/dist/locales/he.d.mts +8 -0
- package/dist/locales/he.d.ts +8 -0
- package/dist/locales/he.js +24 -0
- package/dist/locales/he.js.map +1 -0
- package/dist/locales/he.mjs +22 -0
- package/dist/locales/he.mjs.map +1 -0
- package/package.json +20 -6
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
import * as React$1 from 'react';
|
|
2
|
+
import { FieldValues, FieldPath, FieldPathValue, RefCallBack } from 'react-hook-form';
|
|
3
|
+
import * as z from 'zod/v4/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Extracts the element type of an array type.
|
|
7
|
+
* e.g. `ArrayItem<{ name: string }[]>` → `{ name: string }`
|
|
8
|
+
*/
|
|
9
|
+
type ArrayItem<T> = T extends (infer U)[] ? U : never;
|
|
10
|
+
/**
|
|
11
|
+
* Recursively produces all valid `fields` prop keys for a given schema shape:
|
|
12
|
+
*
|
|
13
|
+
* - Scalar fields → just their key (e.g. `"name"`)
|
|
14
|
+
* - Object fields → their key + all dot-notated child paths
|
|
15
|
+
* (e.g. `"address"` | `"address.street"`)
|
|
16
|
+
* - Array fields → their key + the unprefixed keys of the item object, so
|
|
17
|
+
* you can target every row's sub-field uniformly
|
|
18
|
+
* (e.g. `"items"` | `"items.name"` | `"items.qty"`)
|
|
19
|
+
* Index-based paths like `"items.0.name"` are intentionally
|
|
20
|
+
* excluded — row count is dynamic at runtime.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // Given { name: string; address: { street: string }; items: { qty: number }[] }
|
|
24
|
+
* // DeepKeys produces:
|
|
25
|
+
* // "name" | "address" | "address.street" | "items" | "items.qty"
|
|
26
|
+
*/
|
|
27
|
+
type DeepKeys<T> = T extends object ? {
|
|
28
|
+
[K in keyof T & string]: T[K] extends unknown[] ? ArrayItem<T[K]> extends object ? K | `${K}.${DeepKeys<ArrayItem<T[K]>>}` : K : T[K] extends object ? K | `${K}.${DeepKeys<T[K]>}` : K;
|
|
29
|
+
}[keyof T & string] : never;
|
|
30
|
+
/**
|
|
31
|
+
* Resolves the value type at a dot-notated path within a type `T`.
|
|
32
|
+
* Array fields use the unprefixed child path (matching `DeepKeys` convention).
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // DeepFieldValue<{ name: string; items: { qty: number }[] }, 'items.qty'> → number
|
|
36
|
+
*/
|
|
37
|
+
type DeepFieldValue<T, K extends string> = K extends keyof T ? T[K] : K extends `${infer Head}.${infer Tail}` ? Head extends keyof T ? T[Head] extends (infer Item)[] ? DeepFieldValue<NonNullable<Item>, Tail> : DeepFieldValue<NonNullable<T[Head]>, Tail> : unknown : unknown;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* A single option entry used in `select` / enum fields.
|
|
41
|
+
*/
|
|
42
|
+
type SelectOption = {
|
|
43
|
+
/** Human-readable text displayed in the dropdown. */
|
|
44
|
+
label: string;
|
|
45
|
+
/** The underlying value submitted with the form. */
|
|
46
|
+
value: string | number;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A map of field type keys to React components used to render them.
|
|
51
|
+
* Built-in keys (`string`, `number`, `boolean`, `date`, `select`, `textarea`)
|
|
52
|
+
* are pre-typed. Additional custom keys can be added via the index signature
|
|
53
|
+
* and registered through `createAutoForm` or the `components` prop.
|
|
54
|
+
*/
|
|
55
|
+
type ComponentRegistry = {
|
|
56
|
+
string?: React$1.ComponentType<FieldProps>;
|
|
57
|
+
number?: React$1.ComponentType<FieldProps>;
|
|
58
|
+
boolean?: React$1.ComponentType<FieldProps>;
|
|
59
|
+
date?: React$1.ComponentType<FieldProps>;
|
|
60
|
+
select?: React$1.ComponentType<FieldProps>;
|
|
61
|
+
textarea?: React$1.ComponentType<FieldProps>;
|
|
62
|
+
[key: string]: React$1.ComponentType<FieldProps> | undefined;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Props passed to the field wrapper component that surrounds every rendered
|
|
66
|
+
* field. Used to render the label, description, error message, and grid span.
|
|
67
|
+
*/
|
|
68
|
+
interface FieldWrapperProps {
|
|
69
|
+
/** The field input component to wrap. */
|
|
70
|
+
children: React$1.ReactNode;
|
|
71
|
+
/** The fully resolved field configuration. */
|
|
72
|
+
field: FieldConfig;
|
|
73
|
+
/** Validation error message for the field. */
|
|
74
|
+
error?: string;
|
|
75
|
+
/** Grid column span override (takes precedence over `field.meta.span`). */
|
|
76
|
+
span?: number;
|
|
77
|
+
/**
|
|
78
|
+
* Zero-based render index of this field within its parent container
|
|
79
|
+
* (form root or section). Exposed as the `--field-index` CSS custom property.
|
|
80
|
+
*/
|
|
81
|
+
index?: number;
|
|
82
|
+
/**
|
|
83
|
+
* Nesting depth of this field (0 = top-level, 1 = inside object, etc.).
|
|
84
|
+
* Exposed as the `--field-depth` CSS custom property.
|
|
85
|
+
*/
|
|
86
|
+
depth?: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Props for a generic array action button. Compatible with standard design
|
|
91
|
+
* system button components — pass your own via the `arrayButton` layout slot
|
|
92
|
+
* and it will be used for all array buttons (add, remove, move, duplicate).
|
|
93
|
+
*/
|
|
94
|
+
interface ArrayButtonProps {
|
|
95
|
+
onClick?: React$1.MouseEventHandler<HTMLButtonElement>;
|
|
96
|
+
disabled?: boolean;
|
|
97
|
+
/** Always `"button"` — prevents accidental form submission. */
|
|
98
|
+
type?: 'button' | 'submit' | 'reset';
|
|
99
|
+
/** Accessible label describing the specific action and target row. */
|
|
100
|
+
'aria-label'?: string;
|
|
101
|
+
/** CSS class name forwarded from `classNames.arrayAdd` / `arrayRemove` / etc. */
|
|
102
|
+
className?: string;
|
|
103
|
+
children?: React$1.ReactNode;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Props for the collapse/expand toggle button on an array row.
|
|
107
|
+
* Extends `ArrayButtonProps` with collapse state so custom components
|
|
108
|
+
* can apply directional styling (e.g. rotating a chevron icon).
|
|
109
|
+
*/
|
|
110
|
+
interface ArrayCollapseButtonProps extends ArrayButtonProps {
|
|
111
|
+
/** Whether the row is currently collapsed. */
|
|
112
|
+
isCollapsed: boolean;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Props for the component that wraps the entire array field body,
|
|
116
|
+
* controlling the relative position of the rows and the add button.
|
|
117
|
+
*/
|
|
118
|
+
interface ArrayFieldLayoutProps {
|
|
119
|
+
/** The rendered list of array rows. */
|
|
120
|
+
rows: React$1.ReactNode;
|
|
121
|
+
/** The rendered "add row" button. */
|
|
122
|
+
addButton: React$1.ReactNode;
|
|
123
|
+
/** Total number of rows currently in the array. */
|
|
124
|
+
rowCount: number;
|
|
125
|
+
/** Whether adding another row is permitted (respects `maxItems`). */
|
|
126
|
+
canAdd: boolean;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Props passed to the component that renders a single row inside an array field,
|
|
130
|
+
* including the row's content and action buttons (move, duplicate, remove, collapse).
|
|
131
|
+
*/
|
|
132
|
+
interface ArrayRowLayoutProps {
|
|
133
|
+
/** The rendered fields for this array item. */
|
|
134
|
+
children: React$1.ReactNode;
|
|
135
|
+
/** Action button nodes for the row. */
|
|
136
|
+
buttons: {
|
|
137
|
+
/** Button to move the row up, or `null` if already first. */
|
|
138
|
+
moveUp: React$1.ReactNode | null;
|
|
139
|
+
/** Button to move the row down, or `null` if already last. */
|
|
140
|
+
moveDown: React$1.ReactNode | null;
|
|
141
|
+
/** Button to duplicate the row, or `null` if at max items. */
|
|
142
|
+
duplicate: React$1.ReactNode | null;
|
|
143
|
+
/** Button to remove the row. */
|
|
144
|
+
remove: React$1.ReactNode;
|
|
145
|
+
/** Button to collapse/expand the row, or `null` if collapsing is disabled. */
|
|
146
|
+
collapse: React$1.ReactNode | null;
|
|
147
|
+
};
|
|
148
|
+
/** Zero-based index of this row within the array. */
|
|
149
|
+
index: number;
|
|
150
|
+
/** Total number of rows currently in the array. */
|
|
151
|
+
rowCount: number;
|
|
152
|
+
}
|
|
153
|
+
/** Props received by the `layout.formWrapper` component. */
|
|
154
|
+
interface FormWrapperProps {
|
|
155
|
+
children: React$1.ReactNode;
|
|
156
|
+
}
|
|
157
|
+
/** Props received by the `layout.sectionWrapper` component (and per-section `SectionConfig.component`). */
|
|
158
|
+
interface SectionWrapperProps {
|
|
159
|
+
children: React$1.ReactNode;
|
|
160
|
+
title: string;
|
|
161
|
+
className?: string;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Props received by the `layout.objectWrapper` component.
|
|
165
|
+
* Replaces the default `<fieldset>` / `<legend>` wrapper rendered around
|
|
166
|
+
* nested object fields.
|
|
167
|
+
*/
|
|
168
|
+
interface ObjectWrapperProps {
|
|
169
|
+
/** The rendered child fields. */
|
|
170
|
+
children: React$1.ReactNode;
|
|
171
|
+
/** The field label (used as the legend / heading). May be undefined. */
|
|
172
|
+
label: string | undefined;
|
|
173
|
+
/** CSS class name forwarded from `classNames.objectFieldset`. */
|
|
174
|
+
className?: string;
|
|
175
|
+
/** CSS class name forwarded from `classNames.objectLegend` for the label element. */
|
|
176
|
+
labelClassName?: string;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Props received by the `layout.arrayWrapper` component.
|
|
180
|
+
* Replaces the default `<fieldset>` / `<legend>` wrapper rendered around
|
|
181
|
+
* array fields.
|
|
182
|
+
*/
|
|
183
|
+
interface ArrayWrapperProps {
|
|
184
|
+
/** The rendered array field body (rows + add button). */
|
|
185
|
+
children: React$1.ReactNode;
|
|
186
|
+
/** The field label (used as the legend / heading). May be undefined. */
|
|
187
|
+
label: string | undefined;
|
|
188
|
+
/** CSS class name forwarded from `classNames.arrayFieldset`. */
|
|
189
|
+
className?: string;
|
|
190
|
+
/** CSS class name forwarded from `classNames.arrayLegend` for the label element. */
|
|
191
|
+
labelClassName?: string;
|
|
192
|
+
}
|
|
193
|
+
/** Props received by the `layout.submitButton` component. */
|
|
194
|
+
interface SubmitButtonProps {
|
|
195
|
+
isSubmitting: boolean;
|
|
196
|
+
label: string;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Per-section styling overrides forwarded to the `sectionWrapper` component.
|
|
200
|
+
* Keys are section titles; values control how that section wrapper is styled.
|
|
201
|
+
*/
|
|
202
|
+
type SectionConfig = {
|
|
203
|
+
/** CSS class name(s) applied to the section wrapper. */
|
|
204
|
+
className?: string;
|
|
205
|
+
/** Replaces the section wrapper component entirely for this section. */
|
|
206
|
+
component?: React$1.ComponentType<SectionWrapperProps>;
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* Button component overrides for array fields. Set `base` to swap in your
|
|
210
|
+
* design system's button everywhere; use the specific keys to override
|
|
211
|
+
* individual actions on top of that. All keys fall back to `base`, which
|
|
212
|
+
* itself falls back to a plain `<button>`.
|
|
213
|
+
*/
|
|
214
|
+
type ArrayButtonSlots = {
|
|
215
|
+
/** Used for every array button that has no specific override. */
|
|
216
|
+
base?: React$1.ComponentType<ArrayButtonProps>;
|
|
217
|
+
/** Override for the add-row button only. */
|
|
218
|
+
add?: React$1.ComponentType<ArrayButtonProps>;
|
|
219
|
+
/** Override for the remove-row button only. */
|
|
220
|
+
remove?: React$1.ComponentType<ArrayButtonProps>;
|
|
221
|
+
/** Override for the move-up button only. */
|
|
222
|
+
moveUp?: React$1.ComponentType<ArrayButtonProps>;
|
|
223
|
+
/** Override for the move-down button only. */
|
|
224
|
+
moveDown?: React$1.ComponentType<ArrayButtonProps>;
|
|
225
|
+
/** Override for the duplicate-row button only. */
|
|
226
|
+
duplicate?: React$1.ComponentType<ArrayButtonProps>;
|
|
227
|
+
/**
|
|
228
|
+
* Override for the collapse/expand toggle button only.
|
|
229
|
+
* Receives `isCollapsed` in addition to standard `ArrayButtonProps`.
|
|
230
|
+
*/
|
|
231
|
+
collapse?: React$1.ComponentType<ArrayCollapseButtonProps>;
|
|
232
|
+
};
|
|
233
|
+
/**
|
|
234
|
+
* Resolved button slots where every entry is guaranteed to be defined.
|
|
235
|
+
*/
|
|
236
|
+
type ResolvedArrayButtonSlots = {
|
|
237
|
+
base: React$1.ComponentType<ArrayButtonProps>;
|
|
238
|
+
add: React$1.ComponentType<ArrayButtonProps>;
|
|
239
|
+
remove: React$1.ComponentType<ArrayButtonProps>;
|
|
240
|
+
moveUp: React$1.ComponentType<ArrayButtonProps>;
|
|
241
|
+
moveDown: React$1.ComponentType<ArrayButtonProps>;
|
|
242
|
+
duplicate: React$1.ComponentType<ArrayButtonProps>;
|
|
243
|
+
collapse: React$1.ComponentType<ArrayCollapseButtonProps>;
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Optional layout slot overrides for top-level structural components of the
|
|
247
|
+
* form. Provide only the slots you want to replace; omitted slots fall back
|
|
248
|
+
* to the built-in defaults.
|
|
249
|
+
*/
|
|
250
|
+
type LayoutSlots = {
|
|
251
|
+
/** Wrapper rendered around the entire form. */
|
|
252
|
+
formWrapper?: React$1.ComponentType<FormWrapperProps>;
|
|
253
|
+
/** Wrapper rendered around each named field section. */
|
|
254
|
+
sectionWrapper?: React$1.ComponentType<SectionWrapperProps>;
|
|
255
|
+
/** Custom submit button component. */
|
|
256
|
+
submitButton?: React$1.ComponentType<SubmitButtonProps>;
|
|
257
|
+
/** Custom layout component for individual rows in array fields. */
|
|
258
|
+
arrayRowLayout?: React$1.ComponentType<ArrayRowLayoutProps>;
|
|
259
|
+
/**
|
|
260
|
+
* Controls the layout of the entire array field body — position the rows
|
|
261
|
+
* and add button relative to each other (e.g. add button above rows).
|
|
262
|
+
*/
|
|
263
|
+
arrayFieldLayout?: React$1.ComponentType<ArrayFieldLayoutProps>;
|
|
264
|
+
/**
|
|
265
|
+
* Replaces the `<fieldset>` / `<legend>` wrapper rendered around nested
|
|
266
|
+
* object fields. Receives `label`, `className`, and `labelClassName` props.
|
|
267
|
+
*/
|
|
268
|
+
objectWrapper?: React$1.ComponentType<ObjectWrapperProps>;
|
|
269
|
+
/**
|
|
270
|
+
* Replaces the `<fieldset>` / `<legend>` wrapper rendered around array
|
|
271
|
+
* fields. Receives `label`, `className`, and `labelClassName` props.
|
|
272
|
+
*/
|
|
273
|
+
arrayWrapper?: React$1.ComponentType<ArrayWrapperProps>;
|
|
274
|
+
/**
|
|
275
|
+
* Button component overrides for array fields. Set `base` to use your
|
|
276
|
+
* design system's button everywhere; use specific keys to override
|
|
277
|
+
* individual actions.
|
|
278
|
+
*/
|
|
279
|
+
arrayButtons?: ArrayButtonSlots;
|
|
280
|
+
/**
|
|
281
|
+
* Content rendered while async `defaultValues` are loading.
|
|
282
|
+
* Defaults to a simple `<p>Loading…</p>` when not provided.
|
|
283
|
+
*/
|
|
284
|
+
loadingFallback?: React$1.ReactNode;
|
|
285
|
+
/**
|
|
286
|
+
* Per-section config keyed by section title.
|
|
287
|
+
* Forwarded to the `sectionWrapper` component as a `className` prop.
|
|
288
|
+
*/
|
|
289
|
+
sections?: Record<string, SectionConfig>;
|
|
290
|
+
};
|
|
291
|
+
/**
|
|
292
|
+
* The resolved version of `LayoutSlots` used internally, where all slots are
|
|
293
|
+
* guaranteed to be defined (falling back to built-in defaults).
|
|
294
|
+
*/
|
|
295
|
+
type ResolvedLayoutSlots = {
|
|
296
|
+
formWrapper: React$1.ComponentType<FormWrapperProps>;
|
|
297
|
+
sectionWrapper: React$1.ComponentType<SectionWrapperProps>;
|
|
298
|
+
submitButton: React$1.ComponentType<SubmitButtonProps>;
|
|
299
|
+
arrayRowLayout: React$1.ComponentType<ArrayRowLayoutProps>;
|
|
300
|
+
arrayFieldLayout: React$1.ComponentType<ArrayFieldLayoutProps>;
|
|
301
|
+
objectWrapper: React$1.ComponentType<ObjectWrapperProps>;
|
|
302
|
+
arrayWrapper: React$1.ComponentType<ArrayWrapperProps>;
|
|
303
|
+
arrayButtons: ResolvedArrayButtonSlots;
|
|
304
|
+
loadingFallback: React$1.ReactNode;
|
|
305
|
+
};
|
|
306
|
+
/**
|
|
307
|
+
* CSS class name overrides for the various structural elements of the form.
|
|
308
|
+
* Only the keys you provide will be applied; omitted keys use the built-in
|
|
309
|
+
* default class names (or none, if the default components don't apply any).
|
|
310
|
+
*/
|
|
311
|
+
type FormClassNames = {
|
|
312
|
+
/** Class applied to the `<form>` element. */
|
|
313
|
+
form?: string;
|
|
314
|
+
/** Class applied to each field wrapper. */
|
|
315
|
+
fieldWrapper?: string;
|
|
316
|
+
/** Class applied to each field label. */
|
|
317
|
+
label?: string;
|
|
318
|
+
/** Class applied to each field description. */
|
|
319
|
+
description?: string;
|
|
320
|
+
/** Class applied to each field error message. */
|
|
321
|
+
error?: string;
|
|
322
|
+
/** Class applied to the "add item" button in array fields. */
|
|
323
|
+
arrayAdd?: string;
|
|
324
|
+
/** Class applied to the "remove item" button in array fields. */
|
|
325
|
+
arrayRemove?: string;
|
|
326
|
+
/** Class applied to the "move item" buttons in array fields. */
|
|
327
|
+
arrayMove?: string;
|
|
328
|
+
/** Class applied to the "duplicate item" button in array fields. */
|
|
329
|
+
arrayDuplicate?: string;
|
|
330
|
+
/** Class applied to the "collapse item" button in array fields. */
|
|
331
|
+
arrayCollapse?: string;
|
|
332
|
+
/** Class applied to the `<fieldset>` wrapper around nested object fields. */
|
|
333
|
+
objectFieldset?: string;
|
|
334
|
+
/** Class applied to the `<legend>` label inside nested object fields. */
|
|
335
|
+
objectLegend?: string;
|
|
336
|
+
/** Class applied to the `<fieldset>` wrapper around array fields. */
|
|
337
|
+
arrayFieldset?: string;
|
|
338
|
+
/** Class applied to the `<legend>` label inside array fields. */
|
|
339
|
+
arrayLegend?: string;
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* All programmatic form control methods, shared by both the field `onChange`
|
|
344
|
+
* callback and the imperative ref handle.
|
|
345
|
+
*
|
|
346
|
+
* @template TValues - The inferred shape of the form values.
|
|
347
|
+
*/
|
|
348
|
+
type FormMethods<TValues extends FieldValues = FieldValues> = {
|
|
349
|
+
/** Set a single field value programmatically */
|
|
350
|
+
setValue: <K extends FieldPath<TValues>>(name: K, value: FieldPathValue<TValues, K>) => void;
|
|
351
|
+
/** Set multiple field values at once */
|
|
352
|
+
setValues: (values: Partial<TValues>) => void;
|
|
353
|
+
/** Get the current form values */
|
|
354
|
+
getValues: () => TValues;
|
|
355
|
+
/** Reset a single field to its default value */
|
|
356
|
+
resetField: (name: FieldPath<TValues>) => void;
|
|
357
|
+
/** Reset the entire form, optionally to new values */
|
|
358
|
+
reset: (values?: Partial<TValues>) => void;
|
|
359
|
+
/** Set a validation error on a specific field */
|
|
360
|
+
setError: (name: FieldPath<TValues>, message: string) => void;
|
|
361
|
+
/** Set validation errors on multiple fields at once */
|
|
362
|
+
setErrors: (errors: Partial<Record<FieldPath<TValues>, string>>) => void;
|
|
363
|
+
/** Clear validation errors (all fields, or specific ones) */
|
|
364
|
+
clearErrors: (names?: FieldPath<TValues> | FieldPath<TValues>[]) => void;
|
|
365
|
+
/** Programmatically trigger form submission */
|
|
366
|
+
submit: () => void;
|
|
367
|
+
/** Focus a specific field by name (dot-notated for nested fields) */
|
|
368
|
+
focus: (fieldName: FieldPath<TValues>) => void;
|
|
369
|
+
/** Watch field values reactively */
|
|
370
|
+
watch: {
|
|
371
|
+
(): TValues;
|
|
372
|
+
<K extends FieldPath<TValues>>(name: K): FieldPathValue<TValues, K>;
|
|
373
|
+
};
|
|
374
|
+
};
|
|
375
|
+
type FormLabels = {
|
|
376
|
+
/** Submit button text — default: "Submit" */
|
|
377
|
+
submit?: string;
|
|
378
|
+
/** Array "Add item" button — default: "Add" */
|
|
379
|
+
arrayAdd?: string;
|
|
380
|
+
/** Array "Remove row" button — default: "Remove" */
|
|
381
|
+
arrayRemove?: string;
|
|
382
|
+
/** Array "Move row up" button — default: "↑" */
|
|
383
|
+
arrayMoveUp?: string;
|
|
384
|
+
/** Array "Move row down" button — default: "↓" */
|
|
385
|
+
arrayMoveDown?: string;
|
|
386
|
+
/** Array "Duplicate row" button — default: "Duplicate" */
|
|
387
|
+
arrayDuplicate?: string;
|
|
388
|
+
/** Array row toggle shown when the row is expanded (clicking collapses it) — default: "▼" */
|
|
389
|
+
arrayCollapse?: string;
|
|
390
|
+
/** Array row toggle shown when the row is collapsed (clicking expands it) — default: "▶" */
|
|
391
|
+
arrayExpand?: string;
|
|
392
|
+
/** Collapsed row summary fallback — default: (i) => `Item ${i + 1}` */
|
|
393
|
+
arrayItemSummary?: (index: number) => string;
|
|
394
|
+
/** Aria label for the expand toggle — default: (i) => `Expand item ${i + 1}` */
|
|
395
|
+
arrayAriaExpand?: (index: number) => string;
|
|
396
|
+
/** Aria label for the collapse toggle — default: (i) => `Collapse item ${i + 1}` */
|
|
397
|
+
arrayAriaCollapse?: (index: number) => string;
|
|
398
|
+
/** Aria label for the move-up button — default: (i) => `Move item ${i + 1} up` */
|
|
399
|
+
arrayAriaMoveUp?: (index: number) => string;
|
|
400
|
+
/** Aria label for the move-down button — default: (i) => `Move item ${i + 1} down` */
|
|
401
|
+
arrayAriaMoveDown?: (index: number) => string;
|
|
402
|
+
/** Aria label for the duplicate button — default: (i) => `Duplicate item ${i + 1}` */
|
|
403
|
+
arrayAriaDuplicate?: (index: number) => string;
|
|
404
|
+
/** Aria label for the remove button — default: (i) => `Remove item ${i + 1}` */
|
|
405
|
+
arrayAriaRemove?: (index: number) => string;
|
|
406
|
+
};
|
|
407
|
+
/**
|
|
408
|
+
* A map of field names to coercion functions. Each function receives the raw
|
|
409
|
+
* field value and returns the coerced value before Zod validation is applied.
|
|
410
|
+
* Useful for transforming string inputs (e.g. from native `<input>`) into the
|
|
411
|
+
* types expected by the schema (e.g. numbers, dates).
|
|
412
|
+
*/
|
|
413
|
+
type CoercionMap = Record<string, (value: unknown) => unknown>;
|
|
414
|
+
/**
|
|
415
|
+
* Custom validation error message overrides. Use `required` to override the
|
|
416
|
+
* global "required field" message, or provide a field name key to override
|
|
417
|
+
* messages for a specific field (supports nested dot-notated paths).
|
|
418
|
+
*/
|
|
419
|
+
type ValidationMessages = {
|
|
420
|
+
required?: string;
|
|
421
|
+
[fieldName: string]: string | Record<string, string> | undefined;
|
|
422
|
+
};
|
|
423
|
+
/**
|
|
424
|
+
* A minimal storage adapter interface compatible with `localStorage` and
|
|
425
|
+
* `sessionStorage`. Provide a custom implementation to persist form values
|
|
426
|
+
* to any backing store (e.g. IndexedDB, AsyncStorage).
|
|
427
|
+
*/
|
|
428
|
+
type PersistStorage = {
|
|
429
|
+
getItem: (key: string) => string | null;
|
|
430
|
+
setItem: (key: string, value: string) => void;
|
|
431
|
+
removeItem: (key: string) => void;
|
|
432
|
+
};
|
|
433
|
+
/**
|
|
434
|
+
* The imperative handle exposed via `ref` on `<AutoForm>`. Provides methods
|
|
435
|
+
* to programmatically control the form from a parent component.
|
|
436
|
+
*
|
|
437
|
+
* @template TSchema - The Zod object schema that defines the form shape.
|
|
438
|
+
*/
|
|
439
|
+
type AutoFormHandle<TSchema extends z.$ZodObject = z.$ZodObject> = FormMethods<z.infer<TSchema>>;
|
|
440
|
+
/**
|
|
441
|
+
* Static configuration provided to `createAutoForm`. These options become the
|
|
442
|
+
* default for every form instance created by the factory, and can be
|
|
443
|
+
* overridden per-instance via the corresponding `<AutoForm>` props.
|
|
444
|
+
*/
|
|
445
|
+
type AutoFormConfig = {
|
|
446
|
+
/** Default component registry for all form instances. */
|
|
447
|
+
components?: ComponentRegistry;
|
|
448
|
+
/** Default field wrapper component for all form instances. */
|
|
449
|
+
fieldWrapper?: React.ComponentType<FieldWrapperProps>;
|
|
450
|
+
/** Default layout slot overrides for all form instances. */
|
|
451
|
+
layout?: LayoutSlots;
|
|
452
|
+
/** Default CSS class name overrides for all form instances. */
|
|
453
|
+
classNames?: FormClassNames;
|
|
454
|
+
/** When `true`, all fields in every form instance are disabled by default. */
|
|
455
|
+
disabled?: boolean;
|
|
456
|
+
/** Default coercion map applied to all form instances. */
|
|
457
|
+
coercions?: CoercionMap;
|
|
458
|
+
/** Default validation message overrides for all form instances. */
|
|
459
|
+
messages?: ValidationMessages;
|
|
460
|
+
/** Default label strings; overridden per-instance by the `labels` prop */
|
|
461
|
+
labels?: FormLabels;
|
|
462
|
+
};
|
|
463
|
+
/**
|
|
464
|
+
* Props for the `<AutoForm>` component. Drives schema introspection, field
|
|
465
|
+
* rendering, validation, and submission.
|
|
466
|
+
*
|
|
467
|
+
* @template TSchema - A `ZodObject` schema that defines the form shape.
|
|
468
|
+
*/
|
|
469
|
+
type AutoFormProps<TSchema extends z.$ZodObject> = {
|
|
470
|
+
/** A UniForm instance carrying the schema and typed onChange handlers. */
|
|
471
|
+
form: {
|
|
472
|
+
readonly schema: TSchema;
|
|
473
|
+
};
|
|
474
|
+
/** Called with the validated form values when the form is submitted successfully. */
|
|
475
|
+
onSubmit: (values: z.infer<TSchema>) => void | Promise<void>;
|
|
476
|
+
/**
|
|
477
|
+
* Initial values to pre-populate the form with.
|
|
478
|
+
* When an async function is provided, the form shows `loadingFallback` until the
|
|
479
|
+
* promise resolves, then resets the form with the loaded values.
|
|
480
|
+
*/
|
|
481
|
+
defaultValues?: Partial<z.infer<TSchema>> | (() => Promise<Partial<z.infer<TSchema>>>);
|
|
482
|
+
/** Component registry overrides for this form instance. */
|
|
483
|
+
components?: ComponentRegistry;
|
|
484
|
+
/** Per-field UI metadata overrides (label, placeholder, options, etc.). */
|
|
485
|
+
fields?: {
|
|
486
|
+
[K in DeepKeys<z.infer<TSchema>>]?: FieldOverride<TSchema, DeepFieldValue<z.infer<TSchema>, K>>;
|
|
487
|
+
};
|
|
488
|
+
/** Field wrapper component override for this form instance. */
|
|
489
|
+
fieldWrapper?: React.ComponentType<FieldWrapperProps>;
|
|
490
|
+
/** Layout slot overrides for this form instance. */
|
|
491
|
+
layout?: LayoutSlots;
|
|
492
|
+
/** CSS class name overrides for this form instance. */
|
|
493
|
+
classNames?: FormClassNames;
|
|
494
|
+
/** When `true`, all fields are rendered in a disabled (non-interactive) state. */
|
|
495
|
+
disabled?: boolean;
|
|
496
|
+
/** Coercion map applied before Zod validation for this form instance. */
|
|
497
|
+
coercions?: CoercionMap;
|
|
498
|
+
/** Validation message overrides for this form instance. */
|
|
499
|
+
messages?: ValidationMessages;
|
|
500
|
+
/** When set, form values are auto-saved to storage under this key */
|
|
501
|
+
persistKey?: string;
|
|
502
|
+
/** Debounce interval in ms for persistence writes (default: 300) */
|
|
503
|
+
persistDebounce?: number;
|
|
504
|
+
/** Custom storage adapter (default: localStorage) */
|
|
505
|
+
persistStorage?: PersistStorage;
|
|
506
|
+
/** Called on every value change with the current form values */
|
|
507
|
+
onValuesChange?: (values: z.infer<TSchema>) => void;
|
|
508
|
+
/** Customize hard-coded UI text (submit button, array buttons, etc.) */
|
|
509
|
+
labels?: FormLabels;
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* The resolved primitive or structural type of a schema field, as determined
|
|
514
|
+
* by introspecting the Zod schema. Used internally to decide which field
|
|
515
|
+
* component to render.
|
|
516
|
+
*/
|
|
517
|
+
type FieldType = 'string' | 'number' | 'boolean' | 'date' | 'select' | 'object' | 'array' | 'union' | 'unknown';
|
|
518
|
+
/**
|
|
519
|
+
* A predicate function that receives the current form values and returns
|
|
520
|
+
* `true` when the field should be visible, `false` when it should be hidden.
|
|
521
|
+
*
|
|
522
|
+
* @template TValues - The shape of the form values object.
|
|
523
|
+
*/
|
|
524
|
+
type FieldCondition<TValues = Record<string, unknown>> = (values: TValues) => boolean;
|
|
525
|
+
/**
|
|
526
|
+
* Dynamic field property overrides passed to `ctx.setFieldMeta()` inside a
|
|
527
|
+
* UniForm onChange handler. Each key is optional — only the properties you
|
|
528
|
+
* provide will be applied; omitted keys leave the current field state unchanged.
|
|
529
|
+
*/
|
|
530
|
+
type FieldDependencyResult = {
|
|
531
|
+
/** Override the available options for select fields */
|
|
532
|
+
options?: SelectOption[];
|
|
533
|
+
/** Dynamically show or hide the field */
|
|
534
|
+
hidden?: boolean;
|
|
535
|
+
/** Dynamically enable or disable the field */
|
|
536
|
+
disabled?: boolean;
|
|
537
|
+
/** Override the field label */
|
|
538
|
+
label?: string;
|
|
539
|
+
/** Override the placeholder text */
|
|
540
|
+
placeholder?: string;
|
|
541
|
+
/** Override the description text */
|
|
542
|
+
description?: string;
|
|
543
|
+
};
|
|
544
|
+
/**
|
|
545
|
+
* The base set of per-field UI metadata that can be provided via the `fields`
|
|
546
|
+
* prop or through Zod schema extensions (`.meta()`).
|
|
547
|
+
*
|
|
548
|
+
* `FieldMeta` extends this type with an index signature to allow arbitrary
|
|
549
|
+
* extra keys for custom component use-cases.
|
|
550
|
+
*/
|
|
551
|
+
type FieldMetaBase = {
|
|
552
|
+
/** Human-readable label rendered above the field. Falls back to a derived label from the field name. */
|
|
553
|
+
label?: string;
|
|
554
|
+
/** Placeholder text rendered inside the input when it has no value. */
|
|
555
|
+
placeholder?: string;
|
|
556
|
+
/** Helper text rendered below the field to provide additional context. */
|
|
557
|
+
description?: string;
|
|
558
|
+
/** Static list of options for `select` / enum fields. */
|
|
559
|
+
options?: SelectOption[];
|
|
560
|
+
/** Group the field under a named section in the form layout. */
|
|
561
|
+
section?: string;
|
|
562
|
+
/** Explicit render order within the form or section (lower numbers render first). */
|
|
563
|
+
order?: number;
|
|
564
|
+
/** Grid column span for multi-column layouts (e.g. `1`–`12`). */
|
|
565
|
+
span?: number;
|
|
566
|
+
/** When `true`, the field is not rendered. */
|
|
567
|
+
hidden?: boolean;
|
|
568
|
+
/** When `true`, the field is rendered but not interactive. */
|
|
569
|
+
disabled?: boolean;
|
|
570
|
+
/** Conditionally show or hide the field based on the current form values. */
|
|
571
|
+
condition?: FieldCondition;
|
|
572
|
+
/**
|
|
573
|
+
* Override the component used to render this field.
|
|
574
|
+
*
|
|
575
|
+
* - **string** — a key registered in the `ComponentRegistry` (e.g. `'autocomplete'`
|
|
576
|
+
* registered via `createAutoForm({ components: { autocomplete: MyComp } })` or the
|
|
577
|
+
* `components` prop).
|
|
578
|
+
* - **React component** — a `FieldProps`-compatible component passed inline,
|
|
579
|
+
* bypassing the registry entirely (e.g. `component: MyCustomInput`).
|
|
580
|
+
*
|
|
581
|
+
* Uses `React.ComponentType<never>` as the type parameter rather than
|
|
582
|
+
* `React.ComponentType<FieldProps>` to avoid both a circular inference error
|
|
583
|
+
* (FieldProps → FieldMeta → component → FieldProps) and a contravariance
|
|
584
|
+
* error when components typed as `(props: FieldProps) => JSX.Element` are
|
|
585
|
+
* assigned via Zod's `.meta()`, whose return type widens `meta` to `any`.
|
|
586
|
+
* `ComponentType<never>` is the widest possible assignable supertype.
|
|
587
|
+
*/
|
|
588
|
+
component?: string | React$1.ComponentType<any>;
|
|
589
|
+
/** Called when this field's value changes. Receives the new value and form control methods. May be async. */
|
|
590
|
+
onChange?: (value: unknown, form: FormMethods) => void | Promise<void>;
|
|
591
|
+
/** When `true`, rows in an array field can be reordered via move-up/move-down buttons. */
|
|
592
|
+
movable?: boolean;
|
|
593
|
+
/** When `true`, rows in an array field can be duplicated. */
|
|
594
|
+
duplicable?: boolean;
|
|
595
|
+
/** When `true`, rows in an array field can be individually collapsed. */
|
|
596
|
+
collapsible?: boolean;
|
|
597
|
+
/**
|
|
598
|
+
* Override the wrapper component rendered around this specific object or array field.
|
|
599
|
+
* Takes precedence over the global `layout.objectWrapper` / `layout.arrayWrapper` slots.
|
|
600
|
+
*
|
|
601
|
+
* The component receives the same `ObjectWrapperProps` / `ArrayWrapperProps` as the
|
|
602
|
+
* global slot — `children`, `label`, `className`, and `labelClassName`.
|
|
603
|
+
*/
|
|
604
|
+
wrapper?: React$1.ComponentType<ObjectWrapperProps | ArrayWrapperProps>;
|
|
605
|
+
};
|
|
606
|
+
/**
|
|
607
|
+
* Per-field UI metadata with an open index signature, allowing arbitrary
|
|
608
|
+
* extra keys for custom component use-cases. Extends `FieldMetaBase` with
|
|
609
|
+
* all the standard metadata properties.
|
|
610
|
+
*/
|
|
611
|
+
type FieldMeta = FieldMetaBase & {
|
|
612
|
+
[key: string]: unknown;
|
|
613
|
+
};
|
|
614
|
+
/**
|
|
615
|
+
* Common properties shared by every field variant.
|
|
616
|
+
*/
|
|
617
|
+
type FieldConfigBase = {
|
|
618
|
+
/** Dot-notated field path (e.g. `"address.street"`). */
|
|
619
|
+
name: string;
|
|
620
|
+
/** Display label for the field. */
|
|
621
|
+
label: string;
|
|
622
|
+
/** Whether the field is required by the schema. */
|
|
623
|
+
required: boolean;
|
|
624
|
+
/** Merged UI metadata for the field. */
|
|
625
|
+
meta: FieldMeta;
|
|
626
|
+
/**
|
|
627
|
+
* The original Zod schema for this field, after transparent wrappers
|
|
628
|
+
* (`optional`, `nullable`, `default`, `pipe`) have been stripped.
|
|
629
|
+
*
|
|
630
|
+
* This is a general escape hatch for custom components that need to inspect
|
|
631
|
+
* the raw schema — for example, to read union variants, access custom Zod
|
|
632
|
+
* metadata not captured by introspection, or build schema-aware validation UI.
|
|
633
|
+
*/
|
|
634
|
+
schema: z.$ZodType;
|
|
635
|
+
};
|
|
636
|
+
/**
|
|
637
|
+
* The fully resolved configuration for a single form field, produced by
|
|
638
|
+
* introspecting the Zod schema and merging any `fields` prop overrides.
|
|
639
|
+
* Consumed internally by field renderer components.
|
|
640
|
+
*
|
|
641
|
+
* This is a discriminated union on the `type` field — narrow on `type` to
|
|
642
|
+
* access the fields that are only present for specific field kinds (e.g.
|
|
643
|
+
* `children` for `"object"`, `itemConfig` for `"array"`, etc.).
|
|
644
|
+
*/
|
|
645
|
+
type FieldConfig = FieldConfigBase & ({
|
|
646
|
+
type: 'string';
|
|
647
|
+
} | {
|
|
648
|
+
type: 'number';
|
|
649
|
+
} | {
|
|
650
|
+
type: 'boolean';
|
|
651
|
+
} | {
|
|
652
|
+
type: 'date';
|
|
653
|
+
} | {
|
|
654
|
+
type: 'select';
|
|
655
|
+
/** Resolved options for `select` / enum fields. */
|
|
656
|
+
options: SelectOption[];
|
|
657
|
+
} | {
|
|
658
|
+
type: 'object';
|
|
659
|
+
/** Child field configs for nested object fields. */
|
|
660
|
+
children: FieldConfig[];
|
|
661
|
+
} | {
|
|
662
|
+
type: 'array';
|
|
663
|
+
/** Item field config describing a single row's shape. */
|
|
664
|
+
itemConfig: FieldConfig;
|
|
665
|
+
/** Minimum number of items (from `z.array().min(...)`). */
|
|
666
|
+
minItems?: number;
|
|
667
|
+
/** Maximum number of items (from `z.array().max(...)`). */
|
|
668
|
+
maxItems?: number;
|
|
669
|
+
} | {
|
|
670
|
+
type: 'union';
|
|
671
|
+
/** Variant configs for each union member. */
|
|
672
|
+
unionVariants: FieldConfig[];
|
|
673
|
+
/** Discriminator key for discriminated unions. */
|
|
674
|
+
discriminatorKey?: string;
|
|
675
|
+
} | {
|
|
676
|
+
type: 'unknown';
|
|
677
|
+
});
|
|
678
|
+
/**
|
|
679
|
+
* The props passed to every field renderer component. Provides the current
|
|
680
|
+
* value, change/blur handlers, and all resolved UI metadata needed to render
|
|
681
|
+
* a single field.
|
|
682
|
+
*/
|
|
683
|
+
interface FieldProps {
|
|
684
|
+
/** Dot-notated field path (e.g. `"address.street"`). */
|
|
685
|
+
name: string;
|
|
686
|
+
/** The current field value. */
|
|
687
|
+
value: unknown;
|
|
688
|
+
/** Callback to update the field value. */
|
|
689
|
+
onChange: (value: unknown) => void;
|
|
690
|
+
/** Callback fired when the field loses focus. */
|
|
691
|
+
onBlur: () => void;
|
|
692
|
+
/** Ref callback for registering the DOM element with `react-hook-form`. */
|
|
693
|
+
ref: RefCallBack;
|
|
694
|
+
/** Resolved display label for the field. */
|
|
695
|
+
label: string;
|
|
696
|
+
/** Placeholder text for the input. */
|
|
697
|
+
placeholder?: string;
|
|
698
|
+
/** Helper text rendered below the field. */
|
|
699
|
+
description?: string;
|
|
700
|
+
/** Validation error message for the field. */
|
|
701
|
+
error?: string;
|
|
702
|
+
/** Whether the field is required by the schema. */
|
|
703
|
+
required: boolean;
|
|
704
|
+
/** When `true`, the field is rendered but not interactive. */
|
|
705
|
+
disabled?: boolean;
|
|
706
|
+
/** Resolved options for `select` / enum fields. */
|
|
707
|
+
options?: SelectOption[];
|
|
708
|
+
/** Full field metadata, including any custom keys. */
|
|
709
|
+
meta: FieldMeta;
|
|
710
|
+
/**
|
|
711
|
+
* The original Zod schema for this field (after transparent wrappers are stripped).
|
|
712
|
+
* Use this as an escape hatch when you need capabilities beyond what `FieldConfig`
|
|
713
|
+
* exposes — e.g. inspecting union variants, accessing custom Zod refinements, etc.
|
|
714
|
+
*/
|
|
715
|
+
schema: z.$ZodType;
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* A per-field override entry used in the AutoFormProps `fields` prop.
|
|
719
|
+
* The `onChange` callback is typed to the specific schema's inferred value
|
|
720
|
+
* type, providing full IDE autocomplete.
|
|
721
|
+
*/
|
|
722
|
+
type FieldOverride<TSchema extends z.$ZodObject = z.$ZodObject, TValue = unknown> = Partial<FieldMetaBase> & {
|
|
723
|
+
/** Conditionally show or hide the field based on the current form values. */
|
|
724
|
+
condition?: FieldCondition<z.infer<TSchema>>;
|
|
725
|
+
/** Called when this field's value changes. Receives the new value and form control methods. May be async. */
|
|
726
|
+
onChange?: (value: TValue, form: FormMethods<z.infer<TSchema>>) => void | Promise<void>;
|
|
727
|
+
[key: string]: unknown;
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
export type { AutoFormProps as A, ComponentRegistry as C, DeepKeys as D, FieldMetaBase as F, LayoutSlots as L, ObjectWrapperProps as O, PersistStorage as P, ResolvedLayoutSlots as R, SectionConfig as S, ValidationMessages as V, FieldConfig as a, AutoFormHandle as b, FieldProps as c, FieldWrapperProps as d, ArrayButtonProps as e, ArrayCollapseButtonProps as f, ArrayFieldLayoutProps as g, ArrayRowLayoutProps as h, ArrayWrapperProps as i, AutoFormConfig as j, FormMethods as k, FieldDependencyResult as l, DeepFieldValue as m, FormClassNames as n, CoercionMap as o, FormLabels as p, ArrayButtonSlots as q, FieldCondition as r, FieldMeta as s, FieldOverride as t, FieldType as u, FormWrapperProps as v, ResolvedArrayButtonSlots as w, SectionWrapperProps as x, SelectOption as y, SubmitButtonProps as z };
|