@classytic/formkit 1.3.1 → 1.5.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/CHANGELOG.md +73 -0
- package/README.md +166 -20
- package/dist/index.d.mts +577 -164
- package/dist/index.mjs +1131 -294
- package/dist/server.d.mts +472 -151
- package/dist/server.mjs +593 -98
- package/package.json +116 -113
package/dist/server.d.mts
CHANGED
|
@@ -31,7 +31,7 @@ declare function cn(...inputs: ClassValue[]): string;
|
|
|
31
31
|
* Field type identifier.
|
|
32
32
|
* Can be built-in types or custom string identifiers.
|
|
33
33
|
*/
|
|
34
|
-
type FieldType = "text" | "email" | "password" | "number" | "tel" | "url" | "textarea" | "select" | "checkbox" | "radio" | "switch" | "date" | "time" | "datetime" | "file" | "hidden" | "group" | "array" | "custom" | (string & {});
|
|
34
|
+
type FieldType = "text" | "email" | "password" | "number" | "tel" | "phone" | "url" | "textarea" | "slug" | "select" | "combobox" | "multiselect" | "dependentSelect" | "checkbox" | "radio" | "switch" | "date" | "time" | "datetime" | "rich-text" | "color" | "rating" | "tags" | "json" | "file" | "hidden" | "group" | "array" | "custom" | (string & {});
|
|
35
35
|
/**
|
|
36
36
|
* Layout type identifier.
|
|
37
37
|
*/
|
|
@@ -93,12 +93,55 @@ interface FieldOptionGroup<TValue = string> {
|
|
|
93
93
|
/** Whether group is disabled */
|
|
94
94
|
disabled?: boolean;
|
|
95
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Object form for length/range validation rules with a custom message.
|
|
98
|
+
*/
|
|
99
|
+
interface ValidationRuleObject<TValue = number> {
|
|
100
|
+
value: TValue;
|
|
101
|
+
message: string;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Object form for pattern validation with a custom message.
|
|
105
|
+
*/
|
|
106
|
+
interface PatternRuleObject {
|
|
107
|
+
/** Regex string (will be compiled with `new RegExp(regex)`) */
|
|
108
|
+
regex: string;
|
|
109
|
+
/** Custom error message */
|
|
110
|
+
message: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* AI-friendly metadata attached to any field.
|
|
114
|
+
* Consumed by LLM coding assistants, documentation generators, and
|
|
115
|
+
* schema-introspection tools — never by the form renderer itself.
|
|
116
|
+
*/
|
|
117
|
+
interface FieldMeta {
|
|
118
|
+
/** Human-readable description of what this field collects */
|
|
119
|
+
description?: string;
|
|
120
|
+
/** Representative example value (for documentation / AI context) */
|
|
121
|
+
example?: unknown;
|
|
122
|
+
/** Logical category for grouping fields in documentation or tooling */
|
|
123
|
+
category?: string;
|
|
124
|
+
/** Arbitrary tags for filtering, search, or feature-flagging */
|
|
125
|
+
tags?: string[];
|
|
126
|
+
/** Whether this field is considered PII */
|
|
127
|
+
pii?: boolean;
|
|
128
|
+
/** Arbitrary extension point — anything extra you want to carry */
|
|
129
|
+
[key: string]: unknown;
|
|
130
|
+
}
|
|
96
131
|
/**
|
|
97
132
|
* Base field configuration shared by all field types.
|
|
98
133
|
* @template TFieldValues - Form field values type for type-safe field names
|
|
99
134
|
*/
|
|
100
135
|
interface BaseField<TFieldValues extends FieldValues = FieldValues> {
|
|
101
|
-
/**
|
|
136
|
+
/**
|
|
137
|
+
* Field name — a path into TFieldValues (e.g. `"email"`, `"address.street"`).
|
|
138
|
+
*
|
|
139
|
+
* Accepts any string so that:
|
|
140
|
+
* - Namespaced sections can use relative names (`"street"` → prefixed to `"address.street"`)
|
|
141
|
+
* - Group/array `itemFields` can use relative names (`"email"` → prefixed at render time)
|
|
142
|
+
*
|
|
143
|
+
* Use `field.for<T>()` builder for call-site enforcement that names are valid paths.
|
|
144
|
+
*/
|
|
102
145
|
name: Path<TFieldValues> | (string & {});
|
|
103
146
|
/** Field type identifier */
|
|
104
147
|
type: FieldType;
|
|
@@ -118,6 +161,13 @@ interface BaseField<TFieldValues extends FieldValues = FieldValues> {
|
|
|
118
161
|
variant?: Variant;
|
|
119
162
|
/** Whether field should span full width in grid */
|
|
120
163
|
fullWidth?: boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Span N columns of the section grid (e.g. `2` of a 3-col section). `1` (or
|
|
166
|
+
* unset) is the default single cell; `fullWidth` still means "span the whole
|
|
167
|
+
* row" and takes precedence. Applied as an inline `grid-column: span N` so it
|
|
168
|
+
* works regardless of the host's Tailwind content scan.
|
|
169
|
+
*/
|
|
170
|
+
colSpan?: number;
|
|
121
171
|
/** Custom CSS class name */
|
|
122
172
|
className?: string;
|
|
123
173
|
/**
|
|
@@ -129,18 +179,41 @@ interface BaseField<TFieldValues extends FieldValues = FieldValues> {
|
|
|
129
179
|
defaultValue?: unknown;
|
|
130
180
|
/** Options for select/radio/checkbox fields */
|
|
131
181
|
options?: (FieldOption | FieldOptionGroup)[];
|
|
132
|
-
/**
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
182
|
+
/**
|
|
183
|
+
* Minimum value (for number/date fields).
|
|
184
|
+
* Pass an object `{ value, message }` to provide a custom error message.
|
|
185
|
+
*/
|
|
186
|
+
min?: number | string | ValidationRuleObject<number | string>;
|
|
187
|
+
/**
|
|
188
|
+
* Maximum value (for number/date fields).
|
|
189
|
+
* Pass an object `{ value, message }` to provide a custom error message.
|
|
190
|
+
*/
|
|
191
|
+
max?: number | string | ValidationRuleObject<number | string>;
|
|
136
192
|
/** Step value (for number fields) */
|
|
137
193
|
step?: number;
|
|
138
|
-
/**
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
194
|
+
/**
|
|
195
|
+
* Pattern for validation.
|
|
196
|
+
* Pass a regex string or `{ regex, message }` for a custom error message.
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```ts
|
|
200
|
+
* // simple
|
|
201
|
+
* pattern: "^[a-z]+$"
|
|
202
|
+
* // with custom message
|
|
203
|
+
* pattern: { regex: "^[a-z]+$", message: "Only lowercase letters allowed" }
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
pattern?: string | PatternRuleObject;
|
|
207
|
+
/**
|
|
208
|
+
* Minimum length.
|
|
209
|
+
* Pass an object `{ value, message }` to provide a custom error message.
|
|
210
|
+
*/
|
|
211
|
+
minLength?: number | ValidationRuleObject<number>;
|
|
212
|
+
/**
|
|
213
|
+
* Maximum length.
|
|
214
|
+
* Pass an object `{ value, message }` to provide a custom error message.
|
|
215
|
+
*/
|
|
216
|
+
maxLength?: number | ValidationRuleObject<number>;
|
|
144
217
|
/** Number of rows (for textarea) */
|
|
145
218
|
rows?: number;
|
|
146
219
|
/** Multiple selection (for select/file) */
|
|
@@ -156,18 +229,41 @@ interface BaseField<TFieldValues extends FieldValues = FieldValues> {
|
|
|
156
229
|
/**
|
|
157
230
|
* Dynamic options loaded based on current form values.
|
|
158
231
|
* Useful for dependent selects (e.g., state depends on country).
|
|
232
|
+
*
|
|
233
|
+
* Receives an `AbortSignal` in the second arg — forward it to `fetch` (or
|
|
234
|
+
* abort your own request on it) so a superseded / unmounted load is cancelled
|
|
235
|
+
* instead of racing to completion:
|
|
236
|
+
*
|
|
237
|
+
* ```ts
|
|
238
|
+
* loadOptions: (values, { signal }) =>
|
|
239
|
+
* fetch(`/api/cities?country=${values.country}`, { signal }).then(r => r.json())
|
|
240
|
+
* ```
|
|
159
241
|
*/
|
|
160
|
-
loadOptions?: (formValues: Partial<TFieldValues
|
|
242
|
+
loadOptions?: (formValues: Partial<TFieldValues>, options?: {
|
|
243
|
+
signal: AbortSignal;
|
|
244
|
+
}) => Promise<(FieldOption | FieldOptionGroup)[]> | (FieldOption | FieldOptionGroup)[];
|
|
161
245
|
/**
|
|
162
246
|
* Error callback for loadOptions failures.
|
|
163
247
|
* Called when loadOptions rejects. Defaults to console.error.
|
|
164
248
|
*/
|
|
165
249
|
onLoadError?: (error: unknown) => void;
|
|
166
250
|
/**
|
|
167
|
-
*
|
|
168
|
-
*
|
|
251
|
+
* Memoize async `loadOptions` results per set of watched values, so toggling
|
|
252
|
+
* a dependency back and forth (e.g. re-selecting a country) reuses the last
|
|
253
|
+
* fetch instead of hitting the API again. Off by default — enable only when
|
|
254
|
+
* the options are stable for a given input, since the cache lives for the
|
|
255
|
+
* field's lifetime and won't see server-side changes. Bounded (LRU-ish) so it
|
|
256
|
+
* can't grow without limit.
|
|
257
|
+
*/
|
|
258
|
+
cacheOptions?: boolean;
|
|
259
|
+
/**
|
|
260
|
+
* Sub-fields for `group` and `array` field types.
|
|
261
|
+
*
|
|
262
|
+
* These fields use **relative** names (`"street"`, `"email"`) — FormGenerator
|
|
263
|
+
* prefixes them with the parent field name at render time (`"address.street"`).
|
|
264
|
+
* They are intentionally untyped to TFieldValues for this reason.
|
|
169
265
|
*/
|
|
170
|
-
itemFields?: BaseField
|
|
266
|
+
itemFields?: BaseField[];
|
|
171
267
|
/**
|
|
172
268
|
* Custom render function to override the component registry for this specific field.
|
|
173
269
|
* Completely bypasses the globally registered FieldComponent for this type.
|
|
@@ -176,15 +272,22 @@ interface BaseField<TFieldValues extends FieldValues = FieldValues> {
|
|
|
176
272
|
/**
|
|
177
273
|
* Cross-field validation function.
|
|
178
274
|
* Receives the field value and all form values for cross-field checks.
|
|
179
|
-
* Return `true` for valid,
|
|
275
|
+
* Return `true` for valid, a string error message for invalid, or a Promise of either
|
|
276
|
+
* for async validation (e.g., checking server-side uniqueness).
|
|
180
277
|
*
|
|
181
278
|
* @example
|
|
182
279
|
* ```ts
|
|
183
280
|
* validate: (value, formValues) =>
|
|
184
281
|
* value > formValues.minPrice || "Must be greater than min price"
|
|
282
|
+
*
|
|
283
|
+
* // Async example
|
|
284
|
+
* validate: async (value) => {
|
|
285
|
+
* const taken = await checkUsernameAvailability(value as string);
|
|
286
|
+
* return taken ? "Username already taken" : true;
|
|
287
|
+
* }
|
|
185
288
|
* ```
|
|
186
289
|
*/
|
|
187
|
-
validate?: (value: unknown, formValues: Partial<TFieldValues>) => string | true
|
|
290
|
+
validate?: (value: unknown, formValues: Partial<TFieldValues>) => string | true | Promise<string | true>;
|
|
188
291
|
/**
|
|
189
292
|
* Dependencies for optimizing conditionally rendered fields.
|
|
190
293
|
* Allows specifying specific field names to watch, preventing full form re-renders.
|
|
@@ -192,6 +295,32 @@ interface BaseField<TFieldValues extends FieldValues = FieldValues> {
|
|
|
192
295
|
watchNames?: Path<TFieldValues> | Path<TFieldValues>[];
|
|
193
296
|
/** Additional field-specific props for custom components */
|
|
194
297
|
customProps?: Record<string, unknown>;
|
|
298
|
+
/**
|
|
299
|
+
* AI / agent-friendly metadata for this field.
|
|
300
|
+
*
|
|
301
|
+
* Provides hints that help LLM coding assistants generate correct field
|
|
302
|
+
* configs without needing to inspect the schema at runtime.
|
|
303
|
+
*
|
|
304
|
+
* @example
|
|
305
|
+
* ```ts
|
|
306
|
+
* field.text("companyName", "Company", {
|
|
307
|
+
* meta: {
|
|
308
|
+
* description: "Legal entity name of the organization",
|
|
309
|
+
* example: "Acme Corp",
|
|
310
|
+
* category: "identity",
|
|
311
|
+
* tags: ["crm", "required-for-billing"],
|
|
312
|
+
* }
|
|
313
|
+
* })
|
|
314
|
+
* ```
|
|
315
|
+
*/
|
|
316
|
+
meta?: FieldMeta;
|
|
317
|
+
/**
|
|
318
|
+
* Escape hatch for adapter-specific or custom props.
|
|
319
|
+
* Allows passing arbitrary props directly on the field object so they
|
|
320
|
+
* flow through the adapter spread (`{...field}`) without needing `customProps`.
|
|
321
|
+
* Intentionally broad to support diverse UI component libraries.
|
|
322
|
+
*/
|
|
323
|
+
[key: string]: unknown;
|
|
195
324
|
}
|
|
196
325
|
/**
|
|
197
326
|
* Props passed to field components.
|
|
@@ -237,13 +366,68 @@ interface FieldComponentProps<TFieldValues extends FieldValues = FieldValues> ex
|
|
|
237
366
|
invalid: boolean;
|
|
238
367
|
isDirty: boolean;
|
|
239
368
|
isTouched: boolean;
|
|
240
|
-
isValidating: boolean;
|
|
369
|
+
isValidating: boolean; /** True after the enclosing form's submit handler has been called at least once. */
|
|
370
|
+
isSubmitted: boolean;
|
|
241
371
|
error?: FieldError;
|
|
242
372
|
};
|
|
243
|
-
/**
|
|
373
|
+
/**
|
|
374
|
+
* Generated field ID for label-input association (e.g. `formkit-field-email`).
|
|
375
|
+
* Use as `id` on the input element and `htmlFor` on the `<label>`.
|
|
376
|
+
*/
|
|
244
377
|
fieldId: string;
|
|
378
|
+
/**
|
|
379
|
+
* Generated error container ID for ARIA association (e.g. `formkit-field-email-error`).
|
|
380
|
+
* Use as `id` on the error message element and as the value for `aria-errormessage`
|
|
381
|
+
* (preferred) or `aria-describedby` (broader support) on the input.
|
|
382
|
+
*
|
|
383
|
+
* @example
|
|
384
|
+
* ```tsx
|
|
385
|
+
* <input
|
|
386
|
+
* id={fieldId}
|
|
387
|
+
* aria-invalid={shouldShowError || undefined}
|
|
388
|
+
* aria-errormessage={shouldShowError ? errorId : undefined}
|
|
389
|
+
* />
|
|
390
|
+
* <p id={errorId} role="alert" aria-live="polite">
|
|
391
|
+
* {shouldShowError ? error?.message : null}
|
|
392
|
+
* </p>
|
|
393
|
+
* ```
|
|
394
|
+
*/
|
|
395
|
+
errorId: string;
|
|
396
|
+
/**
|
|
397
|
+
* Whether to display the field error right now.
|
|
398
|
+
*
|
|
399
|
+
* Aligns with the CSS `:user-invalid` timing model: `true` only after the
|
|
400
|
+
* user has interacted with the field (blur) **or** the form has been
|
|
401
|
+
* submitted. This prevents premature "required" errors on untouched fields.
|
|
402
|
+
*
|
|
403
|
+
* Use this — not `!!error` — to drive `aria-invalid`, error message
|
|
404
|
+
* visibility, and destructive ring/border styles.
|
|
405
|
+
*
|
|
406
|
+
* @example
|
|
407
|
+
* ```tsx
|
|
408
|
+
* <input aria-invalid={shouldShowError || undefined} />
|
|
409
|
+
* {shouldShowError && <p id={errorId} role="alert">{error?.message}</p>}
|
|
410
|
+
* ```
|
|
411
|
+
*/
|
|
412
|
+
shouldShowError: boolean;
|
|
245
413
|
/** Whether dynamic options are currently loading */
|
|
246
414
|
isLoading?: boolean;
|
|
415
|
+
/**
|
|
416
|
+
* Pre-computed react-hook-form validation rules for this field.
|
|
417
|
+
* Equivalent to calling `buildValidationRules(field)` — provided here so
|
|
418
|
+
* adapter components can pass `rules={rules}` directly to `<Controller>`
|
|
419
|
+
* without importing or calling `buildValidationRules` themselves.
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* ```tsx
|
|
423
|
+
* function TextInput({ field, control, rules }: FieldComponentProps) {
|
|
424
|
+
* return (
|
|
425
|
+
* <Controller name={field.name} control={control} rules={rules} render={...} />
|
|
426
|
+
* );
|
|
427
|
+
* }
|
|
428
|
+
* ```
|
|
429
|
+
*/
|
|
430
|
+
rules: ValidationRules;
|
|
247
431
|
}
|
|
248
432
|
/**
|
|
249
433
|
* Validation rules compatible with react-hook-form's RegisterOptions.
|
|
@@ -289,6 +473,17 @@ interface Section<TFieldValues extends FieldValues = FieldValues> {
|
|
|
289
473
|
collapsible?: boolean;
|
|
290
474
|
/** Default collapsed state */
|
|
291
475
|
defaultCollapsed?: boolean;
|
|
476
|
+
/**
|
|
477
|
+
* Defer rendering of this section until it scrolls near the viewport.
|
|
478
|
+
* Applies `content-visibility: auto` + `contain-intrinsic-size` to the
|
|
479
|
+
* section container, skipping layout/paint work while off-screen.
|
|
480
|
+
*
|
|
481
|
+
* **Only use for sections that are below the initial fold.** Applying this
|
|
482
|
+
* to above-fold sections has no benefit and slightly increases overhead.
|
|
483
|
+
*
|
|
484
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/content-visibility
|
|
485
|
+
*/
|
|
486
|
+
deferRender?: boolean;
|
|
292
487
|
}
|
|
293
488
|
/**
|
|
294
489
|
* Props passed to section render function.
|
|
@@ -316,6 +511,12 @@ interface SectionLayoutProps {
|
|
|
316
511
|
collapsible?: boolean;
|
|
317
512
|
/** Default collapsed state */
|
|
318
513
|
defaultCollapsed?: boolean;
|
|
514
|
+
/**
|
|
515
|
+
* When true the section is below the initial fold and should defer
|
|
516
|
+
* browser layout/paint work until it nears the viewport.
|
|
517
|
+
* Layout components may apply `content-visibility: auto` here.
|
|
518
|
+
*/
|
|
519
|
+
deferRender?: boolean;
|
|
319
520
|
/** Children content */
|
|
320
521
|
children: ReactNode;
|
|
321
522
|
}
|
|
@@ -350,6 +551,12 @@ type LayoutComponentProps = SectionLayoutProps | GridLayoutProps | DefaultLayout
|
|
|
350
551
|
* @template TFieldValues - Form field values type for type-safe schemas
|
|
351
552
|
*/
|
|
352
553
|
interface FormSchema<TFieldValues extends FieldValues = FieldValues> {
|
|
554
|
+
/** Optional schema identifier — useful for serialization, analytics, and AI context */
|
|
555
|
+
id?: string;
|
|
556
|
+
/** Human-readable form title (AI / documentation use) */
|
|
557
|
+
title?: string;
|
|
558
|
+
/** Human-readable description of the form's purpose */
|
|
559
|
+
description?: string;
|
|
353
560
|
/** Form sections */
|
|
354
561
|
sections: Section<TFieldValues>[];
|
|
355
562
|
}
|
|
@@ -402,6 +609,7 @@ declare function defineSection<TFieldValues extends FieldValues = FieldValues>(s
|
|
|
402
609
|
/**
|
|
403
610
|
* Extracts default values from a form schema.
|
|
404
611
|
* Walks all sections and fields, respecting nameSpace prefixes and group nesting.
|
|
612
|
+
* Array fields default to `[]` when no explicit `defaultValue` is provided.
|
|
405
613
|
*
|
|
406
614
|
* @example
|
|
407
615
|
* ```ts
|
|
@@ -410,11 +618,62 @@ declare function defineSection<TFieldValues extends FieldValues = FieldValues>(s
|
|
|
410
618
|
* ```
|
|
411
619
|
*/
|
|
412
620
|
declare function extractDefaultValues<TFieldValues extends FieldValues = FieldValues>(schema: FormSchema<TFieldValues>): Partial<TFieldValues>;
|
|
621
|
+
interface SchemaIssue {
|
|
622
|
+
/** Where the issue is, e.g. `sections[0].fields[2]` or `sections[1]`. */
|
|
623
|
+
path: string;
|
|
624
|
+
code: "missing-name" | "missing-type" | "duplicate-name" | "itemfields-on-noncontainer" | "empty-container" | "unknown-operator";
|
|
625
|
+
/** `error` = will misbehave at runtime; `warning` = suspicious but tolerated. */
|
|
626
|
+
severity: "error" | "warning";
|
|
627
|
+
message: string;
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Structurally validate a form schema and return a list of issues (empty ⇒ OK).
|
|
631
|
+
* Server-safe (no hooks/DOM), so you can run it when a schema is loaded from a
|
|
632
|
+
* DB, in a test, or in a dev boot check. It validates SHAPE, not your component
|
|
633
|
+
* registry — an unknown field `type` is a registry concern, not a schema error.
|
|
634
|
+
*
|
|
635
|
+
* Checks: missing `name`/`type`, duplicate names (namespace-aware), `itemFields`
|
|
636
|
+
* on a non-container type, containers with no `itemFields`, and unknown DSL
|
|
637
|
+
* condition operators.
|
|
638
|
+
*/
|
|
639
|
+
declare function validateSchema(schema: FormSchema): SchemaIssue[];
|
|
640
|
+
/**
|
|
641
|
+
* Build a default-value object for a flat list of fields — used to seed a new
|
|
642
|
+
* array item (or a group) from its `itemFields`.
|
|
643
|
+
*
|
|
644
|
+
* Recurses into nested `group` children (→ nested object) and seeds nested
|
|
645
|
+
* `array` children as `[]`, so appending an item never leaves a deep sub-field
|
|
646
|
+
* `undefined`. That matters because a missing deep field can trip a resolver
|
|
647
|
+
* (zod et al.) into a spurious "required" error the moment the row is added.
|
|
648
|
+
* Leaf fields without an explicit `defaultValue` seed to `""` (a controlled
|
|
649
|
+
* empty value RHF is happy with).
|
|
650
|
+
*/
|
|
651
|
+
declare function buildFieldDefaults(fields: BaseField[] | undefined): Record<string, unknown>;
|
|
652
|
+
/**
|
|
653
|
+
* Deep-merge `override` onto `base` with default-values semantics: nested
|
|
654
|
+
* plain objects merge recursively; arrays, primitives, and class instances
|
|
655
|
+
* (Date, File, …) from `override` replace wholesale.
|
|
656
|
+
*
|
|
657
|
+
* This is the merge `useFormKit` applies between schema-extracted defaults and
|
|
658
|
+
* caller-provided `defaultValues`. Exported so wrappers that re-seed a form at
|
|
659
|
+
* runtime (e.g. an edit sheet swapping entities) can reproduce the exact same
|
|
660
|
+
* merge for `form.reset(...)`:
|
|
661
|
+
*
|
|
662
|
+
* @example
|
|
663
|
+
* ```ts
|
|
664
|
+
* const merged = mergeDefaultValues(extractDefaultValues(schema), entity);
|
|
665
|
+
* form.reset(merged);
|
|
666
|
+
* ```
|
|
667
|
+
*/
|
|
668
|
+
declare function mergeDefaultValues(base: Record<string, unknown>, override: Record<string, unknown>): Record<string, unknown>;
|
|
413
669
|
/**
|
|
414
670
|
* Generates react-hook-form `RegisterOptions`-compatible validation rules
|
|
415
671
|
* from a field's schema props. Maps `required`, `min`, `max`, `minLength`,
|
|
416
672
|
* `maxLength`, `pattern`, and `validate` to RHF rules.
|
|
417
673
|
*
|
|
674
|
+
* Supports both shorthand scalars and `{ value, message }` objects for all
|
|
675
|
+
* numeric/length rules, and `{ regex, message }` for pattern.
|
|
676
|
+
*
|
|
418
677
|
* @example
|
|
419
678
|
* ```tsx
|
|
420
679
|
* import { buildValidationRules } from '@classytic/formkit';
|
|
@@ -426,155 +685,150 @@ declare function extractDefaultValues<TFieldValues extends FieldValues = FieldVa
|
|
|
426
685
|
* ```
|
|
427
686
|
*/
|
|
428
687
|
declare function buildValidationRules<TFieldValues extends FieldValues = FieldValues>(field: BaseField<TFieldValues>): ValidationRules;
|
|
688
|
+
/** Returns true for fields that carry an `options` array (select, radio, etc.) */
|
|
689
|
+
declare function isChoiceField(field: BaseField): boolean;
|
|
690
|
+
/** Returns true for free-text input fields */
|
|
691
|
+
declare function isTextField(field: BaseField): boolean;
|
|
692
|
+
/** Returns true for numeric input fields */
|
|
693
|
+
declare function isNumericField(field: BaseField): boolean;
|
|
694
|
+
/** Returns true for date / time fields */
|
|
695
|
+
declare function isDateField(field: BaseField): boolean;
|
|
696
|
+
/** Returns true for structural fields that contain sub-fields (`itemFields`) */
|
|
697
|
+
declare function isContainerField(field: BaseField): boolean;
|
|
698
|
+
/** Returns true for array fields that render a repeatable list */
|
|
699
|
+
declare function isArrayField(field: BaseField): boolean;
|
|
700
|
+
/** Returns true for fields that load options asynchronously */
|
|
701
|
+
declare function isDynamicField(field: BaseField): boolean;
|
|
702
|
+
/** Returns true for fields with conditional rendering */
|
|
703
|
+
declare function isConditionalField(field: BaseField): boolean;
|
|
704
|
+
/**
|
|
705
|
+
* Merge two or more schemas into one, concatenating their sections.
|
|
706
|
+
*
|
|
707
|
+
* @example
|
|
708
|
+
* ```ts
|
|
709
|
+
* const full = mergeSchemas(personalSchema, addressSchema, billingSchema);
|
|
710
|
+
* ```
|
|
711
|
+
*/
|
|
712
|
+
declare function mergeSchemas<TFieldValues extends FieldValues = FieldValues>(...schemas: FormSchema<TFieldValues>[]): FormSchema<TFieldValues>;
|
|
713
|
+
/**
|
|
714
|
+
* Add fields to a section identified by `sectionId`.
|
|
715
|
+
* Returns a new schema — the original is not mutated.
|
|
716
|
+
*
|
|
717
|
+
* @example
|
|
718
|
+
* ```ts
|
|
719
|
+
* const extended = extendSection(schema, "personal", [
|
|
720
|
+
* field.text("middleName", "Middle Name"),
|
|
721
|
+
* ]);
|
|
722
|
+
* ```
|
|
723
|
+
*/
|
|
724
|
+
declare function extendSection<TFieldValues extends FieldValues = FieldValues>(schema: FormSchema<TFieldValues>, sectionId: string, fields: BaseField<TFieldValues>[], position?: "start" | "end"): FormSchema<TFieldValues>;
|
|
725
|
+
/**
|
|
726
|
+
* Create a new schema that includes only the named fields.
|
|
727
|
+
*
|
|
728
|
+
* @example
|
|
729
|
+
* ```ts
|
|
730
|
+
* const slim = pickFields(schema, ["email", "password"]);
|
|
731
|
+
* ```
|
|
732
|
+
*/
|
|
733
|
+
declare function pickFields<TFieldValues extends FieldValues = FieldValues>(schema: FormSchema<TFieldValues>, names: string[]): FormSchema<TFieldValues>;
|
|
734
|
+
/**
|
|
735
|
+
* Create a new schema that excludes the named fields.
|
|
736
|
+
*
|
|
737
|
+
* @example
|
|
738
|
+
* ```ts
|
|
739
|
+
* const withoutInternal = omitFields(schema, ["__id", "__createdAt"]);
|
|
740
|
+
* ```
|
|
741
|
+
*/
|
|
742
|
+
declare function omitFields<TFieldValues extends FieldValues = FieldValues>(schema: FormSchema<TFieldValues>, names: string[]): FormSchema<TFieldValues>;
|
|
743
|
+
/**
|
|
744
|
+
* Collect every field from every section into a flat array.
|
|
745
|
+
* Useful for validation, documentation, and AI schema introspection.
|
|
746
|
+
*
|
|
747
|
+
* @example
|
|
748
|
+
* ```ts
|
|
749
|
+
* const allFields = flattenSchema(schema);
|
|
750
|
+
* const required = allFields.filter(f => f.required);
|
|
751
|
+
* ```
|
|
752
|
+
*/
|
|
753
|
+
declare function flattenSchema<TFieldValues extends FieldValues = FieldValues>(schema: FormSchema<TFieldValues>): BaseField<TFieldValues>[];
|
|
429
754
|
//#endregion
|
|
430
755
|
//#region src/builders.d.ts
|
|
431
756
|
/**
|
|
432
|
-
* Additional field props
|
|
757
|
+
* Additional field props accepted by builder helpers.
|
|
433
758
|
* Accepts all BaseField properties except `name`, `type`, and `label`
|
|
434
|
-
* which are
|
|
759
|
+
* which are provided by the builder method directly.
|
|
435
760
|
*/
|
|
436
|
-
type FieldProps<TFieldValues extends FieldValues = FieldValues> = Omit<BaseField<TFieldValues>, "name" | "type" | "label"
|
|
437
|
-
/** Grid column class (e.g., "col-span-2") */gridColumn?: string; /** Icon for the left side of input */
|
|
438
|
-
iconLeft?: ReactNode; /** Icon for the right side of input */
|
|
439
|
-
iconRight?: ReactNode; /** Additional custom props */
|
|
440
|
-
[key: string]: unknown;
|
|
441
|
-
};
|
|
761
|
+
type FieldProps<TFieldValues extends FieldValues = FieldValues> = Omit<BaseField<TFieldValues>, "name" | "type" | "label">;
|
|
442
762
|
/**
|
|
443
763
|
* Section configuration props.
|
|
444
764
|
*/
|
|
445
765
|
interface SectionProps<TFieldValues extends FieldValues = FieldValues> extends Omit<Section<TFieldValues>, "id" | "title" | "fields" | "cols"> {
|
|
446
766
|
cols?: number;
|
|
447
767
|
}
|
|
448
|
-
/**
|
|
449
|
-
* Render function for custom field types.
|
|
450
|
-
*/
|
|
451
|
-
type CustomRenderFn = (props: {
|
|
452
|
-
control: Control<FieldValues>;
|
|
453
|
-
disabled?: boolean;
|
|
454
|
-
error?: FieldError;
|
|
455
|
-
}) => ReactNode;
|
|
456
768
|
/**
|
|
457
769
|
* Type-safe field builder helpers for schema-driven forms.
|
|
458
770
|
*
|
|
459
|
-
*
|
|
460
|
-
*
|
|
771
|
+
* All methods are generic over TFieldValues, defaulting to FieldValues (any string)
|
|
772
|
+
* when no type argument is provided. Specify the generic to enforce that field
|
|
773
|
+
* names are valid paths in your form values type.
|
|
774
|
+
*
|
|
775
|
+
* For fully-typed schemas where every field name is checked, prefer
|
|
776
|
+
* `field.for<MyForm>()` which fixes the generic once for the whole schema:
|
|
461
777
|
*
|
|
462
778
|
* @example
|
|
463
779
|
* ```ts
|
|
464
|
-
*
|
|
780
|
+
* // Untyped — any string accepted (backwards compatible)
|
|
781
|
+
* field.text("email", "Email")
|
|
465
782
|
*
|
|
466
|
-
*
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
*
|
|
470
|
-
*
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
* { label: "User", value: "user" },
|
|
474
|
-
* ]),
|
|
475
|
-
* ], { cols: 2 }),
|
|
476
|
-
* ],
|
|
477
|
-
* };
|
|
783
|
+
* // Per-call generic — name is checked against MyForm
|
|
784
|
+
* field.text<MyForm>("email", "Email")
|
|
785
|
+
*
|
|
786
|
+
* // Typed factory — name checked on every call without repeating the generic
|
|
787
|
+
* const f = field.for<MyForm>()
|
|
788
|
+
* f.text("email", "Email") // ✓
|
|
789
|
+
* f.text("typo", "Email") // ✗ TypeScript error
|
|
478
790
|
* ```
|
|
479
791
|
*/
|
|
480
792
|
declare const field: {
|
|
481
|
-
/**
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
/**
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
/**
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
/**
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
number: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
505
|
-
/**
|
|
506
|
-
* Textarea field with default 3 rows.
|
|
507
|
-
*/
|
|
508
|
-
textarea: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
509
|
-
/**
|
|
510
|
-
* Select dropdown field.
|
|
511
|
-
*/
|
|
512
|
-
select: (name: string, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps) => BaseField;
|
|
513
|
-
/**
|
|
514
|
-
* Searchable combobox field.
|
|
515
|
-
*/
|
|
516
|
-
combobox: (name: string, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps) => BaseField;
|
|
517
|
-
/**
|
|
518
|
-
* Multi-select field (tag choice).
|
|
519
|
-
*/
|
|
520
|
-
multiselect: (name: string, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps) => BaseField;
|
|
521
|
-
/**
|
|
522
|
-
* Dependent select field that reacts to parent field changes.
|
|
523
|
-
*/
|
|
524
|
-
dependentSelect: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
525
|
-
/**
|
|
526
|
-
* Switch/toggle field.
|
|
527
|
-
*/
|
|
528
|
-
switch: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
529
|
-
/**
|
|
530
|
-
* Boolean field (alias for switch).
|
|
531
|
-
*/
|
|
532
|
-
boolean: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
533
|
-
/**
|
|
534
|
-
* Checkbox field.
|
|
535
|
-
*/
|
|
536
|
-
checkbox: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
537
|
-
/**
|
|
538
|
-
* Radio button group field.
|
|
539
|
-
*/
|
|
540
|
-
radio: (name: string, label: string, options: FieldOption[], props?: FieldProps) => BaseField;
|
|
541
|
-
/**
|
|
542
|
-
* Date picker field.
|
|
543
|
-
*/
|
|
544
|
-
date: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
545
|
-
/**
|
|
546
|
-
* Tag input field with default placeholder.
|
|
547
|
-
*/
|
|
548
|
-
tags: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
549
|
-
/**
|
|
550
|
-
* Slug field with auto-generation from source value.
|
|
551
|
-
*/
|
|
552
|
-
slug: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
553
|
-
/**
|
|
554
|
-
* File upload field.
|
|
555
|
-
*/
|
|
556
|
-
file: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
557
|
-
/**
|
|
558
|
-
* Hidden field (no UI).
|
|
559
|
-
*/
|
|
560
|
-
hidden: (name: string, props?: FieldProps) => BaseField;
|
|
793
|
+
/** Text input field. */text: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>; /** Email input field with default placeholder. */
|
|
794
|
+
email: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>; /** URL input field with default placeholder. */
|
|
795
|
+
url: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>; /** Phone/tel input field with default placeholder. */
|
|
796
|
+
tel: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>; /** Password input field. */
|
|
797
|
+
password: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
798
|
+
/** Number input field. No implicit `min` — pass `{ min }` to add one, so the
|
|
799
|
+
* builder never injects validation the author didn't write (signed
|
|
800
|
+
* quantities like deltas / temperatures stay valid). */
|
|
801
|
+
number: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>; /** Textarea field with default 3 rows. */
|
|
802
|
+
textarea: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>; /** Select dropdown field. */
|
|
803
|
+
select: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps<T>) => BaseField<T>; /** Searchable combobox field. */
|
|
804
|
+
combobox: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps<T>) => BaseField<T>; /** Multi-select field. */
|
|
805
|
+
multiselect: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps<T>) => BaseField<T>; /** Dependent select field that reacts to parent field changes. */
|
|
806
|
+
dependentSelect: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>; /** Switch/toggle field. */
|
|
807
|
+
switch: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>; /** Boolean field (alias for switch). */
|
|
808
|
+
boolean: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>; /** Checkbox field. */
|
|
809
|
+
checkbox: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>; /** Radio button group field. */
|
|
810
|
+
radio: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, options: FieldOption[], props?: FieldProps<T>) => BaseField<T>; /** Date picker field. */
|
|
811
|
+
date: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>; /** Tag input field. */
|
|
812
|
+
tags: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>; /** Slug field. */
|
|
813
|
+
slug: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>; /** File upload field. */
|
|
814
|
+
file: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>; /** Hidden field (no UI). */
|
|
815
|
+
hidden: <T extends FieldValues = FieldValues>(name: Path<T>, props?: FieldProps<T>) => BaseField<T>;
|
|
561
816
|
/**
|
|
562
817
|
* Group field for nested objects.
|
|
563
|
-
* Renders itemFields as a sub-grid
|
|
818
|
+
* Renders itemFields as a sub-grid. Child names are relative (e.g. "street"),
|
|
819
|
+
* FormGenerator prefixes them with the group name at render time.
|
|
564
820
|
*
|
|
565
821
|
* @example
|
|
566
822
|
* ```ts
|
|
567
823
|
* field.group("address", "Address", [
|
|
568
824
|
* field.text("street", "Street"),
|
|
569
825
|
* field.text("city", "City"),
|
|
570
|
-
*
|
|
571
|
-
* ], { cols: 3 })
|
|
826
|
+
* ], { cols: 2 })
|
|
572
827
|
* ```
|
|
573
828
|
*/
|
|
574
|
-
group: (name:
|
|
829
|
+
group: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, itemFields: BaseField[], props?: FieldProps<T>) => BaseField<T>;
|
|
575
830
|
/**
|
|
576
|
-
* Array/repeatable field.
|
|
577
|
-
* Renders a dynamic list of sub-forms using react-hook-form's useFieldArray.
|
|
831
|
+
* Array/repeatable field backed by react-hook-form's useFieldArray.
|
|
578
832
|
*
|
|
579
833
|
* @example
|
|
580
834
|
* ```ts
|
|
@@ -584,41 +838,108 @@ declare const field: {
|
|
|
584
838
|
* ])
|
|
585
839
|
* ```
|
|
586
840
|
*/
|
|
587
|
-
array: (name:
|
|
841
|
+
array: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, itemFields: BaseField[], props?: FieldProps<T>) => BaseField<T>;
|
|
588
842
|
/**
|
|
589
843
|
* Custom field with a render function.
|
|
590
|
-
* Bypasses the component registry
|
|
844
|
+
* Bypasses the component registry — full control over rendering.
|
|
845
|
+
*
|
|
846
|
+
* The render callback receives the complete `FieldComponentProps` including
|
|
847
|
+
* `fieldId`, `errorId`, `shouldShowError`, `error`, `rules`, and `control`.
|
|
848
|
+
*
|
|
849
|
+
* Use `shouldShowError` (not `!!error`) to drive `aria-invalid` and error
|
|
850
|
+
* visibility so timing mirrors the CSS `:user-invalid` pseudo-class.
|
|
591
851
|
*
|
|
592
852
|
* @example
|
|
593
|
-
* ```
|
|
594
|
-
* field.custom("skills", "Skills", ({ control,
|
|
595
|
-
* <
|
|
853
|
+
* ```tsx
|
|
854
|
+
* field.custom("skills", "Skills", ({ control, shouldShowError, errorId, error, fieldId }) => (
|
|
855
|
+
* <div>
|
|
856
|
+
* <SkillSelector
|
|
857
|
+
* id={fieldId}
|
|
858
|
+
* control={control}
|
|
859
|
+
* aria-invalid={shouldShowError || undefined}
|
|
860
|
+
* aria-errormessage={shouldShowError ? errorId : undefined}
|
|
861
|
+
* />
|
|
862
|
+
* {shouldShowError && (
|
|
863
|
+
* <p id={errorId} role="alert" className="text-sm text-destructive">
|
|
864
|
+
* {error?.message}
|
|
865
|
+
* </p>
|
|
866
|
+
* )}
|
|
867
|
+
* </div>
|
|
596
868
|
* ))
|
|
597
869
|
* ```
|
|
598
870
|
*/
|
|
599
|
-
custom: (name:
|
|
871
|
+
custom: <T extends FieldValues = FieldValues>(name: Path<T>, label: string, render: (props: FieldComponentProps<T>) => ReactNode, props?: FieldProps<T>) => BaseField<T>;
|
|
872
|
+
/**
|
|
873
|
+
* Returns a typed field builder with `TFieldValues` fixed.
|
|
874
|
+
* Every field name is validated against `Path<TFieldValues>` at the call site —
|
|
875
|
+
* no need to repeat the generic on each individual builder call.
|
|
876
|
+
*
|
|
877
|
+
* @example
|
|
878
|
+
* ```ts
|
|
879
|
+
* interface ContactForm {
|
|
880
|
+
* firstName: string;
|
|
881
|
+
* email: string;
|
|
882
|
+
* address: { street: string; city: string };
|
|
883
|
+
* }
|
|
884
|
+
*
|
|
885
|
+
* const f = field.for<ContactForm>()
|
|
886
|
+
*
|
|
887
|
+
* const schema = defineSchema<ContactForm>({
|
|
888
|
+
* sections: [{
|
|
889
|
+
* fields: [
|
|
890
|
+
* f.text("firstName", "First Name"), // ✓
|
|
891
|
+
* f.email("email", "Email"), // ✓
|
|
892
|
+
* f.text("typo", "Label"), // ✗ TypeScript error
|
|
893
|
+
* ],
|
|
894
|
+
* }],
|
|
895
|
+
* })
|
|
896
|
+
* ```
|
|
897
|
+
*/
|
|
898
|
+
for: <T extends FieldValues>() => {
|
|
899
|
+
text: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
900
|
+
email: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
901
|
+
url: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
902
|
+
tel: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
903
|
+
password: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
904
|
+
number: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
905
|
+
textarea: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
906
|
+
select: (name: Path<T>, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps<T>) => BaseField<T>;
|
|
907
|
+
combobox: (name: Path<T>, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps<T>) => BaseField<T>;
|
|
908
|
+
multiselect: (name: Path<T>, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps<T>) => BaseField<T>;
|
|
909
|
+
dependentSelect: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
910
|
+
switch: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
911
|
+
boolean: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
912
|
+
checkbox: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
913
|
+
radio: (name: Path<T>, label: string, options: FieldOption[], props?: FieldProps<T>) => BaseField<T>;
|
|
914
|
+
date: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
915
|
+
tags: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
916
|
+
slug: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
917
|
+
file: (name: Path<T>, label: string, props?: FieldProps<T>) => BaseField<T>;
|
|
918
|
+
hidden: (name: Path<T>, props?: FieldProps<T>) => BaseField<T>;
|
|
919
|
+
group: (name: Path<T>, label: string, itemFields: BaseField[], props?: FieldProps<T>) => BaseField<T>;
|
|
920
|
+
array: (name: Path<T>, label: string, itemFields: BaseField[], props?: FieldProps<T>) => BaseField<T>;
|
|
921
|
+
custom: (name: Path<T>, label: string, render: (props: FieldComponentProps<T>) => ReactNode, builderProps?: FieldProps<T>) => BaseField<T>;
|
|
922
|
+
};
|
|
600
923
|
};
|
|
601
924
|
/**
|
|
602
925
|
* Create a section definition with sensible defaults.
|
|
603
926
|
*
|
|
604
|
-
* @param id - Unique section identifier
|
|
605
|
-
* @param title - Section title
|
|
606
|
-
* @param fields - Array of field definitions
|
|
607
|
-
* @param props - Additional section configuration
|
|
608
|
-
*
|
|
609
927
|
* @example
|
|
610
928
|
* ```ts
|
|
611
929
|
* section("personal", "Personal Info", [
|
|
612
930
|
* field.text("name", "Name", { required: true }),
|
|
613
931
|
* field.email("email", "Email"),
|
|
614
|
-
* ], { cols: 2
|
|
932
|
+
* ], { cols: 2 })
|
|
615
933
|
* ```
|
|
616
934
|
*/
|
|
617
935
|
declare function section<TFieldValues extends FieldValues = FieldValues>(id: string, title: string, fields: BaseField<TFieldValues>[], props?: SectionProps<TFieldValues>): Section<TFieldValues>;
|
|
618
936
|
/**
|
|
619
937
|
* Create a section without a title (transparent section).
|
|
620
938
|
* Useful for grouping fields without visual separation.
|
|
939
|
+
*
|
|
940
|
+
* Accepts `BaseField[]` (no generic) so mixed-type field arrays don't trigger
|
|
941
|
+
* conflicting type inference across different field name generics.
|
|
621
942
|
*/
|
|
622
|
-
declare function sectionUntitled
|
|
943
|
+
declare function sectionUntitled(fields: BaseField[], props?: Omit<SectionProps, "variant">): Section;
|
|
623
944
|
//#endregion
|
|
624
|
-
export { type BaseField, type ClassValue, type Condition, type ConditionConfig, type ConditionRule, type DefaultLayoutProps, type DefineField, type FieldOption, type FieldOptionGroup, type FieldType, type FormSchema, type GridLayoutProps, type InferSchemaValues, type LayoutComponentProps, type LayoutType, type SchemaFieldNames, type Section, type SectionLayoutProps, type SectionRenderProps, type Variant, buildValidationRules, cn, defineField, defineSchema, defineSection, evaluateCondition, extractDefaultValues, extractWatchNames, field, section, sectionUntitled };
|
|
945
|
+
export { type BaseField, type ClassValue, type Condition, type ConditionConfig, type ConditionRule, type DefaultLayoutProps, type DefineField, type FieldMeta, type FieldOption, type FieldOptionGroup, type FieldType, type FormSchema, type GridLayoutProps, type InferSchemaValues, type LayoutComponentProps, type LayoutType, type PatternRuleObject, type SchemaFieldNames, type SchemaIssue, type Section, type SectionLayoutProps, type SectionRenderProps, type ValidationRuleObject, type Variant, buildFieldDefaults, buildValidationRules, cn, defineField, defineSchema, defineSection, evaluateCondition, extendSection, extractDefaultValues, extractWatchNames, field, flattenSchema, isArrayField, isChoiceField, isConditionalField, isContainerField, isDateField, isDynamicField, isNumericField, isTextField, mergeDefaultValues, mergeSchemas, omitFields, pickFields, section, sectionUntitled, validateSchema };
|