@classytic/formkit 1.0.2 → 1.2.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.
@@ -0,0 +1,914 @@
1
+ "use client";
2
+ import { ComponentType, JSX, ReactNode, Ref } from "react";
3
+ import { Control, FieldError, FieldValues, Path, RegisterOptions, UseFormProps, UseFormReturn } from "react-hook-form";
4
+ import { ClassValue } from "clsx";
5
+
6
+ //#region src/types.d.ts
7
+ /**
8
+ * Field type identifier.
9
+ * Can be built-in types or custom string identifiers.
10
+ */
11
+ type FieldType = "text" | "email" | "password" | "number" | "tel" | "url" | "textarea" | "select" | "checkbox" | "radio" | "switch" | "date" | "time" | "datetime" | "file" | "hidden" | "group" | "array" | "custom" | (string & {});
12
+ /**
13
+ * Layout type identifier.
14
+ */
15
+ type LayoutType = "section" | "grid" | "default" | (string & {});
16
+ /**
17
+ * Variant identifier for component styling.
18
+ */
19
+ type Variant = "default" | "compact" | "inline" | (string & {}) | undefined;
20
+ interface ConditionRule<TFieldValues extends FieldValues = FieldValues> {
21
+ watch: Path<TFieldValues>;
22
+ operator: "===" | "!==" | "in" | "not-in" | "truthy" | "falsy";
23
+ value?: unknown;
24
+ }
25
+ /**
26
+ * Condition configuration with explicit logic operator.
27
+ * Allows combining rules with AND or OR logic.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * // Show field if country is "US" OR "CA"
32
+ * condition: {
33
+ * rules: [
34
+ * { watch: "country", operator: "===", value: "US" },
35
+ * { watch: "country", operator: "===", value: "CA" },
36
+ * ],
37
+ * logic: "or",
38
+ * }
39
+ * ```
40
+ */
41
+ interface ConditionConfig<TFieldValues extends FieldValues = FieldValues> {
42
+ /** Array of condition rules to evaluate */
43
+ rules: ConditionRule<TFieldValues>[];
44
+ /** Logic operator: "and" (all must match) or "or" (any must match). Defaults to "and". */
45
+ logic?: "and" | "or";
46
+ }
47
+ /**
48
+ * Single option for select/radio/checkbox fields.
49
+ */
50
+ interface FieldOption<TValue = string> {
51
+ /** Display label */
52
+ label: string;
53
+ /** Option value */
54
+ value: TValue;
55
+ /** Whether option is disabled */
56
+ disabled?: boolean;
57
+ /** Optional description */
58
+ description?: string;
59
+ /** Optional icon */
60
+ icon?: ReactNode;
61
+ }
62
+ /**
63
+ * Option group for select fields.
64
+ */
65
+ interface FieldOptionGroup<TValue = string> {
66
+ /** Group label */
67
+ label: string;
68
+ /** Group options */
69
+ options: FieldOption<TValue>[];
70
+ /** Whether group is disabled */
71
+ disabled?: boolean;
72
+ }
73
+ /**
74
+ * Base field configuration shared by all field types.
75
+ * @template TFieldValues - Form field values type for type-safe field names
76
+ */
77
+ interface BaseField<TFieldValues extends FieldValues = FieldValues> {
78
+ /** Field name (must be a valid path in form values) */
79
+ name: Path<TFieldValues> | (string & {});
80
+ /** Field type identifier */
81
+ type: FieldType;
82
+ /** Field label */
83
+ label?: string;
84
+ /** Placeholder text */
85
+ placeholder?: string;
86
+ /** Helper text shown below the field */
87
+ helperText?: string;
88
+ /** Whether field is disabled */
89
+ disabled?: boolean;
90
+ /** Whether field is required */
91
+ required?: boolean;
92
+ /** Whether field is read-only */
93
+ readOnly?: boolean;
94
+ /** Field variant */
95
+ variant?: Variant;
96
+ /** Whether field should span full width in grid */
97
+ fullWidth?: boolean;
98
+ /** Custom CSS class name */
99
+ className?: string;
100
+ /**
101
+ * Conditional rendering function, declarative rules, or a condition config with logic.
102
+ * Return true to show the field, false to hide.
103
+ */
104
+ condition?: ((formValues: Partial<TFieldValues>) => boolean) | ConditionRule<TFieldValues> | ConditionRule<TFieldValues>[] | ConditionConfig<TFieldValues>;
105
+ /** Default value */
106
+ defaultValue?: unknown;
107
+ /** Options for select/radio/checkbox fields */
108
+ options?: (FieldOption | FieldOptionGroup)[];
109
+ /** Minimum value (for number/date fields) */
110
+ min?: number | string;
111
+ /** Maximum value (for number/date fields) */
112
+ max?: number | string;
113
+ /** Step value (for number fields) */
114
+ step?: number;
115
+ /** Pattern for validation (regex string) */
116
+ pattern?: string;
117
+ /** Minimum length */
118
+ minLength?: number;
119
+ /** Maximum length */
120
+ maxLength?: number;
121
+ /** Number of rows (for textarea) */
122
+ rows?: number;
123
+ /** Multiple selection (for select/file) */
124
+ multiple?: boolean;
125
+ /** Accepted file types (for file input) */
126
+ accept?: string;
127
+ /** Auto-complete attribute */
128
+ autoComplete?: string;
129
+ /** Auto-focus on mount */
130
+ autoFocus?: boolean;
131
+ /** Debounce loadOptions requests in milliseconds, helps prevent API storms */
132
+ debounceMs?: number;
133
+ /**
134
+ * Dynamic options loaded based on current form values.
135
+ * Useful for dependent selects (e.g., state depends on country).
136
+ */
137
+ loadOptions?: (formValues: Partial<TFieldValues>) => Promise<(FieldOption | FieldOptionGroup)[]> | (FieldOption | FieldOptionGroup)[];
138
+ /**
139
+ * Error callback for loadOptions failures.
140
+ * Called when loadOptions rejects. Defaults to console.error.
141
+ */
142
+ onLoadError?: (error: unknown) => void;
143
+ /**
144
+ * Fields for array or object types.
145
+ * Useful for 'array' or 'group' field types that need a sub-schema.
146
+ */
147
+ itemFields?: BaseField<TFieldValues>[];
148
+ /**
149
+ * Custom render function to override the component registry for this specific field.
150
+ * Completely bypasses the globally registered FieldComponent for this type.
151
+ */
152
+ render?: (props: FieldComponentProps<TFieldValues>) => ReactNode;
153
+ /**
154
+ * Cross-field validation function.
155
+ * Receives the field value and all form values for cross-field checks.
156
+ * Return `true` for valid, or a string error message for invalid.
157
+ *
158
+ * @example
159
+ * ```ts
160
+ * validate: (value, formValues) =>
161
+ * value > formValues.minPrice || "Must be greater than min price"
162
+ * ```
163
+ */
164
+ validate?: (value: unknown, formValues: Partial<TFieldValues>) => string | true;
165
+ /**
166
+ * Dependencies for optimizing conditionally rendered fields.
167
+ * Allows specifying specific field names to watch, preventing full form re-renders.
168
+ */
169
+ watchNames?: Path<TFieldValues> | Path<TFieldValues>[];
170
+ /** Additional field-specific props for custom components */
171
+ customProps?: Record<string, unknown>;
172
+ }
173
+ /**
174
+ * Props passed to field components.
175
+ *
176
+ * Components receive both:
177
+ * 1. A `field` object with the complete field configuration
178
+ * 2. All field properties spread at the top level
179
+ *
180
+ * @template TFieldValues - Form field values type
181
+ *
182
+ * @example
183
+ * ```tsx
184
+ * // Schema
185
+ * { name: "email", type: "email", label: "Email", placeholder: "user@example.com" }
186
+ *
187
+ * // Your component receives:
188
+ * {
189
+ * field: { name: "email", type: "email", label: "Email", placeholder: "..." },
190
+ * control: {...},
191
+ * disabled: false,
192
+ * variant: undefined,
193
+ * // PLUS all field props at top level:
194
+ * name: "email",
195
+ * type: "email",
196
+ * label: "Email",
197
+ * placeholder: "user@example.com"
198
+ * }
199
+ * ```
200
+ */
201
+ interface FieldComponentProps<TFieldValues extends FieldValues = FieldValues> extends BaseField<TFieldValues> {
202
+ /** Field configuration object (contains all field props) */
203
+ field: BaseField<TFieldValues>;
204
+ /** React Hook Form control for Controller integration */
205
+ control: Control<TFieldValues>;
206
+ /** Whether field is globally disabled */
207
+ disabled?: boolean;
208
+ /** Component variant */
209
+ variant?: Variant;
210
+ /** Field validation error from react-hook-form */
211
+ error?: FieldError;
212
+ /** Field state from react-hook-form */
213
+ fieldState?: {
214
+ invalid: boolean;
215
+ isDirty: boolean;
216
+ isTouched: boolean;
217
+ isValidating: boolean;
218
+ error?: FieldError;
219
+ };
220
+ /** Generated field ID for label-input association (e.g. `formkit-field-email`) */
221
+ fieldId: string;
222
+ /** Whether dynamic options are currently loading */
223
+ isLoading?: boolean;
224
+ }
225
+ /**
226
+ * Field component type.
227
+ * A React component that renders a form field.
228
+ */
229
+ type FieldComponent<TFieldValues extends FieldValues = FieldValues> = ComponentType<FieldComponentProps<TFieldValues>>;
230
+ /**
231
+ * Validation rules compatible with react-hook-form's RegisterOptions.
232
+ * Returned by `buildValidationRules()`.
233
+ */
234
+ type ValidationRules = Pick<RegisterOptions, "required" | "min" | "max" | "minLength" | "maxLength" | "pattern" | "validate">;
235
+ /**
236
+ * Section configuration for grouping fields.
237
+ * @template TFieldValues - Form field values type
238
+ */
239
+ interface Section<TFieldValues extends FieldValues = FieldValues> {
240
+ /** Unique section identifier */
241
+ id?: string;
242
+ /** Section title */
243
+ title?: string;
244
+ /** Section description */
245
+ description?: string;
246
+ /** Section icon */
247
+ icon?: ReactNode;
248
+ /** Namespace to prepend to all field names in this section */
249
+ nameSpace?: string;
250
+ /** Fields in this section */
251
+ fields?: BaseField<TFieldValues>[];
252
+ /** Number of columns in grid layout */
253
+ cols?: 1 | 2 | 3 | 4 | 5 | 6 | number;
254
+ /** Gap between grid items (Tailwind spacing scale) */
255
+ gap?: number;
256
+ /**
257
+ * Custom render function for complete control.
258
+ * When provided, fields array is ignored.
259
+ */
260
+ render?: (props: SectionRenderProps<TFieldValues>) => ReactNode;
261
+ /** Section variant */
262
+ variant?: Variant;
263
+ /** Custom CSS class name */
264
+ className?: string;
265
+ /**
266
+ * Conditional rendering function, declarative rules, or a condition config with logic.
267
+ * Return true to show the section, false to hide.
268
+ */
269
+ condition?: ((formValues?: Partial<TFieldValues>) => boolean) | ConditionRule<TFieldValues> | ConditionRule<TFieldValues>[] | ConditionConfig<TFieldValues>;
270
+ /** Whether section is collapsible */
271
+ collapsible?: boolean;
272
+ /** Default collapsed state */
273
+ defaultCollapsed?: boolean;
274
+ }
275
+ /**
276
+ * Props passed to section render function.
277
+ */
278
+ interface SectionRenderProps<TFieldValues extends FieldValues = FieldValues> {
279
+ control?: Control<TFieldValues>;
280
+ disabled?: boolean;
281
+ section: Section<TFieldValues>;
282
+ }
283
+ /**
284
+ * Section layout component props.
285
+ */
286
+ interface SectionLayoutProps {
287
+ /** Section title */
288
+ title?: string;
289
+ /** Section description */
290
+ description?: string;
291
+ /** Section icon */
292
+ icon?: ReactNode;
293
+ /** Layout variant */
294
+ variant?: Variant;
295
+ /** Custom CSS class name */
296
+ className?: string;
297
+ /** Whether section is collapsible */
298
+ collapsible?: boolean;
299
+ /** Default collapsed state */
300
+ defaultCollapsed?: boolean;
301
+ /** Children content */
302
+ children: ReactNode;
303
+ }
304
+ /**
305
+ * Grid layout component props.
306
+ */
307
+ interface GridLayoutProps {
308
+ /** Number of columns */
309
+ cols?: number;
310
+ /** Gap between items */
311
+ gap?: number;
312
+ /** Custom CSS class name */
313
+ className?: string;
314
+ /** Children content */
315
+ children: ReactNode;
316
+ }
317
+ /**
318
+ * Default layout component props.
319
+ */
320
+ interface DefaultLayoutProps {
321
+ /** Custom CSS class name */
322
+ className?: string;
323
+ /** Children content */
324
+ children: ReactNode;
325
+ }
326
+ /**
327
+ * Union of all layout component props.
328
+ */
329
+ type LayoutComponentProps = SectionLayoutProps | GridLayoutProps | DefaultLayoutProps;
330
+ /**
331
+ * Layout component type.
332
+ */
333
+ type LayoutComponent<TProps extends LayoutComponentProps = LayoutComponentProps> = ComponentType<TProps>;
334
+ /**
335
+ * Complete form schema configuration.
336
+ * @template TFieldValues - Form field values type for type-safe schemas
337
+ */
338
+ interface FormSchema<TFieldValues extends FieldValues = FieldValues> {
339
+ /** Form sections */
340
+ sections: Section<TFieldValues>[];
341
+ }
342
+ /**
343
+ * Component registry mapping field types to components.
344
+ * Supports variant-specific components via nested objects.
345
+ *
346
+ * @example
347
+ * ```tsx
348
+ * const components: ComponentRegistry = {
349
+ * text: TextInput,
350
+ * select: SelectInput,
351
+ * // Variant-specific
352
+ * compact: {
353
+ * text: CompactTextInput,
354
+ * },
355
+ * };
356
+ * ```
357
+ */
358
+ interface ComponentRegistry {
359
+ [key: string]: FieldComponent<FieldValues> | ComponentRegistry;
360
+ }
361
+ /**
362
+ * Layout registry mapping layout types to components.
363
+ * Supports variant-specific layouts via nested objects.
364
+ */
365
+ interface LayoutRegistry {
366
+ [key: string]: LayoutComponent<SectionLayoutProps | GridLayoutProps | DefaultLayoutProps> | LayoutRegistry;
367
+ }
368
+ /**
369
+ * Form system context value.
370
+ */
371
+ interface FormSystemContextValue {
372
+ /** Registered field components */
373
+ components: ComponentRegistry;
374
+ /** Registered layout components */
375
+ layouts: LayoutRegistry;
376
+ }
377
+ /**
378
+ * Form system provider props.
379
+ */
380
+ interface FormSystemProviderProps {
381
+ /** Field component registry */
382
+ components?: ComponentRegistry;
383
+ /** Layout component registry */
384
+ layouts?: LayoutRegistry;
385
+ /** Children content */
386
+ children: ReactNode;
387
+ }
388
+ /**
389
+ * FormGenerator component props.
390
+ * @template TFieldValues - Form field values type
391
+ */
392
+ interface FormGeneratorProps<TFieldValues extends FieldValues = FieldValues> {
393
+ /** Form schema defining sections and fields */
394
+ schema: FormSchema<TFieldValues>;
395
+ /** React Hook Form control object */
396
+ control?: Control<TFieldValues>;
397
+ /** Global disabled state for all fields */
398
+ disabled?: boolean;
399
+ /** Global variant for all components */
400
+ variant?: Variant;
401
+ /** Additional CSS class for the root element */
402
+ className?: string;
403
+ /** Ref to the root FormKit div element (React 19 ref-as-prop) */
404
+ ref?: Ref<HTMLDivElement>;
405
+ }
406
+ /**
407
+ * Extract field names from a schema.
408
+ */
409
+ type SchemaFieldNames<TSchema extends FormSchema> = TSchema extends FormSchema<infer T> ? keyof T : never;
410
+ /**
411
+ * Infer field values type from a schema.
412
+ */
413
+ type InferSchemaValues<TSchema extends FormSchema> = TSchema extends FormSchema<infer T> ? T : FieldValues;
414
+ /**
415
+ * Helper type for creating type-safe field definitions.
416
+ */
417
+ type DefineField<TFieldValues extends FieldValues, TType extends FieldType = FieldType> = BaseField<TFieldValues> & {
418
+ type: TType;
419
+ };
420
+ /**
421
+ * JSX Element return type for components.
422
+ */
423
+ type FormElement = JSX.Element | null;
424
+ //#endregion
425
+ //#region src/FormGenerator.d.ts
426
+ /**
427
+ * FormGenerator - Headless Form Generator Component
428
+ *
429
+ * Renders a form based on a schema definition, using components registered
430
+ * via FormSystemProvider. Supports conditional fields, dynamic layouts,
431
+ * and component variants.
432
+ *
433
+ * @template TFieldValues - Form field values type for type safety
434
+ *
435
+ * @example
436
+ * ```tsx
437
+ * import { useFormKit, FormGenerator } from '@classytic/formkit';
438
+ *
439
+ * const { handleSubmit, generatorProps } = useFormKit({
440
+ * schema: formSchema,
441
+ * resolver: zodResolver(validationSchema),
442
+ * });
443
+ *
444
+ * return (
445
+ * <form onSubmit={handleSubmit(onSubmit)}>
446
+ * <FormGenerator {...generatorProps} />
447
+ * </form>
448
+ * );
449
+ * ```
450
+ */
451
+ declare function FormGenerator<TFieldValues extends FieldValues = FieldValues>({
452
+ schema,
453
+ control,
454
+ disabled,
455
+ variant,
456
+ className,
457
+ ref
458
+ }: FormGeneratorProps<TFieldValues>): FormElement;
459
+ interface SectionRendererProps<TFieldValues extends FieldValues = FieldValues> {
460
+ section: Section<TFieldValues>;
461
+ control?: Control<TFieldValues>;
462
+ disabled?: boolean;
463
+ variant?: Variant;
464
+ }
465
+ /**
466
+ * Renders a single section with its fields.
467
+ */
468
+ declare function SectionRenderer<TFieldValues extends FieldValues = FieldValues>(props: SectionRendererProps<TFieldValues>): FormElement;
469
+ interface GridRendererProps<TFieldValues extends FieldValues = FieldValues> {
470
+ fields?: BaseField<TFieldValues>[];
471
+ cols?: number;
472
+ gap?: number;
473
+ control?: Control<TFieldValues>;
474
+ disabled?: boolean;
475
+ variant?: Variant;
476
+ }
477
+ /**
478
+ * Renders a grid of fields with specified column layout.
479
+ */
480
+ declare function GridRenderer<TFieldValues extends FieldValues = FieldValues>({
481
+ fields,
482
+ cols,
483
+ gap,
484
+ control,
485
+ disabled,
486
+ variant
487
+ }: GridRendererProps<TFieldValues>): FormElement;
488
+ interface FieldWrapperProps<TFieldValues extends FieldValues = FieldValues> {
489
+ field: BaseField<TFieldValues>;
490
+ control?: Control<TFieldValues>;
491
+ disabled?: boolean;
492
+ variant?: Variant;
493
+ }
494
+ /**
495
+ * Wraps individual fields.
496
+ * If the field requires conditional logic or dynamic options, it uses the Dynamic wrapper.
497
+ * Otherwise, it uses the Static wrapper, vastly improving performance by skipping `useWatch`.
498
+ */
499
+ declare function FieldWrapper<TFieldValues extends FieldValues = FieldValues>(props: FieldWrapperProps<TFieldValues>): FormElement;
500
+ //#endregion
501
+ //#region src/FormSystemContext.d.ts
502
+ /**
503
+ * FormSystemProvider
504
+ *
505
+ * Root provider that enables the form system. Provides component and layout
506
+ * registries to FormGenerator and its descendants.
507
+ *
508
+ * @example
509
+ * ```tsx
510
+ * import { FormSystemProvider } from '@classytic/formkit';
511
+ *
512
+ * const components = {
513
+ * text: TextInput,
514
+ * select: SelectInput,
515
+ * // Variant-specific components
516
+ * compact: {
517
+ * text: CompactTextInput,
518
+ * },
519
+ * };
520
+ *
521
+ * const layouts = {
522
+ * section: SectionLayout,
523
+ * grid: GridLayout,
524
+ * };
525
+ *
526
+ * function App() {
527
+ * return (
528
+ * <FormSystemProvider components={components} layouts={layouts}>
529
+ * <YourFormComponent />
530
+ * </FormSystemProvider>
531
+ * );
532
+ * }
533
+ * ```
534
+ */
535
+ declare function FormSystemProvider({
536
+ components,
537
+ layouts,
538
+ children
539
+ }: FormSystemProviderProps): FormElement;
540
+ /**
541
+ * Hook to access the form system context.
542
+ *
543
+ * @throws {Error} If used outside FormSystemProvider
544
+ * @returns Form system context value
545
+ *
546
+ * @example
547
+ * ```tsx
548
+ * const { components, layouts } = useFormSystem();
549
+ * ```
550
+ */
551
+ declare function useFormSystem(): FormSystemContextValue;
552
+ /**
553
+ * Hook to get a field component by type and optional variant.
554
+ *
555
+ * Resolution order:
556
+ * 1. Variant-specific component: `components[variant][type]`
557
+ * 2. Type-specific component: `components[type]`
558
+ * 3. Default component: `components["default"]`
559
+ * 4. Text fallback: `components["text"]`
560
+ *
561
+ * @param type - Field type identifier
562
+ * @param variant - Optional variant name
563
+ * @returns Field component or fallback
564
+ *
565
+ * @internal
566
+ */
567
+ declare function useFieldComponent(type: FieldType, variant?: Variant): FieldComponent;
568
+ /**
569
+ * Hook to get a layout component by type and optional variant.
570
+ *
571
+ * Resolution order:
572
+ * 1. Variant-specific layout: `layouts[variant][type]`
573
+ * 2. Type-specific layout: `layouts[type]`
574
+ * 3. Default layout: `layouts["default"]`
575
+ * 4. Built-in default layout
576
+ *
577
+ * @param type - Layout type identifier
578
+ * @param variant - Optional variant name
579
+ * @returns Layout component or fallback
580
+ *
581
+ * @internal
582
+ */
583
+ declare function useLayoutComponent(type: LayoutType, variant?: Variant): LayoutComponent<SectionLayoutProps | GridLayoutProps | DefaultLayoutProps>;
584
+ //#endregion
585
+ //#region src/utils.d.ts
586
+ /**
587
+ * Utility function to merge CSS classes with Tailwind CSS conflict resolution.
588
+ *
589
+ * Combines `clsx` for conditional class handling with `tailwind-merge`
590
+ * for proper Tailwind CSS class conflict resolution.
591
+ *
592
+ * @param inputs - Class values to merge (strings, arrays, objects, or conditionals)
593
+ * @returns Merged and deduplicated class string
594
+ *
595
+ * @example
596
+ * ```tsx
597
+ * // Basic usage
598
+ * cn("px-2 py-1", "px-4") // "py-1 px-4"
599
+ *
600
+ * // Conditional classes
601
+ * cn("base", isActive && "active", { "disabled": isDisabled })
602
+ *
603
+ * // Arrays
604
+ * cn(["flex", "items-center"], "gap-2")
605
+ * ```
606
+ */
607
+ declare function cn(...inputs: ClassValue[]): string;
608
+ /**
609
+ * Shallow equality check for arrays and primitives.
610
+ * Used to stabilize useWatch output without JSON.stringify overhead.
611
+ */
612
+ declare function shallowEqual(a: unknown, b: unknown): boolean;
613
+ //#endregion
614
+ //#region src/schema.d.ts
615
+ /**
616
+ * All supported condition shapes.
617
+ */
618
+ type Condition<TFieldValues extends FieldValues = FieldValues> = ((formValues: Partial<TFieldValues>) => boolean) | ConditionRule<TFieldValues> | ConditionRule<TFieldValues>[] | ConditionConfig<TFieldValues> | undefined;
619
+ /**
620
+ * Evaluates a conditional rule, array of rules, or a ConditionConfig against form values.
621
+ * Supports AND (default) and OR logic via ConditionConfig.
622
+ *
623
+ * @param condition - The condition function, rule(s), or config
624
+ * @param formValues - The form values to evaluate against
625
+ * @returns boolean indicating if condition matches
626
+ */
627
+ declare function evaluateCondition<TFieldValues extends FieldValues = FieldValues>(condition: Condition<TFieldValues>, formValues: Partial<TFieldValues>): boolean;
628
+ /**
629
+ * Extracts all watch names from a condition to optimize `useWatch`.
630
+ * Handles single rules, arrays, and ConditionConfig objects.
631
+ */
632
+ declare function extractWatchNames<TFieldValues extends FieldValues = FieldValues>(condition: Condition<TFieldValues>): string[];
633
+ /**
634
+ * Strictly types a comprehensive form schema, granting exact intellisense bounds across conditions and nested watches.
635
+ */
636
+ declare function defineSchema<TFieldValues extends FieldValues = FieldValues>(schema: FormSchema<TFieldValues>): FormSchema<TFieldValues>;
637
+ /**
638
+ * Standard utility to strictly type a standalone field out-of-bounds, useful for externalizing massive schema structures.
639
+ */
640
+ declare function defineField<TFieldValues extends FieldValues = FieldValues>(field: BaseField<TFieldValues>): BaseField<TFieldValues>;
641
+ /**
642
+ * Standard utility to strictly type a standalone logic section layout block.
643
+ */
644
+ declare function defineSection<TFieldValues extends FieldValues = FieldValues>(section: Section<TFieldValues>): Section<TFieldValues>;
645
+ /**
646
+ * Extracts default values from a form schema.
647
+ * Walks all sections and fields, respecting nameSpace prefixes and group nesting.
648
+ *
649
+ * @example
650
+ * ```ts
651
+ * const defaults = extractDefaultValues(schema);
652
+ * const form = useForm({ defaultValues: defaults });
653
+ * ```
654
+ */
655
+ declare function extractDefaultValues<TFieldValues extends FieldValues = FieldValues>(schema: FormSchema<TFieldValues>): Partial<TFieldValues>;
656
+ /**
657
+ * Generates react-hook-form `RegisterOptions`-compatible validation rules
658
+ * from a field's schema props. Maps `required`, `min`, `max`, `minLength`,
659
+ * `maxLength`, `pattern`, and `validate` to RHF rules.
660
+ *
661
+ * @example
662
+ * ```tsx
663
+ * import { buildValidationRules } from '@classytic/formkit';
664
+ *
665
+ * function FormInput({ field, control }: FieldComponentProps) {
666
+ * const rules = buildValidationRules(field);
667
+ * return <Controller name={field.name} control={control} rules={rules} render={...} />;
668
+ * }
669
+ * ```
670
+ */
671
+ declare function buildValidationRules<TFieldValues extends FieldValues = FieldValues>(field: BaseField<TFieldValues>): ValidationRules;
672
+ //#endregion
673
+ //#region src/builders.d.ts
674
+ /**
675
+ * Additional field props for builder helpers.
676
+ * Accepts all BaseField properties except `name`, `type`, and `label`
677
+ * which are set by the builder method.
678
+ */
679
+ type FieldProps<TFieldValues extends FieldValues = FieldValues> = Omit<BaseField<TFieldValues>, "name" | "type" | "label"> & {
680
+ /** Grid column class (e.g., "col-span-2") */gridColumn?: string; /** Icon for the left side of input */
681
+ iconLeft?: ReactNode; /** Icon for the right side of input */
682
+ iconRight?: ReactNode; /** Additional custom props */
683
+ [key: string]: unknown;
684
+ };
685
+ /**
686
+ * Section configuration props.
687
+ */
688
+ interface SectionProps<TFieldValues extends FieldValues = FieldValues> extends Omit<Section<TFieldValues>, "id" | "title" | "fields" | "cols"> {
689
+ cols?: number;
690
+ }
691
+ /**
692
+ * Render function for custom field types.
693
+ */
694
+ type CustomRenderFn = (props: {
695
+ control: Control<FieldValues>;
696
+ disabled?: boolean;
697
+ error?: FieldError;
698
+ }) => ReactNode;
699
+ /**
700
+ * Type-safe field builder helpers for schema-driven forms.
701
+ *
702
+ * Provides shorthand methods for common field types with sensible defaults,
703
+ * reducing boilerplate while maintaining full type safety.
704
+ *
705
+ * @example
706
+ * ```ts
707
+ * import { field, section } from '@classytic/formkit';
708
+ *
709
+ * const schema = {
710
+ * sections: [
711
+ * section("personal", "Personal Info", [
712
+ * field.text("firstName", "First Name", { required: true }),
713
+ * field.email("email", "Email"),
714
+ * field.select("role", "Role", [
715
+ * { label: "Admin", value: "admin" },
716
+ * { label: "User", value: "user" },
717
+ * ]),
718
+ * ], { cols: 2 }),
719
+ * ],
720
+ * };
721
+ * ```
722
+ */
723
+ declare const field: {
724
+ /**
725
+ * Text input field.
726
+ */
727
+ text: (name: string, label: string, props?: FieldProps) => BaseField;
728
+ /**
729
+ * Email input field with default placeholder.
730
+ */
731
+ email: (name: string, label: string, props?: FieldProps) => BaseField;
732
+ /**
733
+ * URL input field with default placeholder.
734
+ */
735
+ url: (name: string, label: string, props?: FieldProps) => BaseField;
736
+ /**
737
+ * Phone/tel input field with default placeholder.
738
+ */
739
+ tel: (name: string, label: string, props?: FieldProps) => BaseField;
740
+ /**
741
+ * Password input field.
742
+ */
743
+ password: (name: string, label: string, props?: FieldProps) => BaseField;
744
+ /**
745
+ * Number input field with min: 0 default.
746
+ */
747
+ number: (name: string, label: string, props?: FieldProps) => BaseField;
748
+ /**
749
+ * Textarea field with default 3 rows.
750
+ */
751
+ textarea: (name: string, label: string, props?: FieldProps) => BaseField;
752
+ /**
753
+ * Select dropdown field.
754
+ */
755
+ select: (name: string, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps) => BaseField;
756
+ /**
757
+ * Searchable combobox field.
758
+ */
759
+ combobox: (name: string, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps) => BaseField;
760
+ /**
761
+ * Multi-select field (tag choice).
762
+ */
763
+ multiselect: (name: string, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps) => BaseField;
764
+ /**
765
+ * Dependent select field that reacts to parent field changes.
766
+ */
767
+ dependentSelect: (name: string, label: string, props?: FieldProps) => BaseField;
768
+ /**
769
+ * Switch/toggle field.
770
+ */
771
+ switch: (name: string, label: string, props?: FieldProps) => BaseField;
772
+ /**
773
+ * Boolean field (alias for switch).
774
+ */
775
+ boolean: (name: string, label: string, props?: FieldProps) => BaseField;
776
+ /**
777
+ * Checkbox field.
778
+ */
779
+ checkbox: (name: string, label: string, props?: FieldProps) => BaseField;
780
+ /**
781
+ * Radio button group field.
782
+ */
783
+ radio: (name: string, label: string, options: FieldOption[], props?: FieldProps) => BaseField;
784
+ /**
785
+ * Date picker field.
786
+ */
787
+ date: (name: string, label: string, props?: FieldProps) => BaseField;
788
+ /**
789
+ * Tag input field with default placeholder.
790
+ */
791
+ tags: (name: string, label: string, props?: FieldProps) => BaseField;
792
+ /**
793
+ * Slug field with auto-generation from source value.
794
+ */
795
+ slug: (name: string, label: string, props?: FieldProps) => BaseField;
796
+ /**
797
+ * File upload field.
798
+ */
799
+ file: (name: string, label: string, props?: FieldProps) => BaseField;
800
+ /**
801
+ * Hidden field (no UI).
802
+ */
803
+ hidden: (name: string, props?: FieldProps) => BaseField;
804
+ /**
805
+ * Group field for nested objects.
806
+ * Renders itemFields as a sub-grid within the form.
807
+ *
808
+ * @example
809
+ * ```ts
810
+ * field.group("address", "Address", [
811
+ * field.text("street", "Street"),
812
+ * field.text("city", "City"),
813
+ * field.text("zip", "ZIP Code"),
814
+ * ], { cols: 3 })
815
+ * ```
816
+ */
817
+ group: (name: string, label: string, itemFields: BaseField[], props?: FieldProps) => BaseField;
818
+ /**
819
+ * Array/repeatable field.
820
+ * Renders a dynamic list of sub-forms using react-hook-form's useFieldArray.
821
+ *
822
+ * @example
823
+ * ```ts
824
+ * field.array("contacts", "Contacts", [
825
+ * field.text("name", "Name"),
826
+ * field.email("email", "Email"),
827
+ * ])
828
+ * ```
829
+ */
830
+ array: (name: string, label: string, itemFields: BaseField[], props?: FieldProps) => BaseField;
831
+ /**
832
+ * Custom field with a render function.
833
+ * Bypasses the component registry entirely.
834
+ *
835
+ * @example
836
+ * ```ts
837
+ * field.custom("skills", "Skills", ({ control, disabled }) => (
838
+ * <SkillSelector control={control} disabled={disabled} />
839
+ * ))
840
+ * ```
841
+ */
842
+ custom: (name: string, label: string, render: CustomRenderFn, props?: FieldProps) => BaseField;
843
+ };
844
+ /**
845
+ * Create a section definition with sensible defaults.
846
+ *
847
+ * @param id - Unique section identifier
848
+ * @param title - Section title
849
+ * @param fields - Array of field definitions
850
+ * @param props - Additional section configuration
851
+ *
852
+ * @example
853
+ * ```ts
854
+ * section("personal", "Personal Info", [
855
+ * field.text("name", "Name", { required: true }),
856
+ * field.email("email", "Email"),
857
+ * ], { cols: 2, variant: "card" })
858
+ * ```
859
+ */
860
+ declare function section<TFieldValues extends FieldValues = FieldValues>(id: string, title: string, fields: BaseField<TFieldValues>[], props?: SectionProps<TFieldValues>): Section<TFieldValues>;
861
+ /**
862
+ * Create a section without a title (transparent section).
863
+ * Useful for grouping fields without visual separation.
864
+ */
865
+ declare function sectionUntitled<TFieldValues extends FieldValues = FieldValues>(fields: BaseField<TFieldValues>[], props?: Omit<SectionProps<TFieldValues>, "variant">): Section<TFieldValues>;
866
+ //#endregion
867
+ //#region src/useFormKit.d.ts
868
+ /**
869
+ * Options for the useFormKit hook.
870
+ * Extends react-hook-form's UseFormProps with schema-driven defaults.
871
+ */
872
+ interface UseFormKitOptions<TFieldValues extends FieldValues = FieldValues> extends Omit<UseFormProps<TFieldValues>, "defaultValues"> {
873
+ /** Form schema defining sections and fields */
874
+ schema: FormSchema<TFieldValues>;
875
+ /** Override or extend default values extracted from schema */
876
+ defaultValues?: UseFormProps<TFieldValues>["defaultValues"];
877
+ /** Disable all fields */
878
+ disabled?: boolean;
879
+ /** Global variant */
880
+ variant?: Variant;
881
+ /** Root element className */
882
+ className?: string;
883
+ }
884
+ /**
885
+ * Return value from useFormKit.
886
+ * Includes all useForm methods plus pre-built generatorProps.
887
+ */
888
+ interface UseFormKitReturn<TFieldValues extends FieldValues = FieldValues> extends UseFormReturn<TFieldValues> {
889
+ /** Props to spread onto <FormGenerator /> */
890
+ generatorProps: Pick<FormGeneratorProps<TFieldValues>, "schema" | "control" | "disabled" | "variant" | "className">;
891
+ }
892
+ /**
893
+ * Convenience hook that combines schema default extraction with react-hook-form setup.
894
+ * Returns all useForm methods plus ready-to-spread `generatorProps`.
895
+ *
896
+ * @example
897
+ * ```tsx
898
+ * const { handleSubmit, generatorProps } = useFormKit({
899
+ * schema: formSchema,
900
+ * resolver: zodResolver(validationSchema),
901
+ * });
902
+ *
903
+ * return (
904
+ * <form onSubmit={handleSubmit(onSubmit)}>
905
+ * <FormGenerator {...generatorProps} />
906
+ * <button type="submit">Submit</button>
907
+ * </form>
908
+ * );
909
+ * ```
910
+ */
911
+ declare function useFormKit<TFieldValues extends FieldValues = FieldValues>(options: UseFormKitOptions<TFieldValues>): UseFormKitReturn<TFieldValues>;
912
+ //#endregion
913
+ export { type BaseField, type ClassValue, type ComponentRegistry, type Condition, type ConditionConfig, type ConditionRule, type DefaultLayoutProps, type DefineField, type FieldComponent, type FieldComponentProps, type FieldOption, type FieldOptionGroup, type FieldType, FieldWrapper, type FormElement, FormGenerator, type FormGeneratorProps, type FormSchema, type FormSystemContextValue, FormSystemProvider, type FormSystemProviderProps, type GridLayoutProps, GridRenderer, type InferSchemaValues, type LayoutComponent, type LayoutComponentProps, type LayoutRegistry, type LayoutType, type SchemaFieldNames, type Section, type SectionLayoutProps, type SectionRenderProps, SectionRenderer, type UseFormKitOptions, type UseFormKitReturn, type ValidationRules, type Variant, buildValidationRules, cn, defineField, defineSchema, defineSection, evaluateCondition, extractDefaultValues, extractWatchNames, field, section, sectionUntitled, shallowEqual, useFieldComponent, useFormKit, useFormSystem, useLayoutComponent };
914
+ //# sourceMappingURL=index.d.mts.map