@classytic/formkit 1.2.0 → 1.2.2

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 CHANGED
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.2.2] - 2026-02-26
9
+
10
+ ### Fixed
11
+
12
+ - **`useFormKit` referential stability** — Return value now preserves the original `useForm` object identity across re-renders using `Object.assign` instead of object spread. Previously, spreading `{...form, generatorProps}` created a new object every render, which caused infinite loops when the form was used in `useEffect` dependency arrays (e.g., `form.reset()` in effects triggered re-renders → new object → effect fires again)
13
+ - **`generatorProps` memoized** — The `generatorProps` object returned by `useFormKit` is now wrapped in `useMemo`, preventing unnecessary re-renders of `<FormGenerator />` when unrelated props change
14
+
15
+ ### Added
16
+
17
+ - **Referential stability test** — New test case verifying that `useFormKit` return value and its methods (`reset`, `setValue`, `handleSubmit`) maintain referential identity across re-renders
18
+
8
19
  ## [1.1.0] - 2026-02-24
9
20
 
10
21
  ### Added
@@ -75,4 +86,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
75
86
  ### Added
76
87
 
77
88
  - Initial release
78
-
package/README.md CHANGED
@@ -12,7 +12,7 @@ Headless, type-safe form generation engine for React 19. Schema-driven with full
12
12
  - **Headless** - Bring your own UI components (Shadcn, MUI, Chakra, etc.)
13
13
  - **Schema-driven** - Define forms with JSON/TypeScript schemas, defaults extracted automatically
14
14
  - **Type-safe** - Full TypeScript support with generics
15
- - **React Hook Form** - Built on top of the best form library
15
+ - **React Hook Form** - Built on top of the best form library, referentially stable return values
16
16
  - **React 19** - Uses modern React 19 patterns (Context as provider, ref as prop)
17
17
  - **Server Components** - Dedicated `@classytic/formkit/server` entry point for RSC
18
18
  - **Variants** - Support for multiple component variants
@@ -25,7 +25,7 @@ Headless, type-safe form generation engine for React 19. Schema-driven with full
25
25
  ## Requirements
26
26
 
27
27
  - **React 19.0+** (React 18 is not supported)
28
- - **React Hook Form 7.54.0+**
28
+ - **React Hook Form 7.55.0+**
29
29
 
30
30
  ## Installation
31
31
 
@@ -74,9 +74,7 @@ export function FormInput({
74
74
  </Label>
75
75
  )}
76
76
  <Input {...rhfField} id={fieldId} placeholder={placeholder} />
77
- {error && (
78
- <p className="text-sm text-red-500">{error.message}</p>
79
- )}
77
+ {error && <p className="text-sm text-red-500">{error.message}</p>}
80
78
  </div>
81
79
  )}
82
80
  />
@@ -154,15 +152,39 @@ const formSchema: FormSchema<SignupData> = {
154
152
  title: "Personal Information",
155
153
  cols: 2,
156
154
  fields: [
157
- { name: "firstName", type: "text", label: "First Name", required: true, defaultValue: "" },
158
- { name: "lastName", type: "text", label: "Last Name", required: true, defaultValue: "" },
155
+ {
156
+ name: "firstName",
157
+ type: "text",
158
+ label: "First Name",
159
+ required: true,
160
+ defaultValue: "",
161
+ },
162
+ {
163
+ name: "lastName",
164
+ type: "text",
165
+ label: "Last Name",
166
+ required: true,
167
+ defaultValue: "",
168
+ },
159
169
  ],
160
170
  },
161
171
  {
162
172
  title: "Account",
163
173
  fields: [
164
- { name: "email", type: "email", label: "Email", required: true, defaultValue: "" },
165
- { name: "password", type: "password", label: "Password", required: true, defaultValue: "" },
174
+ {
175
+ name: "email",
176
+ type: "email",
177
+ label: "Email",
178
+ required: true,
179
+ defaultValue: "",
180
+ },
181
+ {
182
+ name: "password",
183
+ type: "password",
184
+ label: "Password",
185
+ required: true,
186
+ defaultValue: "",
187
+ },
166
188
  ],
167
189
  },
168
190
  ],
@@ -191,19 +213,28 @@ export default function SignupPage() {
191
213
 
192
214
  Convenience hook that combines schema default extraction with react-hook-form setup. Returns all `useForm` methods plus ready-to-spread `generatorProps`.
193
215
 
216
+ **Referentially stable** — the return value preserves the original `useForm` object identity across re-renders, so it's safe to use in `useEffect` dependency arrays.
217
+
194
218
  ```tsx
195
219
  import { useFormKit, FormGenerator } from "@classytic/formkit";
196
220
 
197
- const { handleSubmit, generatorProps, formState, reset, ...rest } = useFormKit({
221
+ const form = useFormKit({
198
222
  schema: formSchema,
199
223
  resolver: zodResolver(validationSchema), // optional
200
224
  defaultValues: { email: "pre@fill.com" }, // optional overrides
201
- disabled: false, // optional
202
- variant: "compact", // optional
203
- className: "my-form", // optional
204
- mode: "onBlur", // any useForm option
225
+ disabled: false, // optional
226
+ variant: "compact", // optional
227
+ className: "my-form", // optional
228
+ mode: "onBlur", // any useForm option
205
229
  });
206
230
 
231
+ const { handleSubmit, generatorProps } = form;
232
+
233
+ // Safe to use in useEffect deps — form is referentially stable
234
+ useEffect(() => {
235
+ if (open) form.reset(defaults);
236
+ }, [open, form]);
237
+
207
238
  return (
208
239
  <form onSubmit={handleSubmit(onSubmit)}>
209
240
  <FormGenerator {...generatorProps} />
@@ -214,18 +245,20 @@ return (
214
245
 
215
246
  Schema `defaultValue` fields are automatically extracted and merged with any explicit `defaultValues` you provide (explicit values take priority).
216
247
 
248
+ `generatorProps` is memoized — it only recomputes when `schema`, `control`, `disabled`, `variant`, or `className` change.
249
+
217
250
  ### FormGenerator
218
251
 
219
252
  The main component that renders forms from a schema. Supports React 19 `ref` as a regular prop.
220
253
 
221
254
  ```tsx
222
255
  <FormGenerator
223
- schema={formSchema} // Required: Form schema
224
- control={form.control} // Optional: React Hook Form control (or wrap in <FormProvider>)
225
- disabled={false} // Optional: Disable all fields
226
- variant="default" // Optional: Global variant
227
- className="my-form" // Optional: Root element class
228
- ref={formRef} // Optional: Ref to the root <div> (React 19 ref-as-prop)
256
+ schema={formSchema} // Required: Form schema
257
+ control={form.control} // Optional: React Hook Form control (or wrap in <FormProvider>)
258
+ disabled={false} // Optional: Disable all fields
259
+ variant="default" // Optional: Global variant
260
+ className="my-form" // Optional: Root element class
261
+ ref={formRef} // Optional: Ref to the root <div> (React 19 ref-as-prop)
229
262
  />
230
263
  ```
231
264
 
@@ -241,18 +274,18 @@ interface FormSchema<T extends FieldValues = FieldValues> {
241
274
 
242
275
  ```ts
243
276
  interface Section<T> {
244
- id?: string; // Unique identifier
245
- title?: string; // Section title
246
- description?: string; // Section description
247
- icon?: ReactNode; // Section icon
248
- fields?: BaseField<T>[]; // Fields in this section
249
- cols?: number; // Grid columns (1-6)
250
- gap?: number; // Grid gap
251
- variant?: string; // Section variant
252
- className?: string; // Custom class
253
- collapsible?: boolean; // Make section collapsible
277
+ id?: string; // Unique identifier
278
+ title?: string; // Section title
279
+ description?: string; // Section description
280
+ icon?: ReactNode; // Section icon
281
+ fields?: BaseField<T>[]; // Fields in this section
282
+ cols?: number; // Grid columns (1-6)
283
+ gap?: number; // Grid gap
284
+ variant?: string; // Section variant
285
+ className?: string; // Custom class
286
+ collapsible?: boolean; // Make section collapsible
254
287
  defaultCollapsed?: boolean;
255
- nameSpace?: string; // Prefix for nested object fields (e.g. "address")
288
+ nameSpace?: string; // Prefix for nested object fields (e.g. "address")
256
289
 
257
290
  // Conditional rendering (function, DSL rule, or ConditionConfig)
258
291
  condition?: Condition<T>;
@@ -266,25 +299,27 @@ interface Section<T> {
266
299
 
267
300
  ```ts
268
301
  interface BaseField<T> {
269
- name: string; // Field name (required)
270
- type: FieldType; // Field type (required)
271
- label?: string; // Field label
272
- placeholder?: string; // Placeholder text
273
- helperText?: string; // Helper text below field
274
- disabled?: boolean; // Disable field
275
- required?: boolean; // Mark as required
276
- readOnly?: boolean; // Read-only field
277
- variant?: string; // Field variant
278
- fullWidth?: boolean; // Span full grid width
279
- className?: string; // Custom class
280
- defaultValue?: unknown; // Default value
302
+ name: string; // Field name (required)
303
+ type: FieldType; // Field type (required)
304
+ label?: string; // Field label
305
+ placeholder?: string; // Placeholder text
306
+ helperText?: string; // Helper text below field
307
+ disabled?: boolean; // Disable field
308
+ required?: boolean; // Mark as required
309
+ readOnly?: boolean; // Read-only field
310
+ variant?: string; // Field variant
311
+ fullWidth?: boolean; // Span full grid width
312
+ className?: string; // Custom class
313
+ defaultValue?: unknown; // Default value
281
314
 
282
315
  // Conditional rendering
283
316
  condition?: Condition<T>;
284
- watchNames?: string | string[]; // Optimize useWatch performance
317
+ watchNames?: string | string[]; // Optimize useWatch performance
285
318
 
286
319
  // Dynamic options loading
287
- loadOptions?: (formValues: Partial<T>) => Promise<FieldOption[]> | FieldOption[];
320
+ loadOptions?: (
321
+ formValues: Partial<T>,
322
+ ) => Promise<FieldOption[]> | FieldOption[];
288
323
  debounceMs?: number;
289
324
 
290
325
  // For array/grouped types
@@ -319,21 +354,23 @@ interface BaseField<T> {
319
354
  Props passed to your field components:
320
355
 
321
356
  ```ts
322
- interface FieldComponentProps<T extends FieldValues = FieldValues>
323
- extends BaseField<T> {
324
- field: BaseField<T>; // Full field config
325
- control: Control<T>; // React Hook Form control
326
- disabled?: boolean; // Merged disabled state
327
- variant?: string; // Active variant
328
- error?: FieldError; // Field error from react-hook-form
329
- fieldState?: { // Field state metadata
357
+ interface FieldComponentProps<
358
+ T extends FieldValues = FieldValues,
359
+ > extends BaseField<T> {
360
+ field: BaseField<T>; // Full field config
361
+ control: Control<T>; // React Hook Form control
362
+ disabled?: boolean; // Merged disabled state
363
+ variant?: string; // Active variant
364
+ error?: FieldError; // Field error from react-hook-form
365
+ fieldState?: {
366
+ // Field state metadata
330
367
  invalid: boolean;
331
368
  isDirty: boolean;
332
369
  isTouched: boolean;
333
370
  isValidating: boolean;
334
371
  error?: FieldError;
335
372
  };
336
- fieldId: string; // Generated ID for label-input association (e.g. "formkit-field-email")
373
+ fieldId: string; // Generated ID for label-input association (e.g. "formkit-field-email")
337
374
  }
338
375
  ```
339
376
 
@@ -663,7 +700,11 @@ function FormTextarea({ field, customProps, ...props }: FieldComponentProps) {
663
700
  Type-safe helpers for defining schemas outside of components:
664
701
 
665
702
  ```ts
666
- import { defineSchema, defineField, defineSection } from "@classytic/formkit/server";
703
+ import {
704
+ defineSchema,
705
+ defineField,
706
+ defineSection,
707
+ } from "@classytic/formkit/server";
667
708
 
668
709
  const emailField = defineField<MyFormData>({
669
710
  name: "email",
package/dist/index.d.mts CHANGED
@@ -390,8 +390,8 @@ interface FormSystemProviderProps {
390
390
  * @template TFieldValues - Form field values type
391
391
  */
392
392
  interface FormGeneratorProps<TFieldValues extends FieldValues = FieldValues> {
393
- /** Form schema defining sections and fields */
394
- schema: FormSchema<TFieldValues>;
393
+ /** Form schema defining sections and fields. Accepts any FormSchema generic. */
394
+ schema: FormSchema<any>;
395
395
  /** React Hook Form control object */
396
396
  control?: Control<TFieldValues>;
397
397
  /** Global disabled state for all fields */
@@ -870,8 +870,8 @@ declare function sectionUntitled<TFieldValues extends FieldValues = FieldValues>
870
870
  * Extends react-hook-form's UseFormProps with schema-driven defaults.
871
871
  */
872
872
  interface UseFormKitOptions<TFieldValues extends FieldValues = FieldValues> extends Omit<UseFormProps<TFieldValues>, "defaultValues"> {
873
- /** Form schema defining sections and fields */
874
- schema: FormSchema<TFieldValues>;
873
+ /** Form schema defining sections and fields. Accepts any FormSchema generic. */
874
+ schema: FormSchema<any>;
875
875
  /** Override or extend default values extracted from schema */
876
876
  defaultValues?: UseFormProps<TFieldValues>["defaultValues"];
877
877
  /** Disable all fields */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/FormGenerator.tsx","../src/FormSystemContext.tsx","../src/utils.ts","../src/schema.ts","../src/builders.ts","../src/useFormKit.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/FormGenerator.tsx","../src/FormSystemContext.tsx","../src/utils.ts","../src/schema.ts","../src/builders.ts","../src/useFormKit.ts"],"mappings":";;;;;;;;;AAWA;KAAY,SAAA;;;;KAyBA,UAAA;;;;KAKA,OAAA;AAAA,UAWK,aAAA,sBAAmC,WAAA,GAAc,WAAA;EAChE,KAAA,EAAO,IAAA,CAAK,YAAA;EACZ,QAAA;EACA,KAAA;AAAA;AAHF;;;;;;;;;;;;;;;;AAAA,UAsBiB,eAAA,sBACM,WAAA,GAAc,WAAA;EApB9B;EAuBL,KAAA,EAAO,aAAA,CAAc,YAAA;EAJN;EAMf,KAAA;AAAA;;;;UAMe,WAAA;EARK;EAUpB,KAAA;EAbA;EAeA,KAAA,EAAO,MAAA;EAf4B;EAiBnC,QAAA;EAdO;EAgBP,WAAA;EAdA;EAgBA,IAAA,GAAO,SAAA;AAAA;AAVT;;;AAAA,UAgBiB,gBAAA;EAhBY;EAkB3B,KAAA;EAdA;EAgBA,OAAA,EAAS,WAAA,CAAY,MAAA;EAdrB;EAgBA,QAAA;AAAA;;;;AANF;UAiBiB,SAAA,sBAA+B,WAAA,GAAc,WAAA;EAjB7B;EAmB/B,IAAA,EAAM,IAAA,CAAK,YAAA;EAnBqB;EAqBhC,IAAA,EAAM,SAAA;EAjBN;EAmBA,KAAA;EAnBqB;EAqBrB,WAAA;EAnBQ;EAqBR,UAAA;EAVe;EAYf,QAAA;EAZwB;EAcxB,QAAA;EAd4D;EAgB5D,QAAA;EAdM;EAgBN,OAAA,GAAU,OAAA;EAAA;EAEV,SAAA;EAQkB;EANlB,SAAA;EAOI;;;;EAFJ,SAAA,KACM,UAAA,EAAY,OAAA,CAAQ,YAAA,iBACtB,aAAA,CAAc,YAAA,IACd,aAAA,CAAc,YAAA,MACd,eAAA,CAAgB,YAAA;EAIT;EAFX,YAAA;EAkCsB;EAhCtB,OAAA,IAAW,WAAA,GAAc,gBAAA;EAkCZ;EAhCb,GAAA;EAgCI;EA9BJ,GAAA;EA+BmB;EA7BnB,IAAA;EAyCa;EAvCb,OAAA;EA6CiB;EA3CjB,SAAA;EAwDgD;EAtDhD,SAAA;EA4DkB;EA1DlB,IAAA;EA0DuC;EAxDvC,QAAA;EA2Dc;EAzDd,MAAA;EAyDoB;EAvDpB,YAAA;EAvD8C;EAyD9C,SAAA;EAvDA;EA0DA,UAAA;EA1DW;;;;EAgEX,WAAA,IACE,UAAA,EAAY,OAAA,CAAQ,YAAA,MAElB,OAAA,EAAS,WAAA,GAAc,gBAAA,QACtB,WAAA,GAAc,gBAAA;EA5DnB;;;;EAkEA,WAAA,IAAe,KAAA;EA1DL;;;;EAgEV,UAAA,GAAa,SAAA,CAAU,YAAA;EAtDG;;;;EA4D1B,MAAA,IAAU,KAAA,EAAO,mBAAA,CAAoB,YAAA,MAAkB,SAAA;EA1DrC;;;;;;;;;;;EAuElB,QAAA,IAAY,KAAA,WAAgB,UAAA,EAAY,OAAA,CAAQ,YAAA;EAtDhD;;;;EA4DA,UAAA,GAAa,IAAA,CAAK,YAAA,IAAgB,IAAA,CAAK,YAAA;EAlDvC;EAqDA,WAAA,GAAc,MAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAmCC,mBAAA,sBACM,WAAA,GAAc,WAAA,UAC3B,SAAA,CAAU,YAAA;EArCJ;EAuCd,KAAA,EAAO,SAAA,CAAU,YAAA;EAvCG;EAyCpB,OAAA,EAAS,OAAA,CAAQ,YAAA;EANiB;EAQlC,QAAA;EAPqB;EASrB,OAAA,GAAU,OAAA;EARQ;EAUlB,KAAA,GAAQ,UAAA;EARD;EAUP,UAAA;IACE,OAAA;IACA,OAAA;IACA,SAAA;IACA,YAAA;IACA,KAAA,GAAQ,UAAA;EAAA;EAjBO;EAoBjB,OAAA;EArBqB;EAuBrB,SAAA;AAAA;;;;;KAOU,cAAA,sBAAoC,WAAA,GAAc,WAAA,IAC5D,aAAA,CAAc,mBAAA,CAAoB,YAAA;;;;;KAUxB,eAAA,GAAkB,IAAA,CAC5B,eAAA;;;;;UAYe,OAAA,sBAA6B,WAAA,GAAc,WAAA;EAtCxD;EAwCF,EAAA;EAtCE;EAwCF,KAAA;EArCA;EAuCA,WAAA;EArCS;EAuCT,IAAA,GAAO,SAAA;EAhCG;EAkCV,SAAA;EAlCwB;EAoCxB,MAAA,GAAS,SAAA,CAAU,YAAA;EApCyC;EAsC5D,IAAA;EArCc;EAuCd,GAAA;EAvCa;;;;EA4Cb,MAAA,IAAU,KAAA,EAAO,kBAAA,CAAmB,YAAA,MAAkB,SAAA;EA5CtD;EA8CA,OAAA,GAAU,OAAA;EA9CwB;EAgDlC,SAAA;EAhD8C;AAUhD;;;EA2CE,SAAA,KACM,UAAA,GAAa,OAAA,CAAQ,YAAA,iBACvB,aAAA,CAAc,YAAA,IACd,aAAA,CAAc,YAAA,MACd,eAAA,CAAgB,YAAA;EA9CL;EAgDf,WAAA;EApCsB;EAsCtB,gBAAA;AAAA;;;;UAMe,kBAAA,sBACM,WAAA,GAAc,WAAA;EAEnC,OAAA,GAAU,OAAA,CAAQ,YAAA;EAClB,QAAA;EACA,OAAA,EAAS,OAAA,CAAQ,YAAA;AAAA;;;;UAUF,kBAAA;EA1BG;EA4BlB,KAAA;EA3BoB;EA6BpB,WAAA;EA7BmB;EA+BnB,IAAA,GAAO,SAAA;EAjEgB;EAmEvB,OAAA,GAAU,OAAA;EAnEgD;EAqE1D,SAAA;EAjEA;EAmEA,WAAA;EA/DA;EAiEA,gBAAA;EA/DA;EAiEA,QAAA,EAAU,SAAA;AAAA;;;;UAMK,eAAA;EA5DE;EA8DjB,IAAA;EA9DU;EAgEV,GAAA;EA9DA;EAgEA,SAAA;EA9DA;EAgEA,QAAA,EAAU,SAAA;AAAA;;;;UAMK,kBAAA;EA9DX;EAgEJ,SAAA;EA/DI;EAiEJ,QAAA,EAAU,SAAA;AAAA;;;;KAMA,oBAAA,GACR,kBAAA,GACA,eAAA,GACA,kBAAA;;;;KAKQ,eAAA,gBACK,oBAAA,GAAuB,oBAAA,IACpC,aAAA,CAAc,MAAA;;;;;UAUD,UAAA,sBAAgC,WAAA,GAAc,WAAA;EA5E7C;EA8EhB,QAAA,EAAU,OAAA,CAAQ,YAAA;AAAA;;;;;;;;;;;AApEpB;;;;;;UA2FiB,iBAAA;EAAA,CACd,GAAA,WAAc,cAAA,CAAe,WAAA,IAAe,iBAAA;AAAA;;;;;UAO9B,cAAA;EAAA,CACd,GAAA,WACG,eAAA,CAAgB,kBAAA,GAAqB,eAAA,GAAkB,kBAAA,IACvD,cAAA;AAAA;;;;UAUW,sBAAA;EAhGI;EAkGnB,UAAA,EAAY,iBAAA;EA5FkB;EA8F9B,OAAA,EAAS,cAAA;AAAA;;;;UAMM,uBAAA;EA5FL;EA8FV,UAAA,GAAa,iBAAA;EA9FM;EAgGnB,OAAA,GAAU,cAAA;EA1FuB;EA4FjC,QAAA,EAAU,SAAA;AAAA;;;;;UAWK,kBAAA,sBACM,WAAA,GAAc,WAAA;EA9FzB;EAiGV,MAAA,EAAQ,UAAA;;EAER,OAAA,GAAU,OAAA,CAAQ,YAAA;EAjGhB;EAmGF,QAAA;EAlGoB;EAoGpB,OAAA,GAAU,OAAA;EAtGR;EAwGF,SAAA;EAtGE;EAwGF,GAAA,GAAM,GAAA,CAAI,cAAA;AAAA;AAnGZ;;;AAAA,KA6GY,gBAAA,iBAAiC,UAAA,IAC3C,OAAA,SAAgB,UAAA,kBAA4B,CAAA;;;;KAKlC,iBAAA,iBAAkC,UAAA,IAC5C,OAAA,SAAgB,UAAA,YAAsB,CAAA,GAAI,WAAA;;;;KAKhC,WAAA,sBACW,WAAA,gBACP,SAAA,GAAY,SAAA,IACxB,SAAA,CAAU,YAAA;EAAkB,IAAA,EAAM,KAAA;AAAA;;;AAhHtC;KAqHY,WAAA,GAAc,GAAA,CAAI,OAAA;;;;;;AAtiB9B;;;;;AAyBA;;;;;AAKA;;;;;AAWA;;;;;;;iBC2EgB,aAAA,sBAAmC,WAAA,GAAc,WAAA,CAAA,CAAA;EAC/D,MAAA;EACA,OAAA;EACA,QAAA;EACA,OAAA;EACA,SAAA;EACA;AAAA,GACC,kBAAA,CAAmB,YAAA,IAAgB,WAAA;AAAA,UA4C5B,oBAAA,sBAA0C,WAAA,GAAc,WAAA;EAChE,OAAA,EAAS,OAAA,CAAQ,YAAA;EACjB,OAAA,GAAU,OAAA,CAAQ,YAAA;EAClB,QAAA;EACA,OAAA,GAAU,OAAA;AAAA;;;;iBAMH,eAAA,sBAAqC,WAAA,GAAc,WAAA,CAAA,CAC1D,KAAA,EAAO,oBAAA,CAAqB,YAAA,IAC3B,WAAA;AAAA,UAmGO,iBAAA,sBAAuC,WAAA,GAAc,WAAA;EAC7D,MAAA,GAAS,SAAA,CAAU,YAAA;EACnB,IAAA;EACA,GAAA;EACA,OAAA,GAAU,OAAA,CAAQ,YAAA;EAClB,QAAA;EACA,OAAA,GAAU,OAAA;AAAA;;;;iBAMH,YAAA,sBAAkC,WAAA,GAAc,WAAA,CAAA,CAAA;EACvD,MAAA;EACA,IAAA;EACA,GAAA;EACA,OAAA;EACA,QAAA;EACA;AAAA,GACC,iBAAA,CAAkB,YAAA,IAAgB,WAAA;AAAA,UA0B3B,iBAAA,sBAAuC,WAAA,GAAc,WAAA;EAC7D,KAAA,EAAO,SAAA,CAAU,YAAA;EACjB,OAAA,GAAU,OAAA,CAAQ,YAAA;EAClB,QAAA;EACA,OAAA,GAAU,OAAA;AAAA;;AD5PZ;;;;iBCoQS,YAAA,sBAAkC,WAAA,GAAc,WAAA,CAAA,CACvD,KAAA,EAAO,iBAAA,CAAkB,YAAA,IACxB,WAAA;;;;;;;ADjVH;;;;;AAyBA;;;;;AAKA;;;;;AAWA;;;;;;;;;;;;;;iBEWgB,kBAAA,CAAA;EACd,UAAA;EACA,OAAA;EACA;AAAA,GACC,uBAAA,GAA0B,WAAA;;;;;AFO7B;;;;;;;iBEoBgB,aAAA,CAAA,GAAiB,sBAAA;;;;;;;;;;;AFRjC;;;;;iBEkCgB,iBAAA,CAAkB,IAAA,EAAM,SAAA,EAAW,OAAA,GAAU,OAAA,GAAU,cAAA;;;;;;;;;AFlBvE;;;;;;;iBE4EgB,kBAAA,CACd,IAAA,EAAM,UAAA,EACN,OAAA,GAAU,OAAA,GACT,eAAA,CAAgB,kBAAA,GAAqB,eAAA,GAAkB,kBAAA;;;;;;;AF1K1D;;;;;AAyBA;;;;;AAKA;;;;;AAWA;;iBG3BgB,EAAA,CAAA,GAAM,MAAA,EAAQ,UAAA;;;;;iBAQd,YAAA,CAAa,CAAA,WAAY,CAAA;;;;;;KChB7B,SAAA,sBAA+B,WAAA,GAAc,WAAA,MACnD,UAAA,EAAY,OAAA,CAAQ,YAAA,iBACtB,aAAA,CAAc,YAAA,IACd,aAAA,CAAc,YAAA,MACd,eAAA,CAAgB,YAAA;;;;;AJepB;;;;iBIsFgB,iBAAA,sBACO,WAAA,GAAc,WAAA,CAAA,CAEnC,SAAA,EAAW,SAAA,CAAU,YAAA,GACrB,UAAA,EAAY,OAAA,CAAQ,YAAA;AJrFtB;;;;AAAA,iBIwGgB,iBAAA,sBACO,WAAA,GAAc,WAAA,CAAA,CACnC,SAAA,EAAW,SAAA,CAAU,YAAA;AJ/FvB;;;AAAA,iBIyGgB,YAAA,sBAAkC,WAAA,GAAc,WAAA,CAAA,CAC9D,MAAA,EAAQ,UAAA,CAAW,YAAA,IAClB,UAAA,CAAW,YAAA;;;;iBAOE,WAAA,sBAAiC,WAAA,GAAc,WAAA,CAAA,CAC7D,KAAA,EAAO,SAAA,CAAU,YAAA,IAChB,SAAA,CAAU,YAAA;;;;iBAOG,aAAA,sBAAmC,WAAA,GAAc,WAAA,CAAA,CAC/D,OAAA,EAAS,OAAA,CAAQ,YAAA,IAChB,OAAA,CAAQ,YAAA;;;;;;;;AJvGX;;;iBIqHgB,oBAAA,sBACO,WAAA,GAAc,WAAA,CAAA,CACnC,MAAA,EAAQ,UAAA,CAAW,YAAA,IAAgB,OAAA,CAAQ,YAAA;;;;;;;;;;;;;;;AJ3G7C;iBIqJgB,oBAAA,sBACO,WAAA,GAAc,WAAA,CAAA,CACnC,KAAA,EAAO,SAAA,CAAU,YAAA,IAAgB,eAAA;;;;;AJlOnC;;;KKOK,UAAA,sBAAgC,WAAA,GAAc,WAAA,IAAe,IAAA,CAChE,SAAA,CAAU,YAAA;ELRS,6CKYnB,UAAA,WLaoB;EKXpB,QAAA,GAAW,SAAA,ELWS;EKTpB,SAAA,GAAY,SAAA,ELcF;EAAA,CKZT,GAAA;AAAA;;;ALuBH;UKjBU,YAAA,sBAAkC,WAAA,GAAc,WAAA,UAChD,IAAA,CAAK,OAAA,CAAQ,YAAA;EACrB,IAAA;AAAA;;;;KAMG,cAAA,IAAkB,KAAA;EACrB,OAAA,EAAS,OAAA,CAAQ,WAAA;EACjB,QAAA;EACA,KAAA,GAAQ,UAAA;AAAA,MACJ,SAAA;;;;;;;;AL2BN;;;;;;;;;;;;;;;;;cKGa,KAAA;ELSI;;;uBKJD,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;ELCwB;;;wBKUb,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;ELPH;;;sBKmBc,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;ELlBa;;AAMlB;sBKwBgB,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;EL3B4B;;;2BKuCjB,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;ELtCH;;;yBKiDc,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;ELlDK;;AAWV;2BKmDgB,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;ELtDqB;;;yBKkEV,KAAA,UACC,OAAA,GACH,WAAA,GAAc,gBAAA,KAAmB,KAAA,GACpC,UAAA,KACN,SAAA;ELpEG;;;2BKgFQ,KAAA,UACC,OAAA,GACH,WAAA,GAAc,gBAAA,KAAmB,KAAA,GACpC,UAAA,KACN,SAAA;EL1De;;;8BKsEJ,KAAA,UACC,OAAA,GACH,WAAA,GAAc,gBAAA,KAAmB,KAAA,GACpC,UAAA,KACN,SAAA;ELxEC;;;kCKqFU,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;ELnFsB;;;yBK8FX,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;EL/DwB;;;0BK0Eb,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;ELhEoB;;;2BK2ET,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;ELxEoD;;;wBKmFzC,KAAA,UACC,OAAA,EACJ,WAAA,IAAa,KAAA,GACf,UAAA,KACN,SAAA;ELpEU;;;uBKgFC,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;ELhFiB;;;uBK2FN,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;EL5MyD;;;uBKwN9C,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;ELvNH;;;uBKmOc,KAAA,UACC,KAAA,GACN,UAAA,KACN,SAAA;ELhOH;;;yBK2Oc,KAAA,GACL,UAAA,KACN,SAAA;ELrOH;;;;;;;;;;;;;wBKyPc,KAAA,UACC,UAAA,EACD,SAAA,IAAW,KAAA,GAChB,UAAA,KACN,SAAA;EL9OH;;;;;;;;;;;;wBKmQc,KAAA,UACC,UAAA,EACD,SAAA,IAAW,KAAA,GAChB,UAAA,KACN,SAAA;ELjPH;;;;;;;;;;;yBKqQc,KAAA,UACC,MAAA,EACL,cAAA,EAAc,KAAA,GACf,UAAA,KACN,SAAA;AAAA;;;;;;;;;;;;;;;;;iBA6BW,OAAA,sBAA6B,WAAA,GAAc,WAAA,CAAA,CACzD,EAAA,UACA,KAAA,UACA,MAAA,EAAQ,SAAA,CAAU,YAAA,KAClB,KAAA,GAAO,YAAA,CAAa,YAAA,IACnB,OAAA,CAAQ,YAAA;;;;;iBAeK,eAAA,sBAAqC,WAAA,GAAc,WAAA,CAAA,CACjE,MAAA,EAAQ,SAAA,CAAU,YAAA,KAClB,KAAA,GAAO,IAAA,CAAK,YAAA,CAAa,YAAA,gBACxB,OAAA,CAAQ,YAAA;;;;;;ALheX;UMKiB,iBAAA,sBACM,WAAA,GAAc,WAAA,UAC3B,IAAA,CAAK,YAAA,CAAa,YAAA;;EAE1B,MAAA,EAAQ,UAAA;ENTW;EMWnB,aAAA,GAAgB,YAAA,CAAa,YAAA;ENcT;EMZpB,QAAA;ENYoB;EMVpB,OAAA,GAAU,OAAA;ENeA;EMbV,SAAA;AAAA;;;ANwBF;;UMjBiB,gBAAA,sBACM,WAAA,GAAc,WAAA,UAC3B,aAAA,CAAc,YAAA;ENe4B;EMblD,cAAA,EAAgB,IAAA,CACd,kBAAA,CAAmB,YAAA;AAAA;;;;;;;;;;;;;;ANkCvB;;;;;;iBMNgB,UAAA,sBAAgC,WAAA,GAAc,WAAA,CAAA,CAC5D,OAAA,EAAS,iBAAA,CAAkB,YAAA,IAC1B,gBAAA,CAAiB,YAAA"}
package/dist/index.mjs CHANGED
@@ -1023,16 +1023,20 @@ function useFormKit(options) {
1023
1023
  ...formOptions,
1024
1024
  defaultValues: mergedDefaults
1025
1025
  });
1026
- return {
1027
- ...form,
1028
- generatorProps: {
1029
- schema,
1030
- control: form.control,
1031
- disabled,
1032
- variant,
1033
- className
1034
- }
1035
- };
1026
+ const generatorProps = useMemo(() => ({
1027
+ schema,
1028
+ control: form.control,
1029
+ disabled,
1030
+ variant,
1031
+ className
1032
+ }), [
1033
+ schema,
1034
+ form.control,
1035
+ disabled,
1036
+ variant,
1037
+ className
1038
+ ]);
1039
+ return Object.assign(form, { generatorProps });
1036
1040
  }
1037
1041
 
1038
1042
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["getNestedValue"],"sources":["../src/FormSystemContext.tsx","../src/utils.ts","../src/schema.ts","../src/FormGenerator.tsx","../src/builders.ts","../src/useFormKit.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport { createContext, useContext, useMemo } from \"react\";\r\nimport type {\r\n FormSystemContextValue,\r\n FormSystemProviderProps,\r\n FieldComponent,\r\n LayoutComponent,\r\n FieldType,\r\n LayoutType,\r\n Variant,\r\n SectionLayoutProps,\r\n GridLayoutProps,\r\n DefaultLayoutProps,\r\n FormElement,\r\n} from \"./types\";\r\n\r\n// ============================================================================\r\n// Context\r\n// ============================================================================\r\n\r\nconst FormSystemContext = createContext<FormSystemContextValue | null>(null);\r\n\r\n// Display name for React DevTools\r\nFormSystemContext.displayName = \"FormSystemContext\";\r\n\r\n// ============================================================================\r\n// Provider\r\n// ============================================================================\r\n\r\n/**\r\n * FormSystemProvider\r\n *\r\n * Root provider that enables the form system. Provides component and layout\r\n * registries to FormGenerator and its descendants.\r\n *\r\n * @example\r\n * ```tsx\r\n * import { FormSystemProvider } from '@classytic/formkit';\r\n *\r\n * const components = {\r\n * text: TextInput,\r\n * select: SelectInput,\r\n * // Variant-specific components\r\n * compact: {\r\n * text: CompactTextInput,\r\n * },\r\n * };\r\n *\r\n * const layouts = {\r\n * section: SectionLayout,\r\n * grid: GridLayout,\r\n * };\r\n *\r\n * function App() {\r\n * return (\r\n * <FormSystemProvider components={components} layouts={layouts}>\r\n * <YourFormComponent />\r\n * </FormSystemProvider>\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport function FormSystemProvider({\r\n components,\r\n layouts,\r\n children,\r\n}: FormSystemProviderProps): FormElement {\r\n const value = useMemo<FormSystemContextValue>(\r\n () => ({\r\n components: components ?? {},\r\n layouts: layouts ?? {},\r\n }),\r\n [components, layouts]\r\n );\r\n\r\n return <FormSystemContext value={value}>{children}</FormSystemContext>;\r\n}\r\n\r\n// ============================================================================\r\n// Hooks\r\n// ============================================================================\r\n\r\n/**\r\n * Hook to access the form system context.\r\n *\r\n * @throws {Error} If used outside FormSystemProvider\r\n * @returns Form system context value\r\n *\r\n * @example\r\n * ```tsx\r\n * const { components, layouts } = useFormSystem();\r\n * ```\r\n */\r\nexport function useFormSystem(): FormSystemContextValue {\r\n const context = useContext(FormSystemContext);\r\n if (!context) {\r\n throw new Error(\r\n \"[FormKit] useFormSystem must be used within a FormSystemProvider. \" +\r\n \"Make sure to wrap your form components with <FormSystemProvider>.\"\r\n );\r\n }\r\n return context;\r\n}\r\n\r\n/**\r\n * Hook to get a field component by type and optional variant.\r\n *\r\n * Resolution order:\r\n * 1. Variant-specific component: `components[variant][type]`\r\n * 2. Type-specific component: `components[type]`\r\n * 3. Default component: `components[\"default\"]`\r\n * 4. Text fallback: `components[\"text\"]`\r\n *\r\n * @param type - Field type identifier\r\n * @param variant - Optional variant name\r\n * @returns Field component or fallback\r\n *\r\n * @internal\r\n */\r\nexport function useFieldComponent(type: FieldType, variant?: Variant): FieldComponent {\r\n const { components } = useFormSystem();\r\n\r\n // 1. Try variant-specific component\r\n if (variant && typeof components[variant] === \"object\" && components[variant] !== null) {\r\n const variantComponents = components[variant] as Record<string, FieldComponent>;\r\n const variantComponent = variantComponents[type];\r\n if (variantComponent) {\r\n return variantComponent;\r\n }\r\n }\r\n\r\n // 2. Try type-specific component\r\n const typeComponent = components[type] as FieldComponent | undefined;\r\n if (typeComponent && typeof typeComponent === \"function\") {\r\n return typeComponent;\r\n }\r\n\r\n // 3. Try default component\r\n const defaultComponent = components[\"default\"] as FieldComponent | undefined;\r\n if (defaultComponent && typeof defaultComponent === \"function\") {\r\n return defaultComponent;\r\n }\r\n\r\n // 4. Try text fallback\r\n const textComponent = components[\"text\"] as FieldComponent | undefined;\r\n if (textComponent && typeof textComponent === \"function\") {\r\n return textComponent;\r\n }\r\n\r\n // 5. Development warning and placeholder\r\n if (process.env.NODE_ENV !== \"production\") {\r\n console.warn(\r\n `[FormKit] No component found for type \"${type}\"${variant ? ` (variant: \"${variant}\")` : \"\"}. ` +\r\n \"Register a component for this type in your FormSystemProvider.\"\r\n );\r\n return MissingFieldComponent;\r\n }\r\n\r\n // Production: silent fallback\r\n return NullComponent;\r\n}\r\n\r\n/**\r\n * Hook to get a layout component by type and optional variant.\r\n *\r\n * Resolution order:\r\n * 1. Variant-specific layout: `layouts[variant][type]`\r\n * 2. Type-specific layout: `layouts[type]`\r\n * 3. Default layout: `layouts[\"default\"]`\r\n * 4. Built-in default layout\r\n *\r\n * @param type - Layout type identifier\r\n * @param variant - Optional variant name\r\n * @returns Layout component or fallback\r\n *\r\n * @internal\r\n */\r\nexport function useLayoutComponent(\r\n type: LayoutType,\r\n variant?: Variant\r\n): LayoutComponent<SectionLayoutProps | GridLayoutProps | DefaultLayoutProps> {\r\n const { layouts } = useFormSystem();\r\n\r\n // 1. Try variant-specific layout\r\n if (variant && typeof layouts[variant] === \"object\" && layouts[variant] !== null) {\r\n const variantLayouts = layouts[variant] as Record<\r\n string,\r\n LayoutComponent<SectionLayoutProps | GridLayoutProps | DefaultLayoutProps>\r\n >;\r\n const variantLayout = variantLayouts[type];\r\n if (variantLayout) {\r\n return variantLayout;\r\n }\r\n }\r\n\r\n // 2. Try type-specific layout\r\n const typeLayout = layouts[type] as\r\n | LayoutComponent<SectionLayoutProps | GridLayoutProps | DefaultLayoutProps>\r\n | undefined;\r\n if (typeLayout && typeof typeLayout === \"function\") {\r\n return typeLayout;\r\n }\r\n\r\n // 3. Try default layout\r\n const defaultLayout = layouts[\"default\"] as\r\n | LayoutComponent<SectionLayoutProps | GridLayoutProps | DefaultLayoutProps>\r\n | undefined;\r\n if (defaultLayout && typeof defaultLayout === \"function\") {\r\n return defaultLayout;\r\n }\r\n\r\n // 4. Built-in default layout\r\n return DefaultLayout;\r\n}\r\n\r\n// ============================================================================\r\n// Fallback Components\r\n// ============================================================================\r\n\r\n/**\r\n * Default layout component - simple div wrapper.\r\n * Used when no layout is registered.\r\n */\r\nfunction DefaultLayout({ children, className }: DefaultLayoutProps): FormElement {\r\n return <div className={className}>{children}</div>;\r\n}\r\n\r\n/**\r\n * Null component for production fallback.\r\n */\r\nfunction NullComponent(): FormElement {\r\n return null;\r\n}\r\n\r\n/**\r\n * Development placeholder for missing field components.\r\n */\r\nfunction MissingFieldComponent({ field }: { field: { type: string; name: string } }): FormElement {\r\n return (\r\n <div\r\n style={{\r\n color: \"#dc2626\",\r\n padding: \"8px 12px\",\r\n border: \"1px dashed #dc2626\",\r\n borderRadius: \"4px\",\r\n fontSize: \"12px\",\r\n fontFamily: \"monospace\",\r\n backgroundColor: \"#fef2f2\",\r\n }}\r\n >\r\n Missing component: <strong>{field.type}</strong> (field: {field.name})\r\n </div>\r\n );\r\n}\r\n","import { clsx } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\nimport type { ClassValue } from \"clsx\";\r\n\r\n/**\r\n * Utility function to merge CSS classes with Tailwind CSS conflict resolution.\r\n *\r\n * Combines `clsx` for conditional class handling with `tailwind-merge`\r\n * for proper Tailwind CSS class conflict resolution.\r\n *\r\n * @param inputs - Class values to merge (strings, arrays, objects, or conditionals)\r\n * @returns Merged and deduplicated class string\r\n *\r\n * @example\r\n * ```tsx\r\n * // Basic usage\r\n * cn(\"px-2 py-1\", \"px-4\") // \"py-1 px-4\"\r\n *\r\n * // Conditional classes\r\n * cn(\"base\", isActive && \"active\", { \"disabled\": isDisabled })\r\n *\r\n * // Arrays\r\n * cn([\"flex\", \"items-center\"], \"gap-2\")\r\n * ```\r\n */\r\nexport function cn(...inputs: ClassValue[]): string {\r\n return twMerge(clsx(inputs));\r\n}\r\n\r\n/**\r\n * Shallow equality check for arrays and primitives.\r\n * Used to stabilize useWatch output without JSON.stringify overhead.\r\n */\r\nexport function shallowEqual(a: unknown, b: unknown): boolean {\r\n if (Object.is(a, b)) return true;\r\n if (\r\n typeof a !== \"object\" ||\r\n typeof b !== \"object\" ||\r\n a === null ||\r\n b === null\r\n ) {\r\n return false;\r\n }\r\n\r\n if (Array.isArray(a) && Array.isArray(b)) {\r\n if (a.length !== b.length) return false;\r\n for (let i = 0; i < a.length; i++) {\r\n if (!Object.is(a[i], b[i])) return false;\r\n }\r\n return true;\r\n }\r\n\r\n const keysA = Object.keys(a);\r\n const keysB = Object.keys(b);\r\n if (keysA.length !== keysB.length) return false;\r\n\r\n for (const key of keysA) {\r\n if (\r\n !Object.prototype.hasOwnProperty.call(b, key) ||\r\n !Object.is(\r\n (a as Record<string, unknown>)[key],\r\n (b as Record<string, unknown>)[key],\r\n )\r\n ) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n}\r\n\r\n/**\r\n * Re-export ClassValue type for consumers who need it.\r\n */\r\nexport type { ClassValue };\r\n","import type { FieldValues } from \"react-hook-form\";\r\nimport type {\r\n FormSchema,\r\n Section,\r\n BaseField,\r\n ConditionRule,\r\n ConditionConfig,\r\n ValidationRules,\r\n} from \"./types\";\r\n\r\n// ============================================================================\r\n// Condition Types (union used by both evaluateCondition and extractWatchNames)\r\n// ============================================================================\r\n\r\n/**\r\n * All supported condition shapes.\r\n */\r\nexport type Condition<TFieldValues extends FieldValues = FieldValues> =\r\n | ((formValues: Partial<TFieldValues>) => boolean)\r\n | ConditionRule<TFieldValues>\r\n | ConditionRule<TFieldValues>[]\r\n | ConditionConfig<TFieldValues>\r\n | undefined;\r\n\r\n// ============================================================================\r\n// Internal Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Resolves a dot-notation path against an object.\r\n * Handles array indices: \"items.0.name\" resolves through arrays correctly.\r\n */\r\nfunction getNestedValue(obj: Record<string, unknown>, path: string): unknown {\r\n const parts = path.split(\".\");\r\n let current: unknown = obj;\r\n for (const part of parts) {\r\n if (current == null || typeof current !== \"object\") return undefined;\r\n if (Array.isArray(current)) {\r\n const index = Number(part);\r\n if (Number.isNaN(index)) return undefined;\r\n current = current[index];\r\n } else {\r\n current = (current as Record<string, unknown>)[part];\r\n }\r\n }\r\n return current;\r\n}\r\n\r\n/**\r\n * Evaluates a single condition rule against form values.\r\n * Supports both flat dotted keys (\"address.city\" as literal key) and\r\n * nested object resolution (values.address.city). Flat key takes priority\r\n * because DynamicFieldWrapper reconstructs watched values as flat keys.\r\n */\r\nfunction evaluateRule<TFieldValues extends FieldValues>(\r\n rule: ConditionRule<TFieldValues>,\r\n formValues: Partial<TFieldValues>,\r\n): boolean {\r\n const watchPath = rule.watch as string;\r\n const obj = formValues as Record<string, unknown>;\r\n // Flat key first (handles DynamicFieldWrapper's { \"address.city\": val }),\r\n // then nested resolution (handles full form values { address: { city: val } })\r\n const value = watchPath in obj\r\n ? obj[watchPath]\r\n : getNestedValue(obj, watchPath);\r\n\r\n switch (rule.operator) {\r\n case \"===\":\r\n return value === rule.value;\r\n case \"!==\":\r\n return value !== rule.value;\r\n case \"in\":\r\n return Array.isArray(rule.value) && rule.value.includes(value);\r\n case \"not-in\":\r\n return Array.isArray(rule.value) && !rule.value.includes(value);\r\n case \"truthy\":\r\n return Boolean(value);\r\n case \"falsy\":\r\n return !value;\r\n default:\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Type guard: checks if a condition is a ConditionConfig (has `rules` array).\r\n */\r\nfunction isConditionConfig<TFieldValues extends FieldValues>(\r\n condition: NonNullable<Condition<TFieldValues>>,\r\n): condition is ConditionConfig<TFieldValues> {\r\n return (\r\n typeof condition === \"object\" &&\r\n !Array.isArray(condition) &&\r\n \"rules\" in condition\r\n );\r\n}\r\n\r\n/**\r\n * Extracts the rules array from any non-function condition shape.\r\n */\r\nfunction toRules<TFieldValues extends FieldValues>(\r\n condition: Exclude<NonNullable<Condition<TFieldValues>>, Function>,\r\n): { rules: ConditionRule<TFieldValues>[]; logic: \"and\" | \"or\" } {\r\n if (isConditionConfig(condition)) {\r\n return { rules: condition.rules, logic: condition.logic ?? \"and\" };\r\n }\r\n const rules = Array.isArray(condition) ? condition : [condition];\r\n return { rules, logic: \"and\" };\r\n}\r\n\r\n// ============================================================================\r\n// Public API\r\n// ============================================================================\r\n\r\n/**\r\n * Evaluates a conditional rule, array of rules, or a ConditionConfig against form values.\r\n * Supports AND (default) and OR logic via ConditionConfig.\r\n *\r\n * @param condition - The condition function, rule(s), or config\r\n * @param formValues - The form values to evaluate against\r\n * @returns boolean indicating if condition matches\r\n */\r\nexport function evaluateCondition<\r\n TFieldValues extends FieldValues = FieldValues,\r\n>(\r\n condition: Condition<TFieldValues>,\r\n formValues: Partial<TFieldValues>,\r\n): boolean {\r\n if (!condition) return true;\r\n\r\n if (typeof condition === \"function\") {\r\n return condition(formValues);\r\n }\r\n\r\n const { rules, logic } = toRules(condition);\r\n const evalFn = (rule: ConditionRule<TFieldValues>) =>\r\n evaluateRule(rule, formValues);\r\n\r\n return logic === \"or\" ? rules.some(evalFn) : rules.every(evalFn);\r\n}\r\n\r\n/**\r\n * Extracts all watch names from a condition to optimize `useWatch`.\r\n * Handles single rules, arrays, and ConditionConfig objects.\r\n */\r\nexport function extractWatchNames<\r\n TFieldValues extends FieldValues = FieldValues,\r\n>(condition: Condition<TFieldValues>): string[] {\r\n if (!condition || typeof condition === \"function\") return [];\r\n\r\n const { rules } = toRules(condition);\r\n return rules.map((r) => r.watch as string);\r\n}\r\n\r\n/**\r\n * Strictly types a comprehensive form schema, granting exact intellisense bounds across conditions and nested watches.\r\n */\r\nexport function defineSchema<TFieldValues extends FieldValues = FieldValues>(\r\n schema: FormSchema<TFieldValues>,\r\n): FormSchema<TFieldValues> {\r\n return schema;\r\n}\r\n\r\n/**\r\n * Standard utility to strictly type a standalone field out-of-bounds, useful for externalizing massive schema structures.\r\n */\r\nexport function defineField<TFieldValues extends FieldValues = FieldValues>(\r\n field: BaseField<TFieldValues>,\r\n): BaseField<TFieldValues> {\r\n return field;\r\n}\r\n\r\n/**\r\n * Standard utility to strictly type a standalone logic section layout block.\r\n */\r\nexport function defineSection<TFieldValues extends FieldValues = FieldValues>(\r\n section: Section<TFieldValues>,\r\n): Section<TFieldValues> {\r\n return section;\r\n}\r\n\r\n/**\r\n * Extracts default values from a form schema.\r\n * Walks all sections and fields, respecting nameSpace prefixes and group nesting.\r\n *\r\n * @example\r\n * ```ts\r\n * const defaults = extractDefaultValues(schema);\r\n * const form = useForm({ defaultValues: defaults });\r\n * ```\r\n */\r\nexport function extractDefaultValues<\r\n TFieldValues extends FieldValues = FieldValues,\r\n>(schema: FormSchema<TFieldValues>): Partial<TFieldValues> {\r\n const defaults: Record<string, unknown> = {};\r\n\r\n for (const section of schema.sections) {\r\n const prefix = section.nameSpace ? `${section.nameSpace}.` : \"\";\r\n if (!section.fields) continue;\r\n\r\n for (const field of section.fields) {\r\n if (field.defaultValue !== undefined) {\r\n defaults[`${prefix}${field.name as string}`] = field.defaultValue;\r\n }\r\n // Handle group itemFields defaults (skip array types — items are dynamic)\r\n if (field.itemFields && field.type !== \"array\") {\r\n for (const sub of field.itemFields) {\r\n if (sub.defaultValue !== undefined) {\r\n defaults[\r\n `${prefix}${field.name as string}.${sub.name as string}`\r\n ] = sub.defaultValue;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n return defaults as Partial<TFieldValues>;\r\n}\r\n\r\n/**\r\n * Generates react-hook-form `RegisterOptions`-compatible validation rules\r\n * from a field's schema props. Maps `required`, `min`, `max`, `minLength`,\r\n * `maxLength`, `pattern`, and `validate` to RHF rules.\r\n *\r\n * @example\r\n * ```tsx\r\n * import { buildValidationRules } from '@classytic/formkit';\r\n *\r\n * function FormInput({ field, control }: FieldComponentProps) {\r\n * const rules = buildValidationRules(field);\r\n * return <Controller name={field.name} control={control} rules={rules} render={...} />;\r\n * }\r\n * ```\r\n */\r\nexport function buildValidationRules<\r\n TFieldValues extends FieldValues = FieldValues,\r\n>(field: BaseField<TFieldValues>): ValidationRules {\r\n const rules: ValidationRules = {};\r\n\r\n if (field.required) {\r\n rules.required = `${field.label || (field.name as string)} is required`;\r\n }\r\n if (field.minLength !== undefined) {\r\n rules.minLength = {\r\n value: field.minLength,\r\n message: `At least ${field.minLength} characters`,\r\n };\r\n }\r\n if (field.maxLength !== undefined) {\r\n rules.maxLength = {\r\n value: field.maxLength,\r\n message: `At most ${field.maxLength} characters`,\r\n };\r\n }\r\n if (field.min !== undefined) {\r\n rules.min = {\r\n value: field.min,\r\n message: `Must be at least ${field.min}`,\r\n };\r\n }\r\n if (field.max !== undefined) {\r\n rules.max = {\r\n value: field.max,\r\n message: `Must be at most ${field.max}`,\r\n };\r\n }\r\n if (field.pattern) {\r\n rules.pattern = {\r\n value: new RegExp(field.pattern),\r\n message: \"Invalid format\",\r\n };\r\n }\r\n if (field.validate) {\r\n rules.validate = field.validate as ValidationRules[\"validate\"];\r\n }\r\n\r\n return rules;\r\n}\r\n","\"use client\";\r\n\r\nimport { useEffect, useState, useMemo, useRef } from \"react\";\r\nimport {\r\n useFormContext,\r\n useFormState,\r\n useWatch,\r\n useFieldArray,\r\n} from \"react-hook-form\";\r\nimport type {\r\n Control,\r\n FieldValues,\r\n FieldArrayPath,\r\n FieldError,\r\n Path,\r\n} from \"react-hook-form\";\r\nimport {\r\n useFieldComponent,\r\n useLayoutComponent,\r\n useFormSystem,\r\n} from \"./FormSystemContext\";\r\nimport { cn, shallowEqual } from \"./utils\";\r\nimport { evaluateCondition, extractWatchNames } from \"./schema\";\r\nimport type {\r\n FormGeneratorProps,\r\n Section,\r\n BaseField,\r\n FieldComponentProps,\r\n Variant,\r\n FormElement,\r\n} from \"./types\";\r\n\r\n// ============================================================================\r\n// Helpers\r\n// ============================================================================\r\n\r\n/** Generate a deterministic field ID for accessibility label-input association. */\r\nfunction toFieldId(name: string): string {\r\n return `formkit-field-${name.replace(/[.[\\]]/g, \"-\")}`;\r\n}\r\n\r\n/**\r\n * Get nested value from an object using dot-notation path.\r\n * Handles array indices: \"items.0.name\" resolves through arrays correctly.\r\n */\r\nfunction getNestedValue(\r\n obj: Record<string, unknown>,\r\n path: string,\r\n): unknown {\r\n const parts = path.split(\".\");\r\n let current: unknown = obj;\r\n for (const part of parts) {\r\n if (current == null || typeof current !== \"object\") return undefined;\r\n if (Array.isArray(current)) {\r\n const index = Number(part);\r\n if (Number.isNaN(index)) return undefined;\r\n current = current[index];\r\n } else {\r\n current = (current as Record<string, unknown>)[part];\r\n }\r\n }\r\n return current;\r\n}\r\n\r\n/**\r\n * Get nested error from react-hook-form errors object.\r\n * Supports dot-notation paths like \"address.street\" and array paths like \"items.0.name\".\r\n */\r\nfunction getNestedError(\r\n errors: Record<string, unknown>,\r\n path: string,\r\n): FieldError | undefined {\r\n const result = getNestedValue(errors, path);\r\n // FieldError has a `message` property\r\n if (result && typeof result === \"object\" && \"message\" in result) {\r\n return result as FieldError;\r\n }\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Prefix field names with a namespace.\r\n * Memoization-friendly: returns the same shape for stable inputs.\r\n */\r\nfunction prefixFields<TFieldValues extends FieldValues>(\r\n fields: BaseField<TFieldValues>[],\r\n nameSpace: string,\r\n): BaseField<TFieldValues>[] {\r\n return fields.map((f) => ({\r\n ...f,\r\n name: `${nameSpace}.${f.name as string}`,\r\n itemFields: f.itemFields?.map((i) => ({\r\n ...i,\r\n name: `${nameSpace}.${f.name as string}.${i.name as string}`,\r\n })),\r\n })) as BaseField<TFieldValues>[];\r\n}\r\n\r\n// ============================================================================\r\n// FormGenerator Component\r\n// ============================================================================\r\n\r\n/**\r\n * FormGenerator - Headless Form Generator Component\r\n *\r\n * Renders a form based on a schema definition, using components registered\r\n * via FormSystemProvider. Supports conditional fields, dynamic layouts,\r\n * and component variants.\r\n *\r\n * @template TFieldValues - Form field values type for type safety\r\n *\r\n * @example\r\n * ```tsx\r\n * import { useFormKit, FormGenerator } from '@classytic/formkit';\r\n *\r\n * const { handleSubmit, generatorProps } = useFormKit({\r\n * schema: formSchema,\r\n * resolver: zodResolver(validationSchema),\r\n * });\r\n *\r\n * return (\r\n * <form onSubmit={handleSubmit(onSubmit)}>\r\n * <FormGenerator {...generatorProps} />\r\n * </form>\r\n * );\r\n * ```\r\n */\r\nexport function FormGenerator<TFieldValues extends FieldValues = FieldValues>({\r\n schema,\r\n control,\r\n disabled = false,\r\n variant,\r\n className,\r\n ref,\r\n}: FormGeneratorProps<TFieldValues>): FormElement {\r\n // Use provided control or fall back to FormProvider context\r\n const formContext = useFormContext<TFieldValues>();\r\n const activeControl = control ?? formContext?.control;\r\n\r\n if (!activeControl) {\r\n console.warn(\r\n \"[FormKit] FormGenerator requires a `control` prop or to be wrapped in a <FormProvider>.\",\r\n );\r\n return null;\r\n }\r\n\r\n // Early return if no schema\r\n if (!schema?.sections || schema.sections.length === 0) {\r\n return null;\r\n }\r\n\r\n return (\r\n <div\r\n ref={ref}\r\n className={cn(\r\n \"formkit-root\",\r\n variant && `formkit-variant-${variant}`,\r\n className,\r\n )}\r\n data-formkit-root=\"\"\r\n >\r\n {schema.sections.map((section, index) => (\r\n <SectionRenderer\r\n key={section.id ?? `section-${index}`}\r\n section={section}\r\n control={activeControl}\r\n disabled={disabled}\r\n variant={variant}\r\n />\r\n ))}\r\n </div>\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Section Renderer\r\n// ============================================================================\r\n\r\ninterface SectionRendererProps<TFieldValues extends FieldValues = FieldValues> {\r\n section: Section<TFieldValues>;\r\n control?: Control<TFieldValues>;\r\n disabled?: boolean;\r\n variant?: Variant;\r\n}\r\n\r\n/**\r\n * Renders a single section with its fields.\r\n */\r\nfunction SectionRenderer<TFieldValues extends FieldValues = FieldValues>(\r\n props: SectionRendererProps<TFieldValues>,\r\n): FormElement {\r\n if (props.section.condition) {\r\n return <DynamicSectionRenderer {...props} />;\r\n }\r\n return <StaticSectionRenderer {...props} />;\r\n}\r\n\r\n/**\r\n * Section renderer that evaluates conditions reactively.\r\n * Scopes useWatch to only the fields referenced in the condition\r\n * to avoid re-rendering on every form change.\r\n */\r\nfunction DynamicSectionRenderer<\r\n TFieldValues extends FieldValues = FieldValues,\r\n>(props: SectionRendererProps<TFieldValues>): FormElement {\r\n const conditionWatchNames = useMemo(\r\n () => extractWatchNames(props.section.condition),\r\n [props.section.condition],\r\n );\r\n\r\n // Scope watch to condition dependencies when possible\r\n const watchedRaw = conditionWatchNames.length > 0\r\n ? useWatch({ control: props.control, name: conditionWatchNames as unknown as readonly Path<TFieldValues>[] })\r\n : useWatch({ control: props.control });\r\n\r\n // Reconstruct named values if we watched specific names\r\n const sectionValues = useMemo(() => {\r\n if (conditionWatchNames.length > 0 && Array.isArray(watchedRaw)) {\r\n return conditionWatchNames.reduce<Record<string, unknown>>(\r\n (acc, name, i) => ({ ...acc, [name]: watchedRaw[i] }),\r\n {},\r\n );\r\n }\r\n return watchedRaw;\r\n }, [conditionWatchNames, watchedRaw]);\r\n\r\n if (\r\n !evaluateCondition(\r\n props.section.condition,\r\n sectionValues as Partial<TFieldValues>,\r\n )\r\n ) {\r\n return null;\r\n }\r\n return <StaticSectionRenderer {...props} />;\r\n}\r\n\r\nfunction StaticSectionRenderer<\r\n TFieldValues extends FieldValues = FieldValues,\r\n>({\r\n section,\r\n control,\r\n disabled,\r\n variant,\r\n}: SectionRendererProps<TFieldValues>): FormElement {\r\n // Section can override variant\r\n const activeVariant = section.variant ?? variant;\r\n const SectionLayout = useLayoutComponent(\"section\", activeVariant);\r\n\r\n // Memoize namespace-prefixed fields to avoid creating new arrays every render\r\n const resolvedFields = useMemo(() => {\r\n if (section.nameSpace && section.fields) {\r\n return prefixFields(section.fields, section.nameSpace);\r\n }\r\n return section.fields;\r\n }, [section.nameSpace, section.fields]);\r\n\r\n return (\r\n <SectionLayout\r\n title={section.title}\r\n description={section.description}\r\n icon={section.icon}\r\n variant={activeVariant}\r\n className={section.className}\r\n collapsible={section.collapsible}\r\n defaultCollapsed={section.defaultCollapsed}\r\n >\r\n {section.render ? (\r\n // Custom render function\r\n section.render({ control, disabled, section })\r\n ) : (\r\n // Standard grid rendering\r\n <GridRenderer\r\n fields={resolvedFields}\r\n cols={section.cols}\r\n gap={section.gap}\r\n control={control}\r\n disabled={disabled}\r\n variant={activeVariant}\r\n />\r\n )}\r\n </SectionLayout>\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Grid Renderer\r\n// ============================================================================\r\n\r\ninterface GridRendererProps<TFieldValues extends FieldValues = FieldValues> {\r\n fields?: BaseField<TFieldValues>[];\r\n cols?: number;\r\n gap?: number;\r\n control?: Control<TFieldValues>;\r\n disabled?: boolean;\r\n variant?: Variant;\r\n}\r\n\r\n/**\r\n * Renders a grid of fields with specified column layout.\r\n */\r\nfunction GridRenderer<TFieldValues extends FieldValues = FieldValues>({\r\n fields,\r\n cols = 1,\r\n gap,\r\n control,\r\n disabled,\r\n variant,\r\n}: GridRendererProps<TFieldValues>): FormElement {\r\n const GridLayout = useLayoutComponent(\"grid\", variant);\r\n\r\n if (!fields || fields.length === 0) {\r\n return null;\r\n }\r\n\r\n return (\r\n <GridLayout cols={cols} gap={gap}>\r\n {fields.map((field, index) => (\r\n <FieldWrapper\r\n key={field.name || `field-${index}`}\r\n field={field}\r\n control={control}\r\n disabled={disabled}\r\n variant={variant}\r\n />\r\n ))}\r\n </GridLayout>\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Field Wrapper\r\n// ============================================================================\r\n\r\ninterface FieldWrapperProps<TFieldValues extends FieldValues = FieldValues> {\r\n field: BaseField<TFieldValues>;\r\n control?: Control<TFieldValues>;\r\n disabled?: boolean;\r\n variant?: Variant;\r\n}\r\n\r\n/**\r\n * Wraps individual fields.\r\n * If the field requires conditional logic or dynamic options, it uses the Dynamic wrapper.\r\n * Otherwise, it uses the Static wrapper, vastly improving performance by skipping `useWatch`.\r\n */\r\nfunction FieldWrapper<TFieldValues extends FieldValues = FieldValues>(\r\n props: FieldWrapperProps<TFieldValues>,\r\n): FormElement {\r\n if (props.field.condition || props.field.loadOptions) {\r\n return <DynamicFieldWrapper {...props} />;\r\n }\r\n return <StaticFieldWrapper {...props} />;\r\n}\r\n\r\n/**\r\n * Dynamic Field Wrapper\r\n * Conditionally calls `useWatch` to trigger re-renders only when form values change.\r\n * Can be optimized further by providing `watchNames` on the field.\r\n */\r\nfunction DynamicFieldWrapper<TFieldValues extends FieldValues = FieldValues>({\r\n field,\r\n control,\r\n disabled,\r\n variant,\r\n}: FieldWrapperProps<TFieldValues>): FormElement {\r\n // Combine explicit watchNames with names extracted from DSL condition rules\r\n const ruleWatchNames = useMemo(\r\n () => extractWatchNames(field.condition),\r\n [field.condition],\r\n );\r\n const explicitWatchNames = useMemo(() => {\r\n if (Array.isArray(field.watchNames)) return field.watchNames as string[];\r\n if (field.watchNames) return [field.watchNames as string];\r\n return [];\r\n }, [field.watchNames]);\r\n\r\n // Stabilize the watch names list across renders using ref comparison\r\n const allWatchNamesRef = useRef<string[]>([]);\r\n const allWatchNames = useMemo(() => {\r\n const next = Array.from(\r\n new Set([...explicitWatchNames, ...ruleWatchNames]),\r\n );\r\n // Only return new array if contents actually changed\r\n if (\r\n next.length === allWatchNamesRef.current.length &&\r\n next.every((n, i) => n === allWatchNamesRef.current[i])\r\n ) {\r\n return allWatchNamesRef.current;\r\n }\r\n allWatchNamesRef.current = next;\r\n return next;\r\n }, [explicitWatchNames, ruleWatchNames]);\r\n\r\n // Watch form values for conditional rendering.\r\n // When specific watch names are available we pass them to limit re-renders;\r\n // otherwise we watch the entire form.\r\n const watchedRaw = allWatchNames.length > 0\r\n ? useWatch({ control, name: allWatchNames as unknown as readonly Path<TFieldValues>[] })\r\n : useWatch({ control });\r\n\r\n // Use shallow comparison to stabilize watched values without JSON.stringify cost\r\n const prevWatchedRef = useRef(watchedRaw);\r\n const stableWatched = useMemo(() => {\r\n if (shallowEqual(prevWatchedRef.current, watchedRaw)) {\r\n return prevWatchedRef.current;\r\n }\r\n prevWatchedRef.current = watchedRaw;\r\n return watchedRaw;\r\n }, [watchedRaw]);\r\n\r\n // Reconstruct correctly typed partial payload for conditions if watchNames arrays were mapped\r\n const watchedValues = useMemo(() => {\r\n if (allWatchNames.length > 0 && Array.isArray(stableWatched)) {\r\n return allWatchNames.reduce<Record<string, unknown>>(\r\n (acc, name, i) => ({ ...acc, [name]: stableWatched[i] }),\r\n {},\r\n );\r\n }\r\n return stableWatched;\r\n }, [allWatchNames, stableWatched]);\r\n\r\n const [options, setOptions] = useState(field.options || []);\r\n const [isLoading, setIsLoading] = useState(false);\r\n // Store loading timeout to cleanly clear debounce sweeps\r\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\r\n\r\n useEffect(() => {\r\n if (!field.loadOptions) return;\r\n\r\n let isActive = true;\r\n\r\n const executeLoad = () => {\r\n const res = field.loadOptions!(\r\n watchedValues as Partial<TFieldValues>,\r\n );\r\n if (res instanceof Promise) {\r\n setIsLoading(true);\r\n res\r\n .then((newOptions) => {\r\n if (isActive) setOptions(newOptions);\r\n })\r\n .catch((err: unknown) => {\r\n if (isActive) {\r\n if (field.onLoadError) {\r\n field.onLoadError(err);\r\n } else {\r\n console.error(\"[FormKit] loadOptions error:\", err);\r\n }\r\n }\r\n })\r\n .finally(() => {\r\n if (isActive) setIsLoading(false);\r\n });\r\n } else {\r\n setOptions(res);\r\n setIsLoading(false);\r\n }\r\n };\r\n\r\n if (field.debounceMs && field.debounceMs > 0) {\r\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\r\n timeoutRef.current = setTimeout(executeLoad, field.debounceMs);\r\n } else {\r\n executeLoad();\r\n }\r\n\r\n return () => {\r\n isActive = false;\r\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\r\n };\r\n }, [watchedValues, field.loadOptions, field.debounceMs, field.onLoadError]);\r\n\r\n // Memoize the augmented field to avoid creating new objects every render\r\n // Must be before the conditional return to satisfy rules of hooks\r\n const loadingState = field.loadOptions ? isLoading : undefined;\r\n const dynamicField = useMemo<BaseField<TFieldValues>>(() => ({\r\n ...field,\r\n options: field.loadOptions ? options : field.options,\r\n isLoading: loadingState,\r\n } as BaseField<TFieldValues>), [field, options, loadingState]);\r\n\r\n // Check field condition\r\n if (\r\n !evaluateCondition(\r\n field.condition,\r\n watchedValues as Partial<TFieldValues>,\r\n )\r\n ) {\r\n return null;\r\n }\r\n\r\n return (\r\n <StaticFieldWrapper\r\n field={dynamicField}\r\n control={control}\r\n disabled={disabled}\r\n variant={variant}\r\n isLoading={loadingState}\r\n />\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Static Field Wrapper\r\n// ============================================================================\r\n\r\ninterface StaticFieldWrapperProps<TFieldValues extends FieldValues = FieldValues>\r\n extends FieldWrapperProps<TFieldValues> {\r\n isLoading?: boolean;\r\n}\r\n\r\n/**\r\n * Static Field Wrapper\r\n * Handles rendering the actual component via the registry, or via a custom static `render`.\r\n * Does not use `useWatch` internally.\r\n */\r\nfunction StaticFieldWrapper<TFieldValues extends FieldValues = FieldValues>({\r\n field,\r\n control,\r\n disabled,\r\n variant,\r\n isLoading,\r\n}: StaticFieldWrapperProps<TFieldValues>): FormElement {\r\n // All hooks must be called unconditionally at the top\r\n const { components } = useFormSystem();\r\n const fieldName = field.name as string;\r\n const { errors, dirtyFields, touchedFields } = useFormState({\r\n control,\r\n name: fieldName as Path<TFieldValues>,\r\n });\r\n\r\n // Merge disabled states\r\n const isDisabled = disabled || field.disabled;\r\n const fieldId = toFieldId(fieldName);\r\n const fieldError = getNestedError(\r\n errors as Record<string, unknown>,\r\n fieldName,\r\n );\r\n const isDirty = Boolean(\r\n getNestedValue(dirtyFields as Record<string, unknown>, fieldName),\r\n );\r\n const isTouched = Boolean(\r\n getNestedValue(touchedFields as Record<string, unknown>, fieldName),\r\n );\r\n const fieldState = useMemo(\r\n () => ({\r\n invalid: !!fieldError,\r\n isDirty,\r\n isTouched,\r\n isValidating: false,\r\n error: fieldError,\r\n }),\r\n [fieldError, isDirty, isTouched],\r\n );\r\n const activeVariant = field.variant ?? variant;\r\n\r\n // Render override bypassing the registry completely\r\n if (field.render) {\r\n return (\r\n <div\r\n className={cn(\r\n \"formkit-field\",\r\n field.fullWidth && \"col-span-full\",\r\n field.className,\r\n )}\r\n id={fieldId}\r\n data-formkit-field={fieldName}\r\n data-field-type={field.type}\r\n >\r\n {field.render({\r\n ...field,\r\n field,\r\n control: control as Control<TFieldValues>,\r\n disabled: isDisabled,\r\n variant: activeVariant,\r\n error: fieldError,\r\n fieldState,\r\n fieldId,\r\n isLoading,\r\n } as FieldComponentProps<TFieldValues>)}\r\n </div>\r\n );\r\n }\r\n\r\n // Verify if a component explicitly exists for this type, preventing default \"text\" fallback\r\n // from devouring nested group types entirely.\r\n const hasExplicitComponent = Boolean(\r\n components[field.type] ||\r\n (activeVariant &&\r\n components[activeVariant] &&\r\n typeof components[activeVariant] === \"object\" &&\r\n (components[activeVariant] as Record<string, unknown>)[field.type]),\r\n );\r\n\r\n if (\r\n !hasExplicitComponent &&\r\n field.itemFields &&\r\n field.itemFields.length > 0\r\n ) {\r\n if (field.type === \"array\") {\r\n return (\r\n <ArrayFieldFallback\r\n field={field}\r\n control={control}\r\n disabled={isDisabled}\r\n variant={activeVariant}\r\n />\r\n );\r\n }\r\n\r\n // Default Group mapping fallback\r\n return (\r\n <div\r\n className={cn(\r\n \"formkit-field-group\",\r\n field.fullWidth && \"col-span-full\",\r\n field.className,\r\n )}\r\n data-formkit-field={fieldName}\r\n data-field-type={field.type}\r\n >\r\n <GridRenderer\r\n fields={field.itemFields}\r\n control={control}\r\n disabled={isDisabled}\r\n variant={activeVariant}\r\n />\r\n </div>\r\n );\r\n }\r\n\r\n const FieldComponent = useFieldComponent(field.type, activeVariant);\r\n\r\n if (!FieldComponent) {\r\n return null;\r\n }\r\n\r\n return (\r\n <div\r\n className={cn(\r\n \"formkit-field\",\r\n field.fullWidth && \"col-span-full\",\r\n field.className,\r\n )}\r\n id={fieldId}\r\n data-formkit-field={fieldName}\r\n data-field-type={field.type}\r\n >\r\n <FieldComponent\r\n {...(field as BaseField<FieldValues>)}\r\n field={field as BaseField<FieldValues>}\r\n control={control as Control<FieldValues>}\r\n disabled={isDisabled}\r\n variant={activeVariant}\r\n error={fieldError}\r\n fieldState={fieldState}\r\n fieldId={fieldId}\r\n isLoading={isLoading}\r\n />\r\n </div>\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Array Native Fallback Wrapper\r\n// ============================================================================\r\n\r\nfunction ArrayFieldFallback<TFieldValues extends FieldValues = FieldValues>({\r\n field,\r\n control,\r\n disabled,\r\n variant,\r\n}: FieldWrapperProps<TFieldValues>): FormElement {\r\n const { fields, append, remove } = useFieldArray({\r\n control,\r\n name: field.name as FieldArrayPath<TFieldValues>,\r\n });\r\n\r\n return (\r\n <div\r\n className={cn(\r\n \"formkit-field-array flex flex-col gap-4\",\r\n field.fullWidth && \"col-span-full\",\r\n field.className,\r\n )}\r\n data-formkit-field={field.name}\r\n data-field-type=\"array\"\r\n >\r\n <div className=\"flex items-center justify-between\">\r\n {field.label && (\r\n <label className=\"font-semibold\">{field.label}</label>\r\n )}\r\n </div>\r\n\r\n {fields.map((item, index) => (\r\n <div\r\n key={item.id}\r\n className=\"relative formkit-array-item border p-4 rounded-md\"\r\n >\r\n <GridRenderer\r\n fields={\r\n field.itemFields?.map((f) => ({\r\n ...f,\r\n name: `${field.name as string}.${index}.${f.name as string}`,\r\n })) as BaseField<TFieldValues>[] | undefined\r\n }\r\n control={control}\r\n disabled={disabled}\r\n variant={variant}\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={() => remove(index)}\r\n className=\"absolute top-2 right-2 text-red-500 hover:text-red-700 text-sm font-medium\"\r\n >\r\n Remove\r\n </button>\r\n </div>\r\n ))}\r\n <button\r\n type=\"button\"\r\n onClick={() => append({} as Record<string, unknown> as TFieldValues[string & keyof TFieldValues])}\r\n disabled={disabled}\r\n className=\"self-start mt-2 px-4 py-2 bg-blue-50 text-blue-600 rounded-md text-sm font-medium hover:bg-blue-100 disabled:opacity-50\"\r\n >\r\n + Add Item\r\n </button>\r\n </div>\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Named Exports for Subcomponents (for advanced use cases)\r\n// ============================================================================\r\n\r\nexport { SectionRenderer, GridRenderer, FieldWrapper };\r\n","import type { ReactNode } from \"react\";\r\nimport type { FieldValues, Control, FieldError } from \"react-hook-form\";\r\nimport type {\r\n BaseField,\r\n FieldOption,\r\n FieldOptionGroup,\r\n Section,\r\n} from \"./types\";\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Additional field props for builder helpers.\r\n * Accepts all BaseField properties except `name`, `type`, and `label`\r\n * which are set by the builder method.\r\n */\r\ntype FieldProps<TFieldValues extends FieldValues = FieldValues> = Omit<\r\n BaseField<TFieldValues>,\r\n \"name\" | \"type\" | \"label\"\r\n> & {\r\n /** Grid column class (e.g., \"col-span-2\") */\r\n gridColumn?: string;\r\n /** Icon for the left side of input */\r\n iconLeft?: ReactNode;\r\n /** Icon for the right side of input */\r\n iconRight?: ReactNode;\r\n /** Additional custom props */\r\n [key: string]: unknown;\r\n};\r\n\r\n/**\r\n * Section configuration props.\r\n */\r\ninterface SectionProps<TFieldValues extends FieldValues = FieldValues>\r\n extends Omit<Section<TFieldValues>, \"id\" | \"title\" | \"fields\" | \"cols\"> {\r\n cols?: number;\r\n}\r\n\r\n/**\r\n * Render function for custom field types.\r\n */\r\ntype CustomRenderFn = (props: {\r\n control: Control<FieldValues>;\r\n disabled?: boolean;\r\n error?: FieldError;\r\n}) => ReactNode;\r\n\r\n// ============================================================================\r\n// Field Builder\r\n// ============================================================================\r\n\r\n/**\r\n * Type-safe field builder helpers for schema-driven forms.\r\n *\r\n * Provides shorthand methods for common field types with sensible defaults,\r\n * reducing boilerplate while maintaining full type safety.\r\n *\r\n * @example\r\n * ```ts\r\n * import { field, section } from '@classytic/formkit';\r\n *\r\n * const schema = {\r\n * sections: [\r\n * section(\"personal\", \"Personal Info\", [\r\n * field.text(\"firstName\", \"First Name\", { required: true }),\r\n * field.email(\"email\", \"Email\"),\r\n * field.select(\"role\", \"Role\", [\r\n * { label: \"Admin\", value: \"admin\" },\r\n * { label: \"User\", value: \"user\" },\r\n * ]),\r\n * ], { cols: 2 }),\r\n * ],\r\n * };\r\n * ```\r\n */\r\nexport const field = {\r\n /**\r\n * Text input field.\r\n */\r\n text: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"text\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Email input field with default placeholder.\r\n */\r\n email: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"email\",\r\n name,\r\n label,\r\n placeholder: \"example@email.com\",\r\n ...props,\r\n }),\r\n\r\n /**\r\n * URL input field with default placeholder.\r\n */\r\n url: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"url\",\r\n name,\r\n label,\r\n placeholder: \"https://example.com\",\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Phone/tel input field with default placeholder.\r\n */\r\n tel: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"tel\",\r\n name,\r\n label,\r\n placeholder: \"+1 (555) 000-0000\",\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Password input field.\r\n */\r\n password: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"password\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Number input field with min: 0 default.\r\n */\r\n number: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"number\",\r\n name,\r\n label,\r\n min: 0,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Textarea field with default 3 rows.\r\n */\r\n textarea: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"textarea\",\r\n name,\r\n label,\r\n rows: 3,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Select dropdown field.\r\n */\r\n select: (\r\n name: string,\r\n label: string,\r\n options: (FieldOption | FieldOptionGroup)[],\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"select\",\r\n name,\r\n label,\r\n options,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Searchable combobox field.\r\n */\r\n combobox: (\r\n name: string,\r\n label: string,\r\n options: (FieldOption | FieldOptionGroup)[],\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"combobox\",\r\n name,\r\n label,\r\n options,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Multi-select field (tag choice).\r\n */\r\n multiselect: (\r\n name: string,\r\n label: string,\r\n options: (FieldOption | FieldOptionGroup)[],\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"multiselect\",\r\n name,\r\n label,\r\n options,\r\n placeholder: \"Select options...\",\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Dependent select field that reacts to parent field changes.\r\n */\r\n dependentSelect: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"dependentSelect\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Switch/toggle field.\r\n */\r\n switch: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"switch\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Boolean field (alias for switch).\r\n */\r\n boolean: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"switch\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Checkbox field.\r\n */\r\n checkbox: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"checkbox\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Radio button group field.\r\n */\r\n radio: (\r\n name: string,\r\n label: string,\r\n options: FieldOption[],\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"radio\",\r\n name,\r\n label,\r\n options,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Date picker field.\r\n */\r\n date: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"date\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Tag input field with default placeholder.\r\n */\r\n tags: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"tags\",\r\n name,\r\n label,\r\n placeholder: \"Add tags...\",\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Slug field with auto-generation from source value.\r\n */\r\n slug: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"slug\",\r\n name,\r\n label,\r\n placeholder: \"my-page-slug\",\r\n ...props,\r\n }),\r\n\r\n /**\r\n * File upload field.\r\n */\r\n file: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"file\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Hidden field (no UI).\r\n */\r\n hidden: (\r\n name: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"hidden\",\r\n name,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Group field for nested objects.\r\n * Renders itemFields as a sub-grid within the form.\r\n *\r\n * @example\r\n * ```ts\r\n * field.group(\"address\", \"Address\", [\r\n * field.text(\"street\", \"Street\"),\r\n * field.text(\"city\", \"City\"),\r\n * field.text(\"zip\", \"ZIP Code\"),\r\n * ], { cols: 3 })\r\n * ```\r\n */\r\n group: (\r\n name: string,\r\n label: string,\r\n itemFields: BaseField[],\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"group\",\r\n name,\r\n label,\r\n itemFields,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Array/repeatable field.\r\n * Renders a dynamic list of sub-forms using react-hook-form's useFieldArray.\r\n *\r\n * @example\r\n * ```ts\r\n * field.array(\"contacts\", \"Contacts\", [\r\n * field.text(\"name\", \"Name\"),\r\n * field.email(\"email\", \"Email\"),\r\n * ])\r\n * ```\r\n */\r\n array: (\r\n name: string,\r\n label: string,\r\n itemFields: BaseField[],\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"array\",\r\n name,\r\n label,\r\n itemFields,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Custom field with a render function.\r\n * Bypasses the component registry entirely.\r\n *\r\n * @example\r\n * ```ts\r\n * field.custom(\"skills\", \"Skills\", ({ control, disabled }) => (\r\n * <SkillSelector control={control} disabled={disabled} />\r\n * ))\r\n * ```\r\n */\r\n custom: (\r\n name: string,\r\n label: string,\r\n render: CustomRenderFn,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"custom\",\r\n name,\r\n label,\r\n render: render as BaseField[\"render\"],\r\n ...props,\r\n }),\r\n};\r\n\r\n// ============================================================================\r\n// Section Builder\r\n// ============================================================================\r\n\r\n/**\r\n * Create a section definition with sensible defaults.\r\n *\r\n * @param id - Unique section identifier\r\n * @param title - Section title\r\n * @param fields - Array of field definitions\r\n * @param props - Additional section configuration\r\n *\r\n * @example\r\n * ```ts\r\n * section(\"personal\", \"Personal Info\", [\r\n * field.text(\"name\", \"Name\", { required: true }),\r\n * field.email(\"email\", \"Email\"),\r\n * ], { cols: 2, variant: \"card\" })\r\n * ```\r\n */\r\nexport function section<TFieldValues extends FieldValues = FieldValues>(\r\n id: string,\r\n title: string,\r\n fields: BaseField<TFieldValues>[],\r\n props: SectionProps<TFieldValues> = {},\r\n): Section<TFieldValues> {\r\n const { cols = 2, ...rest } = props;\r\n return {\r\n id,\r\n title,\r\n fields,\r\n cols,\r\n ...rest,\r\n };\r\n}\r\n\r\n/**\r\n * Create a section without a title (transparent section).\r\n * Useful for grouping fields without visual separation.\r\n */\r\nexport function sectionUntitled<TFieldValues extends FieldValues = FieldValues>(\r\n fields: BaseField<TFieldValues>[],\r\n props: Omit<SectionProps<TFieldValues>, \"variant\"> = {},\r\n): Section<TFieldValues> {\r\n const { cols = 1, ...rest } = props;\r\n return {\r\n fields,\r\n cols,\r\n variant: \"transparent\",\r\n ...rest,\r\n };\r\n}\r\n","\"use client\";\r\n\r\nimport { useForm } from \"react-hook-form\";\r\nimport type { UseFormProps, UseFormReturn, FieldValues } from \"react-hook-form\";\r\nimport { extractDefaultValues } from \"./schema\";\r\nimport type { FormSchema, FormGeneratorProps, Variant } from \"./types\";\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Options for the useFormKit hook.\r\n * Extends react-hook-form's UseFormProps with schema-driven defaults.\r\n */\r\nexport interface UseFormKitOptions<\r\n TFieldValues extends FieldValues = FieldValues,\r\n> extends Omit<UseFormProps<TFieldValues>, \"defaultValues\"> {\r\n /** Form schema defining sections and fields */\r\n schema: FormSchema<TFieldValues>;\r\n /** Override or extend default values extracted from schema */\r\n defaultValues?: UseFormProps<TFieldValues>[\"defaultValues\"];\r\n /** Disable all fields */\r\n disabled?: boolean;\r\n /** Global variant */\r\n variant?: Variant;\r\n /** Root element className */\r\n className?: string;\r\n}\r\n\r\n/**\r\n * Return value from useFormKit.\r\n * Includes all useForm methods plus pre-built generatorProps.\r\n */\r\nexport interface UseFormKitReturn<\r\n TFieldValues extends FieldValues = FieldValues,\r\n> extends UseFormReturn<TFieldValues> {\r\n /** Props to spread onto <FormGenerator /> */\r\n generatorProps: Pick<\r\n FormGeneratorProps<TFieldValues>,\r\n \"schema\" | \"control\" | \"disabled\" | \"variant\" | \"className\"\r\n >;\r\n}\r\n\r\n// ============================================================================\r\n// Hook\r\n// ============================================================================\r\n\r\n/**\r\n * Convenience hook that combines schema default extraction with react-hook-form setup.\r\n * Returns all useForm methods plus ready-to-spread `generatorProps`.\r\n *\r\n * @example\r\n * ```tsx\r\n * const { handleSubmit, generatorProps } = useFormKit({\r\n * schema: formSchema,\r\n * resolver: zodResolver(validationSchema),\r\n * });\r\n *\r\n * return (\r\n * <form onSubmit={handleSubmit(onSubmit)}>\r\n * <FormGenerator {...generatorProps} />\r\n * <button type=\"submit\">Submit</button>\r\n * </form>\r\n * );\r\n * ```\r\n */\r\nexport function useFormKit<TFieldValues extends FieldValues = FieldValues>(\r\n options: UseFormKitOptions<TFieldValues>,\r\n): UseFormKitReturn<TFieldValues> {\r\n const { schema, disabled, variant, className, defaultValues, ...formOptions } =\r\n options;\r\n\r\n // Extract defaults from schema, merge with explicit overrides\r\n const schemaDefaults = extractDefaultValues(schema);\r\n const mergedDefaults = {\r\n ...schemaDefaults,\r\n ...(typeof defaultValues === \"object\" && defaultValues !== null\r\n ? defaultValues\r\n : {}),\r\n } as UseFormProps<TFieldValues>[\"defaultValues\"];\r\n\r\n const form = useForm<TFieldValues>({\r\n ...formOptions,\r\n defaultValues: mergedDefaults,\r\n });\r\n\r\n return {\r\n ...form,\r\n generatorProps: {\r\n schema,\r\n control: form.control,\r\n disabled,\r\n variant,\r\n className,\r\n },\r\n };\r\n}\r\n"],"mappings":"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CX;MAEQ;MApBJ,KAAK,GAqBN,CACN;GACF,oBAAC;IACC,MAAK;IACL,eAAe,OAAO,EAAE,CAAyE;IACvF;IACV,WAAU;cACX;KAEQ;;GACL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3oBV,MAAa,QAAQ;CAInB,OACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,QACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,aAAa;EACb,GAAG;EACJ;CAKD,MACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,aAAa;EACb,GAAG;EACJ;CAKD,MACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,aAAa;EACb,GAAG;EACJ;CAKD,WACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,SACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,KAAK;EACL,GAAG;EACJ;CAKD,WACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,MAAM;EACN,GAAG;EACJ;CAKD,SACE,MACA,OACA,SACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA;EACA,GAAG;EACJ;CAKD,WACE,MACA,OACA,SACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA;EACA,GAAG;EACJ;CAKD,cACE,MACA,OACA,SACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA;EACA,aAAa;EACb,GAAG;EACJ;CAKD,kBACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,SACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,UACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,WACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,QACE,MACA,OACA,SACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA;EACA,GAAG;EACJ;CAKD,OACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,OACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,aAAa;EACb,GAAG;EACJ;CAKD,OACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,aAAa;EACb,GAAG;EACJ;CAKD,OACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,SACE,MACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA,GAAG;EACJ;CAeD,QACE,MACA,OACA,YACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA;EACA,GAAG;EACJ;CAcD,QACE,MACA,OACA,YACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA;EACA,GAAG;EACJ;CAaD,SACE,MACA,OACA,QACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACQ;EACR,GAAG;EACJ;CACF;;;;;;;;;;;;;;;;;AAsBD,SAAgB,QACd,IACA,OACA,QACA,QAAoC,EAAE,EACf;CACvB,MAAM,EAAE,OAAO,GAAG,GAAG,SAAS;AAC9B,QAAO;EACL;EACA;EACA;EACA;EACA,GAAG;EACJ;;;;;;AAOH,SAAgB,gBACd,QACA,QAAqD,EAAE,EAChC;CACvB,MAAM,EAAE,OAAO,GAAG,GAAG,SAAS;AAC9B,QAAO;EACL;EACA;EACA,SAAS;EACT,GAAG;EACJ;;;;;;;;;;;;;;;;;;;;;;;;AC/aH,SAAgB,WACd,SACgC;CAChC,MAAM,EAAE,QAAQ,UAAU,SAAS,WAAW,eAAe,GAAG,gBAC9D;CAIF,MAAM,iBAAiB;EACrB,GAFqB,qBAAqB,OAAO;EAGjD,GAAI,OAAO,kBAAkB,YAAY,kBAAkB,OACvD,gBACA,EAAE;EACP;CAED,MAAM,OAAO,QAAsB;EACjC,GAAG;EACH,eAAe;EAChB,CAAC;AAEF,QAAO;EACL,GAAG;EACH,gBAAgB;GACd;GACA,SAAS,KAAK;GACd;GACA;GACA;GACD;EACF"}
1
+ {"version":3,"file":"index.mjs","names":["getNestedValue"],"sources":["../src/FormSystemContext.tsx","../src/utils.ts","../src/schema.ts","../src/FormGenerator.tsx","../src/builders.ts","../src/useFormKit.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport { createContext, useContext, useMemo } from \"react\";\r\nimport type {\r\n FormSystemContextValue,\r\n FormSystemProviderProps,\r\n FieldComponent,\r\n LayoutComponent,\r\n FieldType,\r\n LayoutType,\r\n Variant,\r\n SectionLayoutProps,\r\n GridLayoutProps,\r\n DefaultLayoutProps,\r\n FormElement,\r\n} from \"./types\";\r\n\r\n// ============================================================================\r\n// Context\r\n// ============================================================================\r\n\r\nconst FormSystemContext = createContext<FormSystemContextValue | null>(null);\r\n\r\n// Display name for React DevTools\r\nFormSystemContext.displayName = \"FormSystemContext\";\r\n\r\n// ============================================================================\r\n// Provider\r\n// ============================================================================\r\n\r\n/**\r\n * FormSystemProvider\r\n *\r\n * Root provider that enables the form system. Provides component and layout\r\n * registries to FormGenerator and its descendants.\r\n *\r\n * @example\r\n * ```tsx\r\n * import { FormSystemProvider } from '@classytic/formkit';\r\n *\r\n * const components = {\r\n * text: TextInput,\r\n * select: SelectInput,\r\n * // Variant-specific components\r\n * compact: {\r\n * text: CompactTextInput,\r\n * },\r\n * };\r\n *\r\n * const layouts = {\r\n * section: SectionLayout,\r\n * grid: GridLayout,\r\n * };\r\n *\r\n * function App() {\r\n * return (\r\n * <FormSystemProvider components={components} layouts={layouts}>\r\n * <YourFormComponent />\r\n * </FormSystemProvider>\r\n * );\r\n * }\r\n * ```\r\n */\r\nexport function FormSystemProvider({\r\n components,\r\n layouts,\r\n children,\r\n}: FormSystemProviderProps): FormElement {\r\n const value = useMemo<FormSystemContextValue>(\r\n () => ({\r\n components: components ?? {},\r\n layouts: layouts ?? {},\r\n }),\r\n [components, layouts]\r\n );\r\n\r\n return <FormSystemContext value={value}>{children}</FormSystemContext>;\r\n}\r\n\r\n// ============================================================================\r\n// Hooks\r\n// ============================================================================\r\n\r\n/**\r\n * Hook to access the form system context.\r\n *\r\n * @throws {Error} If used outside FormSystemProvider\r\n * @returns Form system context value\r\n *\r\n * @example\r\n * ```tsx\r\n * const { components, layouts } = useFormSystem();\r\n * ```\r\n */\r\nexport function useFormSystem(): FormSystemContextValue {\r\n const context = useContext(FormSystemContext);\r\n if (!context) {\r\n throw new Error(\r\n \"[FormKit] useFormSystem must be used within a FormSystemProvider. \" +\r\n \"Make sure to wrap your form components with <FormSystemProvider>.\"\r\n );\r\n }\r\n return context;\r\n}\r\n\r\n/**\r\n * Hook to get a field component by type and optional variant.\r\n *\r\n * Resolution order:\r\n * 1. Variant-specific component: `components[variant][type]`\r\n * 2. Type-specific component: `components[type]`\r\n * 3. Default component: `components[\"default\"]`\r\n * 4. Text fallback: `components[\"text\"]`\r\n *\r\n * @param type - Field type identifier\r\n * @param variant - Optional variant name\r\n * @returns Field component or fallback\r\n *\r\n * @internal\r\n */\r\nexport function useFieldComponent(type: FieldType, variant?: Variant): FieldComponent {\r\n const { components } = useFormSystem();\r\n\r\n // 1. Try variant-specific component\r\n if (variant && typeof components[variant] === \"object\" && components[variant] !== null) {\r\n const variantComponents = components[variant] as Record<string, FieldComponent>;\r\n const variantComponent = variantComponents[type];\r\n if (variantComponent) {\r\n return variantComponent;\r\n }\r\n }\r\n\r\n // 2. Try type-specific component\r\n const typeComponent = components[type] as FieldComponent | undefined;\r\n if (typeComponent && typeof typeComponent === \"function\") {\r\n return typeComponent;\r\n }\r\n\r\n // 3. Try default component\r\n const defaultComponent = components[\"default\"] as FieldComponent | undefined;\r\n if (defaultComponent && typeof defaultComponent === \"function\") {\r\n return defaultComponent;\r\n }\r\n\r\n // 4. Try text fallback\r\n const textComponent = components[\"text\"] as FieldComponent | undefined;\r\n if (textComponent && typeof textComponent === \"function\") {\r\n return textComponent;\r\n }\r\n\r\n // 5. Development warning and placeholder\r\n if (process.env.NODE_ENV !== \"production\") {\r\n console.warn(\r\n `[FormKit] No component found for type \"${type}\"${variant ? ` (variant: \"${variant}\")` : \"\"}. ` +\r\n \"Register a component for this type in your FormSystemProvider.\"\r\n );\r\n return MissingFieldComponent;\r\n }\r\n\r\n // Production: silent fallback\r\n return NullComponent;\r\n}\r\n\r\n/**\r\n * Hook to get a layout component by type and optional variant.\r\n *\r\n * Resolution order:\r\n * 1. Variant-specific layout: `layouts[variant][type]`\r\n * 2. Type-specific layout: `layouts[type]`\r\n * 3. Default layout: `layouts[\"default\"]`\r\n * 4. Built-in default layout\r\n *\r\n * @param type - Layout type identifier\r\n * @param variant - Optional variant name\r\n * @returns Layout component or fallback\r\n *\r\n * @internal\r\n */\r\nexport function useLayoutComponent(\r\n type: LayoutType,\r\n variant?: Variant\r\n): LayoutComponent<SectionLayoutProps | GridLayoutProps | DefaultLayoutProps> {\r\n const { layouts } = useFormSystem();\r\n\r\n // 1. Try variant-specific layout\r\n if (variant && typeof layouts[variant] === \"object\" && layouts[variant] !== null) {\r\n const variantLayouts = layouts[variant] as Record<\r\n string,\r\n LayoutComponent<SectionLayoutProps | GridLayoutProps | DefaultLayoutProps>\r\n >;\r\n const variantLayout = variantLayouts[type];\r\n if (variantLayout) {\r\n return variantLayout;\r\n }\r\n }\r\n\r\n // 2. Try type-specific layout\r\n const typeLayout = layouts[type] as\r\n | LayoutComponent<SectionLayoutProps | GridLayoutProps | DefaultLayoutProps>\r\n | undefined;\r\n if (typeLayout && typeof typeLayout === \"function\") {\r\n return typeLayout;\r\n }\r\n\r\n // 3. Try default layout\r\n const defaultLayout = layouts[\"default\"] as\r\n | LayoutComponent<SectionLayoutProps | GridLayoutProps | DefaultLayoutProps>\r\n | undefined;\r\n if (defaultLayout && typeof defaultLayout === \"function\") {\r\n return defaultLayout;\r\n }\r\n\r\n // 4. Built-in default layout\r\n return DefaultLayout;\r\n}\r\n\r\n// ============================================================================\r\n// Fallback Components\r\n// ============================================================================\r\n\r\n/**\r\n * Default layout component - simple div wrapper.\r\n * Used when no layout is registered.\r\n */\r\nfunction DefaultLayout({ children, className }: DefaultLayoutProps): FormElement {\r\n return <div className={className}>{children}</div>;\r\n}\r\n\r\n/**\r\n * Null component for production fallback.\r\n */\r\nfunction NullComponent(): FormElement {\r\n return null;\r\n}\r\n\r\n/**\r\n * Development placeholder for missing field components.\r\n */\r\nfunction MissingFieldComponent({ field }: { field: { type: string; name: string } }): FormElement {\r\n return (\r\n <div\r\n style={{\r\n color: \"#dc2626\",\r\n padding: \"8px 12px\",\r\n border: \"1px dashed #dc2626\",\r\n borderRadius: \"4px\",\r\n fontSize: \"12px\",\r\n fontFamily: \"monospace\",\r\n backgroundColor: \"#fef2f2\",\r\n }}\r\n >\r\n Missing component: <strong>{field.type}</strong> (field: {field.name})\r\n </div>\r\n );\r\n}\r\n","import { clsx } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\nimport type { ClassValue } from \"clsx\";\r\n\r\n/**\r\n * Utility function to merge CSS classes with Tailwind CSS conflict resolution.\r\n *\r\n * Combines `clsx` for conditional class handling with `tailwind-merge`\r\n * for proper Tailwind CSS class conflict resolution.\r\n *\r\n * @param inputs - Class values to merge (strings, arrays, objects, or conditionals)\r\n * @returns Merged and deduplicated class string\r\n *\r\n * @example\r\n * ```tsx\r\n * // Basic usage\r\n * cn(\"px-2 py-1\", \"px-4\") // \"py-1 px-4\"\r\n *\r\n * // Conditional classes\r\n * cn(\"base\", isActive && \"active\", { \"disabled\": isDisabled })\r\n *\r\n * // Arrays\r\n * cn([\"flex\", \"items-center\"], \"gap-2\")\r\n * ```\r\n */\r\nexport function cn(...inputs: ClassValue[]): string {\r\n return twMerge(clsx(inputs));\r\n}\r\n\r\n/**\r\n * Shallow equality check for arrays and primitives.\r\n * Used to stabilize useWatch output without JSON.stringify overhead.\r\n */\r\nexport function shallowEqual(a: unknown, b: unknown): boolean {\r\n if (Object.is(a, b)) return true;\r\n if (\r\n typeof a !== \"object\" ||\r\n typeof b !== \"object\" ||\r\n a === null ||\r\n b === null\r\n ) {\r\n return false;\r\n }\r\n\r\n if (Array.isArray(a) && Array.isArray(b)) {\r\n if (a.length !== b.length) return false;\r\n for (let i = 0; i < a.length; i++) {\r\n if (!Object.is(a[i], b[i])) return false;\r\n }\r\n return true;\r\n }\r\n\r\n const keysA = Object.keys(a);\r\n const keysB = Object.keys(b);\r\n if (keysA.length !== keysB.length) return false;\r\n\r\n for (const key of keysA) {\r\n if (\r\n !Object.prototype.hasOwnProperty.call(b, key) ||\r\n !Object.is(\r\n (a as Record<string, unknown>)[key],\r\n (b as Record<string, unknown>)[key],\r\n )\r\n ) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n}\r\n\r\n/**\r\n * Re-export ClassValue type for consumers who need it.\r\n */\r\nexport type { ClassValue };\r\n","import type { FieldValues } from \"react-hook-form\";\r\nimport type {\r\n FormSchema,\r\n Section,\r\n BaseField,\r\n ConditionRule,\r\n ConditionConfig,\r\n ValidationRules,\r\n} from \"./types\";\r\n\r\n// ============================================================================\r\n// Condition Types (union used by both evaluateCondition and extractWatchNames)\r\n// ============================================================================\r\n\r\n/**\r\n * All supported condition shapes.\r\n */\r\nexport type Condition<TFieldValues extends FieldValues = FieldValues> =\r\n | ((formValues: Partial<TFieldValues>) => boolean)\r\n | ConditionRule<TFieldValues>\r\n | ConditionRule<TFieldValues>[]\r\n | ConditionConfig<TFieldValues>\r\n | undefined;\r\n\r\n// ============================================================================\r\n// Internal Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Resolves a dot-notation path against an object.\r\n * Handles array indices: \"items.0.name\" resolves through arrays correctly.\r\n */\r\nfunction getNestedValue(obj: Record<string, unknown>, path: string): unknown {\r\n const parts = path.split(\".\");\r\n let current: unknown = obj;\r\n for (const part of parts) {\r\n if (current == null || typeof current !== \"object\") return undefined;\r\n if (Array.isArray(current)) {\r\n const index = Number(part);\r\n if (Number.isNaN(index)) return undefined;\r\n current = current[index];\r\n } else {\r\n current = (current as Record<string, unknown>)[part];\r\n }\r\n }\r\n return current;\r\n}\r\n\r\n/**\r\n * Evaluates a single condition rule against form values.\r\n * Supports both flat dotted keys (\"address.city\" as literal key) and\r\n * nested object resolution (values.address.city). Flat key takes priority\r\n * because DynamicFieldWrapper reconstructs watched values as flat keys.\r\n */\r\nfunction evaluateRule<TFieldValues extends FieldValues>(\r\n rule: ConditionRule<TFieldValues>,\r\n formValues: Partial<TFieldValues>,\r\n): boolean {\r\n const watchPath = rule.watch as string;\r\n const obj = formValues as Record<string, unknown>;\r\n // Flat key first (handles DynamicFieldWrapper's { \"address.city\": val }),\r\n // then nested resolution (handles full form values { address: { city: val } })\r\n const value = watchPath in obj\r\n ? obj[watchPath]\r\n : getNestedValue(obj, watchPath);\r\n\r\n switch (rule.operator) {\r\n case \"===\":\r\n return value === rule.value;\r\n case \"!==\":\r\n return value !== rule.value;\r\n case \"in\":\r\n return Array.isArray(rule.value) && rule.value.includes(value);\r\n case \"not-in\":\r\n return Array.isArray(rule.value) && !rule.value.includes(value);\r\n case \"truthy\":\r\n return Boolean(value);\r\n case \"falsy\":\r\n return !value;\r\n default:\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Type guard: checks if a condition is a ConditionConfig (has `rules` array).\r\n */\r\nfunction isConditionConfig<TFieldValues extends FieldValues>(\r\n condition: NonNullable<Condition<TFieldValues>>,\r\n): condition is ConditionConfig<TFieldValues> {\r\n return (\r\n typeof condition === \"object\" &&\r\n !Array.isArray(condition) &&\r\n \"rules\" in condition\r\n );\r\n}\r\n\r\n/**\r\n * Extracts the rules array from any non-function condition shape.\r\n */\r\nfunction toRules<TFieldValues extends FieldValues>(\r\n condition: Exclude<NonNullable<Condition<TFieldValues>>, Function>,\r\n): { rules: ConditionRule<TFieldValues>[]; logic: \"and\" | \"or\" } {\r\n if (isConditionConfig(condition)) {\r\n return { rules: condition.rules, logic: condition.logic ?? \"and\" };\r\n }\r\n const rules = Array.isArray(condition) ? condition : [condition];\r\n return { rules, logic: \"and\" };\r\n}\r\n\r\n// ============================================================================\r\n// Public API\r\n// ============================================================================\r\n\r\n/**\r\n * Evaluates a conditional rule, array of rules, or a ConditionConfig against form values.\r\n * Supports AND (default) and OR logic via ConditionConfig.\r\n *\r\n * @param condition - The condition function, rule(s), or config\r\n * @param formValues - The form values to evaluate against\r\n * @returns boolean indicating if condition matches\r\n */\r\nexport function evaluateCondition<\r\n TFieldValues extends FieldValues = FieldValues,\r\n>(\r\n condition: Condition<TFieldValues>,\r\n formValues: Partial<TFieldValues>,\r\n): boolean {\r\n if (!condition) return true;\r\n\r\n if (typeof condition === \"function\") {\r\n return condition(formValues);\r\n }\r\n\r\n const { rules, logic } = toRules(condition);\r\n const evalFn = (rule: ConditionRule<TFieldValues>) =>\r\n evaluateRule(rule, formValues);\r\n\r\n return logic === \"or\" ? rules.some(evalFn) : rules.every(evalFn);\r\n}\r\n\r\n/**\r\n * Extracts all watch names from a condition to optimize `useWatch`.\r\n * Handles single rules, arrays, and ConditionConfig objects.\r\n */\r\nexport function extractWatchNames<\r\n TFieldValues extends FieldValues = FieldValues,\r\n>(condition: Condition<TFieldValues>): string[] {\r\n if (!condition || typeof condition === \"function\") return [];\r\n\r\n const { rules } = toRules(condition);\r\n return rules.map((r) => r.watch as string);\r\n}\r\n\r\n/**\r\n * Strictly types a comprehensive form schema, granting exact intellisense bounds across conditions and nested watches.\r\n */\r\nexport function defineSchema<TFieldValues extends FieldValues = FieldValues>(\r\n schema: FormSchema<TFieldValues>,\r\n): FormSchema<TFieldValues> {\r\n return schema;\r\n}\r\n\r\n/**\r\n * Standard utility to strictly type a standalone field out-of-bounds, useful for externalizing massive schema structures.\r\n */\r\nexport function defineField<TFieldValues extends FieldValues = FieldValues>(\r\n field: BaseField<TFieldValues>,\r\n): BaseField<TFieldValues> {\r\n return field;\r\n}\r\n\r\n/**\r\n * Standard utility to strictly type a standalone logic section layout block.\r\n */\r\nexport function defineSection<TFieldValues extends FieldValues = FieldValues>(\r\n section: Section<TFieldValues>,\r\n): Section<TFieldValues> {\r\n return section;\r\n}\r\n\r\n/**\r\n * Extracts default values from a form schema.\r\n * Walks all sections and fields, respecting nameSpace prefixes and group nesting.\r\n *\r\n * @example\r\n * ```ts\r\n * const defaults = extractDefaultValues(schema);\r\n * const form = useForm({ defaultValues: defaults });\r\n * ```\r\n */\r\nexport function extractDefaultValues<\r\n TFieldValues extends FieldValues = FieldValues,\r\n>(schema: FormSchema<TFieldValues>): Partial<TFieldValues> {\r\n const defaults: Record<string, unknown> = {};\r\n\r\n for (const section of schema.sections) {\r\n const prefix = section.nameSpace ? `${section.nameSpace}.` : \"\";\r\n if (!section.fields) continue;\r\n\r\n for (const field of section.fields) {\r\n if (field.defaultValue !== undefined) {\r\n defaults[`${prefix}${field.name as string}`] = field.defaultValue;\r\n }\r\n // Handle group itemFields defaults (skip array types — items are dynamic)\r\n if (field.itemFields && field.type !== \"array\") {\r\n for (const sub of field.itemFields) {\r\n if (sub.defaultValue !== undefined) {\r\n defaults[\r\n `${prefix}${field.name as string}.${sub.name as string}`\r\n ] = sub.defaultValue;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n return defaults as Partial<TFieldValues>;\r\n}\r\n\r\n/**\r\n * Generates react-hook-form `RegisterOptions`-compatible validation rules\r\n * from a field's schema props. Maps `required`, `min`, `max`, `minLength`,\r\n * `maxLength`, `pattern`, and `validate` to RHF rules.\r\n *\r\n * @example\r\n * ```tsx\r\n * import { buildValidationRules } from '@classytic/formkit';\r\n *\r\n * function FormInput({ field, control }: FieldComponentProps) {\r\n * const rules = buildValidationRules(field);\r\n * return <Controller name={field.name} control={control} rules={rules} render={...} />;\r\n * }\r\n * ```\r\n */\r\nexport function buildValidationRules<\r\n TFieldValues extends FieldValues = FieldValues,\r\n>(field: BaseField<TFieldValues>): ValidationRules {\r\n const rules: ValidationRules = {};\r\n\r\n if (field.required) {\r\n rules.required = `${field.label || (field.name as string)} is required`;\r\n }\r\n if (field.minLength !== undefined) {\r\n rules.minLength = {\r\n value: field.minLength,\r\n message: `At least ${field.minLength} characters`,\r\n };\r\n }\r\n if (field.maxLength !== undefined) {\r\n rules.maxLength = {\r\n value: field.maxLength,\r\n message: `At most ${field.maxLength} characters`,\r\n };\r\n }\r\n if (field.min !== undefined) {\r\n rules.min = {\r\n value: field.min,\r\n message: `Must be at least ${field.min}`,\r\n };\r\n }\r\n if (field.max !== undefined) {\r\n rules.max = {\r\n value: field.max,\r\n message: `Must be at most ${field.max}`,\r\n };\r\n }\r\n if (field.pattern) {\r\n rules.pattern = {\r\n value: new RegExp(field.pattern),\r\n message: \"Invalid format\",\r\n };\r\n }\r\n if (field.validate) {\r\n rules.validate = field.validate as ValidationRules[\"validate\"];\r\n }\r\n\r\n return rules;\r\n}\r\n","\"use client\";\r\n\r\nimport { useEffect, useState, useMemo, useRef } from \"react\";\r\nimport {\r\n useFormContext,\r\n useFormState,\r\n useWatch,\r\n useFieldArray,\r\n} from \"react-hook-form\";\r\nimport type {\r\n Control,\r\n FieldValues,\r\n FieldArrayPath,\r\n FieldError,\r\n Path,\r\n} from \"react-hook-form\";\r\nimport {\r\n useFieldComponent,\r\n useLayoutComponent,\r\n useFormSystem,\r\n} from \"./FormSystemContext\";\r\nimport { cn, shallowEqual } from \"./utils\";\r\nimport { evaluateCondition, extractWatchNames } from \"./schema\";\r\nimport type {\r\n FormGeneratorProps,\r\n Section,\r\n BaseField,\r\n FieldComponentProps,\r\n Variant,\r\n FormElement,\r\n} from \"./types\";\r\n\r\n// ============================================================================\r\n// Helpers\r\n// ============================================================================\r\n\r\n/** Generate a deterministic field ID for accessibility label-input association. */\r\nfunction toFieldId(name: string): string {\r\n return `formkit-field-${name.replace(/[.[\\]]/g, \"-\")}`;\r\n}\r\n\r\n/**\r\n * Get nested value from an object using dot-notation path.\r\n * Handles array indices: \"items.0.name\" resolves through arrays correctly.\r\n */\r\nfunction getNestedValue(\r\n obj: Record<string, unknown>,\r\n path: string,\r\n): unknown {\r\n const parts = path.split(\".\");\r\n let current: unknown = obj;\r\n for (const part of parts) {\r\n if (current == null || typeof current !== \"object\") return undefined;\r\n if (Array.isArray(current)) {\r\n const index = Number(part);\r\n if (Number.isNaN(index)) return undefined;\r\n current = current[index];\r\n } else {\r\n current = (current as Record<string, unknown>)[part];\r\n }\r\n }\r\n return current;\r\n}\r\n\r\n/**\r\n * Get nested error from react-hook-form errors object.\r\n * Supports dot-notation paths like \"address.street\" and array paths like \"items.0.name\".\r\n */\r\nfunction getNestedError(\r\n errors: Record<string, unknown>,\r\n path: string,\r\n): FieldError | undefined {\r\n const result = getNestedValue(errors, path);\r\n // FieldError has a `message` property\r\n if (result && typeof result === \"object\" && \"message\" in result) {\r\n return result as FieldError;\r\n }\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Prefix field names with a namespace.\r\n * Memoization-friendly: returns the same shape for stable inputs.\r\n */\r\nfunction prefixFields<TFieldValues extends FieldValues>(\r\n fields: BaseField<TFieldValues>[],\r\n nameSpace: string,\r\n): BaseField<TFieldValues>[] {\r\n return fields.map((f) => ({\r\n ...f,\r\n name: `${nameSpace}.${f.name as string}`,\r\n itemFields: f.itemFields?.map((i) => ({\r\n ...i,\r\n name: `${nameSpace}.${f.name as string}.${i.name as string}`,\r\n })),\r\n })) as BaseField<TFieldValues>[];\r\n}\r\n\r\n// ============================================================================\r\n// FormGenerator Component\r\n// ============================================================================\r\n\r\n/**\r\n * FormGenerator - Headless Form Generator Component\r\n *\r\n * Renders a form based on a schema definition, using components registered\r\n * via FormSystemProvider. Supports conditional fields, dynamic layouts,\r\n * and component variants.\r\n *\r\n * @template TFieldValues - Form field values type for type safety\r\n *\r\n * @example\r\n * ```tsx\r\n * import { useFormKit, FormGenerator } from '@classytic/formkit';\r\n *\r\n * const { handleSubmit, generatorProps } = useFormKit({\r\n * schema: formSchema,\r\n * resolver: zodResolver(validationSchema),\r\n * });\r\n *\r\n * return (\r\n * <form onSubmit={handleSubmit(onSubmit)}>\r\n * <FormGenerator {...generatorProps} />\r\n * </form>\r\n * );\r\n * ```\r\n */\r\nexport function FormGenerator<TFieldValues extends FieldValues = FieldValues>({\r\n schema,\r\n control,\r\n disabled = false,\r\n variant,\r\n className,\r\n ref,\r\n}: FormGeneratorProps<TFieldValues>): FormElement {\r\n // Use provided control or fall back to FormProvider context\r\n const formContext = useFormContext<TFieldValues>();\r\n const activeControl = control ?? formContext?.control;\r\n\r\n if (!activeControl) {\r\n console.warn(\r\n \"[FormKit] FormGenerator requires a `control` prop or to be wrapped in a <FormProvider>.\",\r\n );\r\n return null;\r\n }\r\n\r\n // Early return if no schema\r\n if (!schema?.sections || schema.sections.length === 0) {\r\n return null;\r\n }\r\n\r\n return (\r\n <div\r\n ref={ref}\r\n className={cn(\r\n \"formkit-root\",\r\n variant && `formkit-variant-${variant}`,\r\n className,\r\n )}\r\n data-formkit-root=\"\"\r\n >\r\n {schema.sections.map((section, index) => (\r\n <SectionRenderer\r\n key={section.id ?? `section-${index}`}\r\n section={section}\r\n control={activeControl}\r\n disabled={disabled}\r\n variant={variant}\r\n />\r\n ))}\r\n </div>\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Section Renderer\r\n// ============================================================================\r\n\r\ninterface SectionRendererProps<TFieldValues extends FieldValues = FieldValues> {\r\n section: Section<TFieldValues>;\r\n control?: Control<TFieldValues>;\r\n disabled?: boolean;\r\n variant?: Variant;\r\n}\r\n\r\n/**\r\n * Renders a single section with its fields.\r\n */\r\nfunction SectionRenderer<TFieldValues extends FieldValues = FieldValues>(\r\n props: SectionRendererProps<TFieldValues>,\r\n): FormElement {\r\n if (props.section.condition) {\r\n return <DynamicSectionRenderer {...props} />;\r\n }\r\n return <StaticSectionRenderer {...props} />;\r\n}\r\n\r\n/**\r\n * Section renderer that evaluates conditions reactively.\r\n * Scopes useWatch to only the fields referenced in the condition\r\n * to avoid re-rendering on every form change.\r\n */\r\nfunction DynamicSectionRenderer<\r\n TFieldValues extends FieldValues = FieldValues,\r\n>(props: SectionRendererProps<TFieldValues>): FormElement {\r\n const conditionWatchNames = useMemo(\r\n () => extractWatchNames(props.section.condition),\r\n [props.section.condition],\r\n );\r\n\r\n // Scope watch to condition dependencies when possible\r\n const watchedRaw = conditionWatchNames.length > 0\r\n ? useWatch({ control: props.control, name: conditionWatchNames as unknown as readonly Path<TFieldValues>[] })\r\n : useWatch({ control: props.control });\r\n\r\n // Reconstruct named values if we watched specific names\r\n const sectionValues = useMemo(() => {\r\n if (conditionWatchNames.length > 0 && Array.isArray(watchedRaw)) {\r\n return conditionWatchNames.reduce<Record<string, unknown>>(\r\n (acc, name, i) => ({ ...acc, [name]: watchedRaw[i] }),\r\n {},\r\n );\r\n }\r\n return watchedRaw;\r\n }, [conditionWatchNames, watchedRaw]);\r\n\r\n if (\r\n !evaluateCondition(\r\n props.section.condition,\r\n sectionValues as Partial<TFieldValues>,\r\n )\r\n ) {\r\n return null;\r\n }\r\n return <StaticSectionRenderer {...props} />;\r\n}\r\n\r\nfunction StaticSectionRenderer<\r\n TFieldValues extends FieldValues = FieldValues,\r\n>({\r\n section,\r\n control,\r\n disabled,\r\n variant,\r\n}: SectionRendererProps<TFieldValues>): FormElement {\r\n // Section can override variant\r\n const activeVariant = section.variant ?? variant;\r\n const SectionLayout = useLayoutComponent(\"section\", activeVariant);\r\n\r\n // Memoize namespace-prefixed fields to avoid creating new arrays every render\r\n const resolvedFields = useMemo(() => {\r\n if (section.nameSpace && section.fields) {\r\n return prefixFields(section.fields, section.nameSpace);\r\n }\r\n return section.fields;\r\n }, [section.nameSpace, section.fields]);\r\n\r\n return (\r\n <SectionLayout\r\n title={section.title}\r\n description={section.description}\r\n icon={section.icon}\r\n variant={activeVariant}\r\n className={section.className}\r\n collapsible={section.collapsible}\r\n defaultCollapsed={section.defaultCollapsed}\r\n >\r\n {section.render ? (\r\n // Custom render function\r\n section.render({ control, disabled, section })\r\n ) : (\r\n // Standard grid rendering\r\n <GridRenderer\r\n fields={resolvedFields}\r\n cols={section.cols}\r\n gap={section.gap}\r\n control={control}\r\n disabled={disabled}\r\n variant={activeVariant}\r\n />\r\n )}\r\n </SectionLayout>\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Grid Renderer\r\n// ============================================================================\r\n\r\ninterface GridRendererProps<TFieldValues extends FieldValues = FieldValues> {\r\n fields?: BaseField<TFieldValues>[];\r\n cols?: number;\r\n gap?: number;\r\n control?: Control<TFieldValues>;\r\n disabled?: boolean;\r\n variant?: Variant;\r\n}\r\n\r\n/**\r\n * Renders a grid of fields with specified column layout.\r\n */\r\nfunction GridRenderer<TFieldValues extends FieldValues = FieldValues>({\r\n fields,\r\n cols = 1,\r\n gap,\r\n control,\r\n disabled,\r\n variant,\r\n}: GridRendererProps<TFieldValues>): FormElement {\r\n const GridLayout = useLayoutComponent(\"grid\", variant);\r\n\r\n if (!fields || fields.length === 0) {\r\n return null;\r\n }\r\n\r\n return (\r\n <GridLayout cols={cols} gap={gap}>\r\n {fields.map((field, index) => (\r\n <FieldWrapper\r\n key={field.name || `field-${index}`}\r\n field={field}\r\n control={control}\r\n disabled={disabled}\r\n variant={variant}\r\n />\r\n ))}\r\n </GridLayout>\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Field Wrapper\r\n// ============================================================================\r\n\r\ninterface FieldWrapperProps<TFieldValues extends FieldValues = FieldValues> {\r\n field: BaseField<TFieldValues>;\r\n control?: Control<TFieldValues>;\r\n disabled?: boolean;\r\n variant?: Variant;\r\n}\r\n\r\n/**\r\n * Wraps individual fields.\r\n * If the field requires conditional logic or dynamic options, it uses the Dynamic wrapper.\r\n * Otherwise, it uses the Static wrapper, vastly improving performance by skipping `useWatch`.\r\n */\r\nfunction FieldWrapper<TFieldValues extends FieldValues = FieldValues>(\r\n props: FieldWrapperProps<TFieldValues>,\r\n): FormElement {\r\n if (props.field.condition || props.field.loadOptions) {\r\n return <DynamicFieldWrapper {...props} />;\r\n }\r\n return <StaticFieldWrapper {...props} />;\r\n}\r\n\r\n/**\r\n * Dynamic Field Wrapper\r\n * Conditionally calls `useWatch` to trigger re-renders only when form values change.\r\n * Can be optimized further by providing `watchNames` on the field.\r\n */\r\nfunction DynamicFieldWrapper<TFieldValues extends FieldValues = FieldValues>({\r\n field,\r\n control,\r\n disabled,\r\n variant,\r\n}: FieldWrapperProps<TFieldValues>): FormElement {\r\n // Combine explicit watchNames with names extracted from DSL condition rules\r\n const ruleWatchNames = useMemo(\r\n () => extractWatchNames(field.condition),\r\n [field.condition],\r\n );\r\n const explicitWatchNames = useMemo(() => {\r\n if (Array.isArray(field.watchNames)) return field.watchNames as string[];\r\n if (field.watchNames) return [field.watchNames as string];\r\n return [];\r\n }, [field.watchNames]);\r\n\r\n // Stabilize the watch names list across renders using ref comparison\r\n const allWatchNamesRef = useRef<string[]>([]);\r\n const allWatchNames = useMemo(() => {\r\n const next = Array.from(\r\n new Set([...explicitWatchNames, ...ruleWatchNames]),\r\n );\r\n // Only return new array if contents actually changed\r\n if (\r\n next.length === allWatchNamesRef.current.length &&\r\n next.every((n, i) => n === allWatchNamesRef.current[i])\r\n ) {\r\n return allWatchNamesRef.current;\r\n }\r\n allWatchNamesRef.current = next;\r\n return next;\r\n }, [explicitWatchNames, ruleWatchNames]);\r\n\r\n // Watch form values for conditional rendering.\r\n // When specific watch names are available we pass them to limit re-renders;\r\n // otherwise we watch the entire form.\r\n const watchedRaw = allWatchNames.length > 0\r\n ? useWatch({ control, name: allWatchNames as unknown as readonly Path<TFieldValues>[] })\r\n : useWatch({ control });\r\n\r\n // Use shallow comparison to stabilize watched values without JSON.stringify cost\r\n const prevWatchedRef = useRef(watchedRaw);\r\n const stableWatched = useMemo(() => {\r\n if (shallowEqual(prevWatchedRef.current, watchedRaw)) {\r\n return prevWatchedRef.current;\r\n }\r\n prevWatchedRef.current = watchedRaw;\r\n return watchedRaw;\r\n }, [watchedRaw]);\r\n\r\n // Reconstruct correctly typed partial payload for conditions if watchNames arrays were mapped\r\n const watchedValues = useMemo(() => {\r\n if (allWatchNames.length > 0 && Array.isArray(stableWatched)) {\r\n return allWatchNames.reduce<Record<string, unknown>>(\r\n (acc, name, i) => ({ ...acc, [name]: stableWatched[i] }),\r\n {},\r\n );\r\n }\r\n return stableWatched;\r\n }, [allWatchNames, stableWatched]);\r\n\r\n const [options, setOptions] = useState(field.options || []);\r\n const [isLoading, setIsLoading] = useState(false);\r\n // Store loading timeout to cleanly clear debounce sweeps\r\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\r\n\r\n useEffect(() => {\r\n if (!field.loadOptions) return;\r\n\r\n let isActive = true;\r\n\r\n const executeLoad = () => {\r\n const res = field.loadOptions!(\r\n watchedValues as Partial<TFieldValues>,\r\n );\r\n if (res instanceof Promise) {\r\n setIsLoading(true);\r\n res\r\n .then((newOptions) => {\r\n if (isActive) setOptions(newOptions);\r\n })\r\n .catch((err: unknown) => {\r\n if (isActive) {\r\n if (field.onLoadError) {\r\n field.onLoadError(err);\r\n } else {\r\n console.error(\"[FormKit] loadOptions error:\", err);\r\n }\r\n }\r\n })\r\n .finally(() => {\r\n if (isActive) setIsLoading(false);\r\n });\r\n } else {\r\n setOptions(res);\r\n setIsLoading(false);\r\n }\r\n };\r\n\r\n if (field.debounceMs && field.debounceMs > 0) {\r\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\r\n timeoutRef.current = setTimeout(executeLoad, field.debounceMs);\r\n } else {\r\n executeLoad();\r\n }\r\n\r\n return () => {\r\n isActive = false;\r\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\r\n };\r\n }, [watchedValues, field.loadOptions, field.debounceMs, field.onLoadError]);\r\n\r\n // Memoize the augmented field to avoid creating new objects every render\r\n // Must be before the conditional return to satisfy rules of hooks\r\n const loadingState = field.loadOptions ? isLoading : undefined;\r\n const dynamicField = useMemo<BaseField<TFieldValues>>(() => ({\r\n ...field,\r\n options: field.loadOptions ? options : field.options,\r\n isLoading: loadingState,\r\n } as BaseField<TFieldValues>), [field, options, loadingState]);\r\n\r\n // Check field condition\r\n if (\r\n !evaluateCondition(\r\n field.condition,\r\n watchedValues as Partial<TFieldValues>,\r\n )\r\n ) {\r\n return null;\r\n }\r\n\r\n return (\r\n <StaticFieldWrapper\r\n field={dynamicField}\r\n control={control}\r\n disabled={disabled}\r\n variant={variant}\r\n isLoading={loadingState}\r\n />\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Static Field Wrapper\r\n// ============================================================================\r\n\r\ninterface StaticFieldWrapperProps<TFieldValues extends FieldValues = FieldValues>\r\n extends FieldWrapperProps<TFieldValues> {\r\n isLoading?: boolean;\r\n}\r\n\r\n/**\r\n * Static Field Wrapper\r\n * Handles rendering the actual component via the registry, or via a custom static `render`.\r\n * Does not use `useWatch` internally.\r\n */\r\nfunction StaticFieldWrapper<TFieldValues extends FieldValues = FieldValues>({\r\n field,\r\n control,\r\n disabled,\r\n variant,\r\n isLoading,\r\n}: StaticFieldWrapperProps<TFieldValues>): FormElement {\r\n // All hooks must be called unconditionally at the top\r\n const { components } = useFormSystem();\r\n const fieldName = field.name as string;\r\n const { errors, dirtyFields, touchedFields } = useFormState({\r\n control,\r\n name: fieldName as Path<TFieldValues>,\r\n });\r\n\r\n // Merge disabled states\r\n const isDisabled = disabled || field.disabled;\r\n const fieldId = toFieldId(fieldName);\r\n const fieldError = getNestedError(\r\n errors as Record<string, unknown>,\r\n fieldName,\r\n );\r\n const isDirty = Boolean(\r\n getNestedValue(dirtyFields as Record<string, unknown>, fieldName),\r\n );\r\n const isTouched = Boolean(\r\n getNestedValue(touchedFields as Record<string, unknown>, fieldName),\r\n );\r\n const fieldState = useMemo(\r\n () => ({\r\n invalid: !!fieldError,\r\n isDirty,\r\n isTouched,\r\n isValidating: false,\r\n error: fieldError,\r\n }),\r\n [fieldError, isDirty, isTouched],\r\n );\r\n const activeVariant = field.variant ?? variant;\r\n\r\n // Render override bypassing the registry completely\r\n if (field.render) {\r\n return (\r\n <div\r\n className={cn(\r\n \"formkit-field\",\r\n field.fullWidth && \"col-span-full\",\r\n field.className,\r\n )}\r\n id={fieldId}\r\n data-formkit-field={fieldName}\r\n data-field-type={field.type}\r\n >\r\n {field.render({\r\n ...field,\r\n field,\r\n control: control as Control<TFieldValues>,\r\n disabled: isDisabled,\r\n variant: activeVariant,\r\n error: fieldError,\r\n fieldState,\r\n fieldId,\r\n isLoading,\r\n } as FieldComponentProps<TFieldValues>)}\r\n </div>\r\n );\r\n }\r\n\r\n // Verify if a component explicitly exists for this type, preventing default \"text\" fallback\r\n // from devouring nested group types entirely.\r\n const hasExplicitComponent = Boolean(\r\n components[field.type] ||\r\n (activeVariant &&\r\n components[activeVariant] &&\r\n typeof components[activeVariant] === \"object\" &&\r\n (components[activeVariant] as Record<string, unknown>)[field.type]),\r\n );\r\n\r\n if (\r\n !hasExplicitComponent &&\r\n field.itemFields &&\r\n field.itemFields.length > 0\r\n ) {\r\n if (field.type === \"array\") {\r\n return (\r\n <ArrayFieldFallback\r\n field={field}\r\n control={control}\r\n disabled={isDisabled}\r\n variant={activeVariant}\r\n />\r\n );\r\n }\r\n\r\n // Default Group mapping fallback\r\n return (\r\n <div\r\n className={cn(\r\n \"formkit-field-group\",\r\n field.fullWidth && \"col-span-full\",\r\n field.className,\r\n )}\r\n data-formkit-field={fieldName}\r\n data-field-type={field.type}\r\n >\r\n <GridRenderer\r\n fields={field.itemFields}\r\n control={control}\r\n disabled={isDisabled}\r\n variant={activeVariant}\r\n />\r\n </div>\r\n );\r\n }\r\n\r\n const FieldComponent = useFieldComponent(field.type, activeVariant);\r\n\r\n if (!FieldComponent) {\r\n return null;\r\n }\r\n\r\n return (\r\n <div\r\n className={cn(\r\n \"formkit-field\",\r\n field.fullWidth && \"col-span-full\",\r\n field.className,\r\n )}\r\n id={fieldId}\r\n data-formkit-field={fieldName}\r\n data-field-type={field.type}\r\n >\r\n <FieldComponent\r\n {...(field as BaseField<FieldValues>)}\r\n field={field as BaseField<FieldValues>}\r\n control={control as Control<FieldValues>}\r\n disabled={isDisabled}\r\n variant={activeVariant}\r\n error={fieldError}\r\n fieldState={fieldState}\r\n fieldId={fieldId}\r\n isLoading={isLoading}\r\n />\r\n </div>\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Array Native Fallback Wrapper\r\n// ============================================================================\r\n\r\nfunction ArrayFieldFallback<TFieldValues extends FieldValues = FieldValues>({\r\n field,\r\n control,\r\n disabled,\r\n variant,\r\n}: FieldWrapperProps<TFieldValues>): FormElement {\r\n const { fields, append, remove } = useFieldArray({\r\n control,\r\n name: field.name as FieldArrayPath<TFieldValues>,\r\n });\r\n\r\n return (\r\n <div\r\n className={cn(\r\n \"formkit-field-array flex flex-col gap-4\",\r\n field.fullWidth && \"col-span-full\",\r\n field.className,\r\n )}\r\n data-formkit-field={field.name}\r\n data-field-type=\"array\"\r\n >\r\n <div className=\"flex items-center justify-between\">\r\n {field.label && (\r\n <label className=\"font-semibold\">{field.label}</label>\r\n )}\r\n </div>\r\n\r\n {fields.map((item, index) => (\r\n <div\r\n key={item.id}\r\n className=\"relative formkit-array-item border p-4 rounded-md\"\r\n >\r\n <GridRenderer\r\n fields={\r\n field.itemFields?.map((f) => ({\r\n ...f,\r\n name: `${field.name as string}.${index}.${f.name as string}`,\r\n })) as BaseField<TFieldValues>[] | undefined\r\n }\r\n control={control}\r\n disabled={disabled}\r\n variant={variant}\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={() => remove(index)}\r\n className=\"absolute top-2 right-2 text-red-500 hover:text-red-700 text-sm font-medium\"\r\n >\r\n Remove\r\n </button>\r\n </div>\r\n ))}\r\n <button\r\n type=\"button\"\r\n onClick={() => append({} as Record<string, unknown> as TFieldValues[string & keyof TFieldValues])}\r\n disabled={disabled}\r\n className=\"self-start mt-2 px-4 py-2 bg-blue-50 text-blue-600 rounded-md text-sm font-medium hover:bg-blue-100 disabled:opacity-50\"\r\n >\r\n + Add Item\r\n </button>\r\n </div>\r\n );\r\n}\r\n\r\n// ============================================================================\r\n// Named Exports for Subcomponents (for advanced use cases)\r\n// ============================================================================\r\n\r\nexport { SectionRenderer, GridRenderer, FieldWrapper };\r\n","import type { ReactNode } from \"react\";\r\nimport type { FieldValues, Control, FieldError } from \"react-hook-form\";\r\nimport type {\r\n BaseField,\r\n FieldOption,\r\n FieldOptionGroup,\r\n Section,\r\n} from \"./types\";\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Additional field props for builder helpers.\r\n * Accepts all BaseField properties except `name`, `type`, and `label`\r\n * which are set by the builder method.\r\n */\r\ntype FieldProps<TFieldValues extends FieldValues = FieldValues> = Omit<\r\n BaseField<TFieldValues>,\r\n \"name\" | \"type\" | \"label\"\r\n> & {\r\n /** Grid column class (e.g., \"col-span-2\") */\r\n gridColumn?: string;\r\n /** Icon for the left side of input */\r\n iconLeft?: ReactNode;\r\n /** Icon for the right side of input */\r\n iconRight?: ReactNode;\r\n /** Additional custom props */\r\n [key: string]: unknown;\r\n};\r\n\r\n/**\r\n * Section configuration props.\r\n */\r\ninterface SectionProps<TFieldValues extends FieldValues = FieldValues>\r\n extends Omit<Section<TFieldValues>, \"id\" | \"title\" | \"fields\" | \"cols\"> {\r\n cols?: number;\r\n}\r\n\r\n/**\r\n * Render function for custom field types.\r\n */\r\ntype CustomRenderFn = (props: {\r\n control: Control<FieldValues>;\r\n disabled?: boolean;\r\n error?: FieldError;\r\n}) => ReactNode;\r\n\r\n// ============================================================================\r\n// Field Builder\r\n// ============================================================================\r\n\r\n/**\r\n * Type-safe field builder helpers for schema-driven forms.\r\n *\r\n * Provides shorthand methods for common field types with sensible defaults,\r\n * reducing boilerplate while maintaining full type safety.\r\n *\r\n * @example\r\n * ```ts\r\n * import { field, section } from '@classytic/formkit';\r\n *\r\n * const schema = {\r\n * sections: [\r\n * section(\"personal\", \"Personal Info\", [\r\n * field.text(\"firstName\", \"First Name\", { required: true }),\r\n * field.email(\"email\", \"Email\"),\r\n * field.select(\"role\", \"Role\", [\r\n * { label: \"Admin\", value: \"admin\" },\r\n * { label: \"User\", value: \"user\" },\r\n * ]),\r\n * ], { cols: 2 }),\r\n * ],\r\n * };\r\n * ```\r\n */\r\nexport const field = {\r\n /**\r\n * Text input field.\r\n */\r\n text: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"text\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Email input field with default placeholder.\r\n */\r\n email: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"email\",\r\n name,\r\n label,\r\n placeholder: \"example@email.com\",\r\n ...props,\r\n }),\r\n\r\n /**\r\n * URL input field with default placeholder.\r\n */\r\n url: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"url\",\r\n name,\r\n label,\r\n placeholder: \"https://example.com\",\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Phone/tel input field with default placeholder.\r\n */\r\n tel: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"tel\",\r\n name,\r\n label,\r\n placeholder: \"+1 (555) 000-0000\",\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Password input field.\r\n */\r\n password: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"password\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Number input field with min: 0 default.\r\n */\r\n number: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"number\",\r\n name,\r\n label,\r\n min: 0,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Textarea field with default 3 rows.\r\n */\r\n textarea: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"textarea\",\r\n name,\r\n label,\r\n rows: 3,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Select dropdown field.\r\n */\r\n select: (\r\n name: string,\r\n label: string,\r\n options: (FieldOption | FieldOptionGroup)[],\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"select\",\r\n name,\r\n label,\r\n options,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Searchable combobox field.\r\n */\r\n combobox: (\r\n name: string,\r\n label: string,\r\n options: (FieldOption | FieldOptionGroup)[],\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"combobox\",\r\n name,\r\n label,\r\n options,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Multi-select field (tag choice).\r\n */\r\n multiselect: (\r\n name: string,\r\n label: string,\r\n options: (FieldOption | FieldOptionGroup)[],\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"multiselect\",\r\n name,\r\n label,\r\n options,\r\n placeholder: \"Select options...\",\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Dependent select field that reacts to parent field changes.\r\n */\r\n dependentSelect: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"dependentSelect\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Switch/toggle field.\r\n */\r\n switch: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"switch\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Boolean field (alias for switch).\r\n */\r\n boolean: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"switch\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Checkbox field.\r\n */\r\n checkbox: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"checkbox\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Radio button group field.\r\n */\r\n radio: (\r\n name: string,\r\n label: string,\r\n options: FieldOption[],\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"radio\",\r\n name,\r\n label,\r\n options,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Date picker field.\r\n */\r\n date: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"date\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Tag input field with default placeholder.\r\n */\r\n tags: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"tags\",\r\n name,\r\n label,\r\n placeholder: \"Add tags...\",\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Slug field with auto-generation from source value.\r\n */\r\n slug: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"slug\",\r\n name,\r\n label,\r\n placeholder: \"my-page-slug\",\r\n ...props,\r\n }),\r\n\r\n /**\r\n * File upload field.\r\n */\r\n file: (\r\n name: string,\r\n label: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"file\",\r\n name,\r\n label,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Hidden field (no UI).\r\n */\r\n hidden: (\r\n name: string,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"hidden\",\r\n name,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Group field for nested objects.\r\n * Renders itemFields as a sub-grid within the form.\r\n *\r\n * @example\r\n * ```ts\r\n * field.group(\"address\", \"Address\", [\r\n * field.text(\"street\", \"Street\"),\r\n * field.text(\"city\", \"City\"),\r\n * field.text(\"zip\", \"ZIP Code\"),\r\n * ], { cols: 3 })\r\n * ```\r\n */\r\n group: (\r\n name: string,\r\n label: string,\r\n itemFields: BaseField[],\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"group\",\r\n name,\r\n label,\r\n itemFields,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Array/repeatable field.\r\n * Renders a dynamic list of sub-forms using react-hook-form's useFieldArray.\r\n *\r\n * @example\r\n * ```ts\r\n * field.array(\"contacts\", \"Contacts\", [\r\n * field.text(\"name\", \"Name\"),\r\n * field.email(\"email\", \"Email\"),\r\n * ])\r\n * ```\r\n */\r\n array: (\r\n name: string,\r\n label: string,\r\n itemFields: BaseField[],\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"array\",\r\n name,\r\n label,\r\n itemFields,\r\n ...props,\r\n }),\r\n\r\n /**\r\n * Custom field with a render function.\r\n * Bypasses the component registry entirely.\r\n *\r\n * @example\r\n * ```ts\r\n * field.custom(\"skills\", \"Skills\", ({ control, disabled }) => (\r\n * <SkillSelector control={control} disabled={disabled} />\r\n * ))\r\n * ```\r\n */\r\n custom: (\r\n name: string,\r\n label: string,\r\n render: CustomRenderFn,\r\n props: FieldProps = {},\r\n ): BaseField => ({\r\n type: \"custom\",\r\n name,\r\n label,\r\n render: render as BaseField[\"render\"],\r\n ...props,\r\n }),\r\n};\r\n\r\n// ============================================================================\r\n// Section Builder\r\n// ============================================================================\r\n\r\n/**\r\n * Create a section definition with sensible defaults.\r\n *\r\n * @param id - Unique section identifier\r\n * @param title - Section title\r\n * @param fields - Array of field definitions\r\n * @param props - Additional section configuration\r\n *\r\n * @example\r\n * ```ts\r\n * section(\"personal\", \"Personal Info\", [\r\n * field.text(\"name\", \"Name\", { required: true }),\r\n * field.email(\"email\", \"Email\"),\r\n * ], { cols: 2, variant: \"card\" })\r\n * ```\r\n */\r\nexport function section<TFieldValues extends FieldValues = FieldValues>(\r\n id: string,\r\n title: string,\r\n fields: BaseField<TFieldValues>[],\r\n props: SectionProps<TFieldValues> = {},\r\n): Section<TFieldValues> {\r\n const { cols = 2, ...rest } = props;\r\n return {\r\n id,\r\n title,\r\n fields,\r\n cols,\r\n ...rest,\r\n };\r\n}\r\n\r\n/**\r\n * Create a section without a title (transparent section).\r\n * Useful for grouping fields without visual separation.\r\n */\r\nexport function sectionUntitled<TFieldValues extends FieldValues = FieldValues>(\r\n fields: BaseField<TFieldValues>[],\r\n props: Omit<SectionProps<TFieldValues>, \"variant\"> = {},\r\n): Section<TFieldValues> {\r\n const { cols = 1, ...rest } = props;\r\n return {\r\n fields,\r\n cols,\r\n variant: \"transparent\",\r\n ...rest,\r\n };\r\n}\r\n","\"use client\";\r\n\r\nimport { useMemo } from \"react\";\r\nimport { useForm } from \"react-hook-form\";\r\nimport type { UseFormProps, UseFormReturn, FieldValues } from \"react-hook-form\";\r\nimport { extractDefaultValues } from \"./schema\";\r\nimport type { FormSchema, FormGeneratorProps, Variant } from \"./types\";\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Options for the useFormKit hook.\r\n * Extends react-hook-form's UseFormProps with schema-driven defaults.\r\n */\r\nexport interface UseFormKitOptions<\r\n TFieldValues extends FieldValues = FieldValues,\r\n> extends Omit<UseFormProps<TFieldValues>, \"defaultValues\"> {\r\n /** Form schema defining sections and fields. Accepts any FormSchema generic. */\r\n schema: FormSchema<any>;\r\n /** Override or extend default values extracted from schema */\r\n defaultValues?: UseFormProps<TFieldValues>[\"defaultValues\"];\r\n /** Disable all fields */\r\n disabled?: boolean;\r\n /** Global variant */\r\n variant?: Variant;\r\n /** Root element className */\r\n className?: string;\r\n}\r\n\r\n/**\r\n * Return value from useFormKit.\r\n * Includes all useForm methods plus pre-built generatorProps.\r\n */\r\nexport interface UseFormKitReturn<\r\n TFieldValues extends FieldValues = FieldValues,\r\n> extends UseFormReturn<TFieldValues> {\r\n /** Props to spread onto <FormGenerator /> */\r\n generatorProps: Pick<\r\n FormGeneratorProps<TFieldValues>,\r\n \"schema\" | \"control\" | \"disabled\" | \"variant\" | \"className\"\r\n >;\r\n}\r\n\r\n// ============================================================================\r\n// Hook\r\n// ============================================================================\r\n\r\n/**\r\n * Convenience hook that combines schema default extraction with react-hook-form setup.\r\n * Returns all useForm methods plus ready-to-spread `generatorProps`.\r\n *\r\n * @example\r\n * ```tsx\r\n * const { handleSubmit, generatorProps } = useFormKit({\r\n * schema: formSchema,\r\n * resolver: zodResolver(validationSchema),\r\n * });\r\n *\r\n * return (\r\n * <form onSubmit={handleSubmit(onSubmit)}>\r\n * <FormGenerator {...generatorProps} />\r\n * <button type=\"submit\">Submit</button>\r\n * </form>\r\n * );\r\n * ```\r\n */\r\nexport function useFormKit<TFieldValues extends FieldValues = FieldValues>(\r\n options: UseFormKitOptions<TFieldValues>,\r\n): UseFormKitReturn<TFieldValues> {\r\n const { schema, disabled, variant, className, defaultValues, ...formOptions } =\r\n options;\r\n\r\n // Extract defaults from schema, merge with explicit overrides\r\n const schemaDefaults = extractDefaultValues(schema);\r\n const mergedDefaults = {\r\n ...schemaDefaults,\r\n ...(typeof defaultValues === \"object\" && defaultValues !== null\r\n ? defaultValues\r\n : {}),\r\n } as UseFormProps<TFieldValues>[\"defaultValues\"];\r\n\r\n const form = useForm<TFieldValues>({\r\n ...formOptions,\r\n defaultValues: mergedDefaults,\r\n });\r\n\r\n const generatorProps = useMemo(\r\n () => ({\r\n schema,\r\n control: form.control,\r\n disabled,\r\n variant,\r\n className,\r\n }),\r\n [schema, form.control, disabled, variant, className],\r\n );\r\n\r\n // Return the original form object with generatorProps attached.\r\n // We assign directly instead of spreading to preserve referential identity\r\n // of the useForm return value — spreading creates a new object every render,\r\n // which breaks useEffect dependency arrays that include the form.\r\n return Object.assign(form, { generatorProps });\r\n}\r\n"],"mappings":";;;;;;;;AAqBA,MAAM,oBAAoB,cAA6C,KAAK;AAG5E,kBAAkB,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuChC,SAAgB,mBAAmB,EACjC,YACA,SACA,YACuC;AASvC,QAAO,oBAAC;EAAkB,OARZ,eACL;GACL,YAAY,cAAc,EAAE;GAC5B,SAAS,WAAW,EAAE;GACvB,GACD,CAAC,YAAY,QAAQ,CACtB;EAEwC;GAA6B;;;;;;;;;;;;;AAkBxE,SAAgB,gBAAwC;CACtD,MAAM,UAAU,WAAW,kBAAkB;AAC7C,KAAI,CAAC,QACH,OAAM,IAAI,MACR,sIAED;AAEH,QAAO;;;;;;;;;;;;;;;;;AAkBT,SAAgB,kBAAkB,MAAiB,SAAmC;CACpF,MAAM,EAAE,eAAe,eAAe;AAGtC,KAAI,WAAW,OAAO,WAAW,aAAa,YAAY,WAAW,aAAa,MAAM;EAEtF,MAAM,mBADoB,WAAW,SACM;AAC3C,MAAI,iBACF,QAAO;;CAKX,MAAM,gBAAgB,WAAW;AACjC,KAAI,iBAAiB,OAAO,kBAAkB,WAC5C,QAAO;CAIT,MAAM,mBAAmB,WAAW;AACpC,KAAI,oBAAoB,OAAO,qBAAqB,WAClD,QAAO;CAIT,MAAM,gBAAgB,WAAW;AACjC,KAAI,iBAAiB,OAAO,kBAAkB,WAC5C,QAAO;AAIT,KAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,UAAQ,KACN,0CAA0C,KAAK,GAAG,UAAU,eAAe,QAAQ,MAAM,GAAG,kEAE7F;AACD,SAAO;;AAIT,QAAO;;;;;;;;;;;;;;;;;AAkBT,SAAgB,mBACd,MACA,SAC4E;CAC5E,MAAM,EAAE,YAAY,eAAe;AAGnC,KAAI,WAAW,OAAO,QAAQ,aAAa,YAAY,QAAQ,aAAa,MAAM;EAKhF,MAAM,gBAJiB,QAAQ,SAIM;AACrC,MAAI,cACF,QAAO;;CAKX,MAAM,aAAa,QAAQ;AAG3B,KAAI,cAAc,OAAO,eAAe,WACtC,QAAO;CAIT,MAAM,gBAAgB,QAAQ;AAG9B,KAAI,iBAAiB,OAAO,kBAAkB,WAC5C,QAAO;AAIT,QAAO;;;;;;AAWT,SAAS,cAAc,EAAE,UAAU,aAA8C;AAC/E,QAAO,oBAAC;EAAe;EAAY;GAAe;;;;;AAMpD,SAAS,gBAA6B;AACpC,QAAO;;;;;AAMT,SAAS,sBAAsB,EAAE,SAAiE;AAChG,QACE,qBAAC;EACC,OAAO;GACL,OAAO;GACP,SAAS;GACT,QAAQ;GACR,cAAc;GACd,UAAU;GACV,YAAY;GACZ,iBAAiB;GAClB;;GACF;GACoB,oBAAC,sBAAQ,MAAM,OAAc;;GAAU,MAAM;GAAK;;GACjE;;;;;;;;;;;;;;;;;;;;;;;;;;ACnOV,SAAgB,GAAG,GAAG,QAA8B;AAClD,QAAO,QAAQ,KAAK,OAAO,CAAC;;;;;;AAO9B,SAAgB,aAAa,GAAY,GAAqB;AAC5D,KAAI,OAAO,GAAG,GAAG,EAAE,CAAE,QAAO;AAC5B,KACE,OAAO,MAAM,YACb,OAAO,MAAM,YACb,MAAM,QACN,MAAM,KAEN,QAAO;AAGT,KAAI,MAAM,QAAQ,EAAE,IAAI,MAAM,QAAQ,EAAE,EAAE;AACxC,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,OAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,IAC5B,KAAI,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,GAAG,CAAE,QAAO;AAErC,SAAO;;CAGT,MAAM,QAAQ,OAAO,KAAK,EAAE;CAC5B,MAAM,QAAQ,OAAO,KAAK,EAAE;AAC5B,KAAI,MAAM,WAAW,MAAM,OAAQ,QAAO;AAE1C,MAAK,MAAM,OAAO,MAChB,KACE,CAAC,OAAO,UAAU,eAAe,KAAK,GAAG,IAAI,IAC7C,CAAC,OAAO,GACL,EAA8B,MAC9B,EAA8B,KAChC,CAED,QAAO;AAGX,QAAO;;;;;;;;;ACnCT,SAASA,iBAAe,KAA8B,MAAuB;CAC3E,MAAM,QAAQ,KAAK,MAAM,IAAI;CAC7B,IAAI,UAAmB;AACvB,MAAK,MAAM,QAAQ,OAAO;AACxB,MAAI,WAAW,QAAQ,OAAO,YAAY,SAAU,QAAO;AAC3D,MAAI,MAAM,QAAQ,QAAQ,EAAE;GAC1B,MAAM,QAAQ,OAAO,KAAK;AAC1B,OAAI,OAAO,MAAM,MAAM,CAAE,QAAO;AAChC,aAAU,QAAQ;QAElB,WAAW,QAAoC;;AAGnD,QAAO;;;;;;;;AAST,SAAS,aACP,MACA,YACS;CACT,MAAM,YAAY,KAAK;CACvB,MAAM,MAAM;CAGZ,MAAM,QAAQ,aAAa,MACvB,IAAI,aACJA,iBAAe,KAAK,UAAU;AAElC,SAAQ,KAAK,UAAb;EACE,KAAK,MACH,QAAO,UAAU,KAAK;EACxB,KAAK,MACH,QAAO,UAAU,KAAK;EACxB,KAAK,KACH,QAAO,MAAM,QAAQ,KAAK,MAAM,IAAI,KAAK,MAAM,SAAS,MAAM;EAChE,KAAK,SACH,QAAO,MAAM,QAAQ,KAAK,MAAM,IAAI,CAAC,KAAK,MAAM,SAAS,MAAM;EACjE,KAAK,SACH,QAAO,QAAQ,MAAM;EACvB,KAAK,QACH,QAAO,CAAC;EACV,QACE,QAAO;;;;;;AAOb,SAAS,kBACP,WAC4C;AAC5C,QACE,OAAO,cAAc,YACrB,CAAC,MAAM,QAAQ,UAAU,IACzB,WAAW;;;;;AAOf,SAAS,QACP,WAC+D;AAC/D,KAAI,kBAAkB,UAAU,CAC9B,QAAO;EAAE,OAAO,UAAU;EAAO,OAAO,UAAU,SAAS;EAAO;AAGpE,QAAO;EAAE,OADK,MAAM,QAAQ,UAAU,GAAG,YAAY,CAAC,UAAU;EAChD,OAAO;EAAO;;;;;;;;;;AAehC,SAAgB,kBAGd,WACA,YACS;AACT,KAAI,CAAC,UAAW,QAAO;AAEvB,KAAI,OAAO,cAAc,WACvB,QAAO,UAAU,WAAW;CAG9B,MAAM,EAAE,OAAO,UAAU,QAAQ,UAAU;CAC3C,MAAM,UAAU,SACd,aAAa,MAAM,WAAW;AAEhC,QAAO,UAAU,OAAO,MAAM,KAAK,OAAO,GAAG,MAAM,MAAM,OAAO;;;;;;AAOlE,SAAgB,kBAEd,WAA8C;AAC9C,KAAI,CAAC,aAAa,OAAO,cAAc,WAAY,QAAO,EAAE;CAE5D,MAAM,EAAE,UAAU,QAAQ,UAAU;AACpC,QAAO,MAAM,KAAK,MAAM,EAAE,MAAgB;;;;;AAM5C,SAAgB,aACd,QAC0B;AAC1B,QAAO;;;;;AAMT,SAAgB,YACd,OACyB;AACzB,QAAO;;;;;AAMT,SAAgB,cACd,SACuB;AACvB,QAAO;;;;;;;;;;;;AAaT,SAAgB,qBAEd,QAAyD;CACzD,MAAM,WAAoC,EAAE;AAE5C,MAAK,MAAM,WAAW,OAAO,UAAU;EACrC,MAAM,SAAS,QAAQ,YAAY,GAAG,QAAQ,UAAU,KAAK;AAC7D,MAAI,CAAC,QAAQ,OAAQ;AAErB,OAAK,MAAM,SAAS,QAAQ,QAAQ;AAClC,OAAI,MAAM,iBAAiB,OACzB,UAAS,GAAG,SAAS,MAAM,UAAoB,MAAM;AAGvD,OAAI,MAAM,cAAc,MAAM,SAAS,SACrC;SAAK,MAAM,OAAO,MAAM,WACtB,KAAI,IAAI,iBAAiB,OACvB,UACE,GAAG,SAAS,MAAM,KAAe,GAAG,IAAI,UACtC,IAAI;;;;AAOlB,QAAO;;;;;;;;;;;;;;;;;AAkBT,SAAgB,qBAEd,OAAiD;CACjD,MAAM,QAAyB,EAAE;AAEjC,KAAI,MAAM,SACR,OAAM,WAAW,GAAG,MAAM,SAAU,MAAM,KAAgB;AAE5D,KAAI,MAAM,cAAc,OACtB,OAAM,YAAY;EAChB,OAAO,MAAM;EACb,SAAS,YAAY,MAAM,UAAU;EACtC;AAEH,KAAI,MAAM,cAAc,OACtB,OAAM,YAAY;EAChB,OAAO,MAAM;EACb,SAAS,WAAW,MAAM,UAAU;EACrC;AAEH,KAAI,MAAM,QAAQ,OAChB,OAAM,MAAM;EACV,OAAO,MAAM;EACb,SAAS,oBAAoB,MAAM;EACpC;AAEH,KAAI,MAAM,QAAQ,OAChB,OAAM,MAAM;EACV,OAAO,MAAM;EACb,SAAS,mBAAmB,MAAM;EACnC;AAEH,KAAI,MAAM,QACR,OAAM,UAAU;EACd,OAAO,IAAI,OAAO,MAAM,QAAQ;EAChC,SAAS;EACV;AAEH,KAAI,MAAM,SACR,OAAM,WAAW,MAAM;AAGzB,QAAO;;;;;;AChPT,SAAS,UAAU,MAAsB;AACvC,QAAO,iBAAiB,KAAK,QAAQ,WAAW,IAAI;;;;;;AAOtD,SAAS,eACP,KACA,MACS;CACT,MAAM,QAAQ,KAAK,MAAM,IAAI;CAC7B,IAAI,UAAmB;AACvB,MAAK,MAAM,QAAQ,OAAO;AACxB,MAAI,WAAW,QAAQ,OAAO,YAAY,SAAU,QAAO;AAC3D,MAAI,MAAM,QAAQ,QAAQ,EAAE;GAC1B,MAAM,QAAQ,OAAO,KAAK;AAC1B,OAAI,OAAO,MAAM,MAAM,CAAE,QAAO;AAChC,aAAU,QAAQ;QAElB,WAAW,QAAoC;;AAGnD,QAAO;;;;;;AAOT,SAAS,eACP,QACA,MACwB;CACxB,MAAM,SAAS,eAAe,QAAQ,KAAK;AAE3C,KAAI,UAAU,OAAO,WAAW,YAAY,aAAa,OACvD,QAAO;;;;;;AASX,SAAS,aACP,QACA,WAC2B;AAC3B,QAAO,OAAO,KAAK,OAAO;EACxB,GAAG;EACH,MAAM,GAAG,UAAU,GAAG,EAAE;EACxB,YAAY,EAAE,YAAY,KAAK,OAAO;GACpC,GAAG;GACH,MAAM,GAAG,UAAU,GAAG,EAAE,KAAe,GAAG,EAAE;GAC7C,EAAE;EACJ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCL,SAAgB,cAA8D,EAC5E,QACA,SACA,WAAW,OACX,SACA,WACA,OACgD;CAEhD,MAAM,cAAc,gBAA8B;CAClD,MAAM,gBAAgB,WAAW,aAAa;AAE9C,KAAI,CAAC,eAAe;AAClB,UAAQ,KACN,0FACD;AACD,SAAO;;AAIT,KAAI,CAAC,QAAQ,YAAY,OAAO,SAAS,WAAW,EAClD,QAAO;AAGT,QACE,oBAAC;EACM;EACL,WAAW,GACT,gBACA,WAAW,mBAAmB,WAC9B,UACD;EACD,qBAAkB;YAEjB,OAAO,SAAS,KAAK,SAAS,UAC7B,oBAAC;GAEU;GACT,SAAS;GACC;GACD;KAJJ,QAAQ,MAAM,WAAW,QAK9B,CACF;GACE;;;;;AAkBV,SAAS,gBACP,OACa;AACb,KAAI,MAAM,QAAQ,UAChB,QAAO,oBAAC,0BAAuB,GAAI,QAAS;AAE9C,QAAO,oBAAC,yBAAsB,GAAI,QAAS;;;;;;;AAQ7C,SAAS,uBAEP,OAAwD;CACxD,MAAM,sBAAsB,cACpB,kBAAkB,MAAM,QAAQ,UAAU,EAChD,CAAC,MAAM,QAAQ,UAAU,CAC1B;CAGD,MAAM,aAAa,oBAAoB,SAAS,IAC5C,SAAS;EAAE,SAAS,MAAM;EAAS,MAAM;EAAiE,CAAC,GAC3G,SAAS,EAAE,SAAS,MAAM,SAAS,CAAC;CAGxC,MAAM,gBAAgB,cAAc;AAClC,MAAI,oBAAoB,SAAS,KAAK,MAAM,QAAQ,WAAW,CAC7D,QAAO,oBAAoB,QACxB,KAAK,MAAM,OAAO;GAAE,GAAG;IAAM,OAAO,WAAW;GAAI,GACpD,EAAE,CACH;AAEH,SAAO;IACN,CAAC,qBAAqB,WAAW,CAAC;AAErC,KACE,CAAC,kBACC,MAAM,QAAQ,WACd,cACD,CAED,QAAO;AAET,QAAO,oBAAC,yBAAsB,GAAI,QAAS;;AAG7C,SAAS,sBAEP,EACA,SACA,SACA,UACA,WACkD;CAElD,MAAM,gBAAgB,QAAQ,WAAW;CACzC,MAAM,gBAAgB,mBAAmB,WAAW,cAAc;CAGlE,MAAM,iBAAiB,cAAc;AACnC,MAAI,QAAQ,aAAa,QAAQ,OAC/B,QAAO,aAAa,QAAQ,QAAQ,QAAQ,UAAU;AAExD,SAAO,QAAQ;IACd,CAAC,QAAQ,WAAW,QAAQ,OAAO,CAAC;AAEvC,QACE,oBAAC;EACC,OAAO,QAAQ;EACf,aAAa,QAAQ;EACrB,MAAM,QAAQ;EACd,SAAS;EACT,WAAW,QAAQ;EACnB,aAAa,QAAQ;EACrB,kBAAkB,QAAQ;YAEzB,QAAQ,SAEP,QAAQ,OAAO;GAAE;GAAS;GAAU;GAAS,CAAC,GAG9C,oBAAC;GACC,QAAQ;GACR,MAAM,QAAQ;GACd,KAAK,QAAQ;GACJ;GACC;GACV,SAAS;IACT;GAEU;;;;;AAoBpB,SAAS,aAA6D,EACpE,QACA,OAAO,GACP,KACA,SACA,UACA,WAC+C;CAC/C,MAAM,aAAa,mBAAmB,QAAQ,QAAQ;AAEtD,KAAI,CAAC,UAAU,OAAO,WAAW,EAC/B,QAAO;AAGT,QACE,oBAAC;EAAiB;EAAW;YAC1B,OAAO,KAAK,OAAO,UAClB,oBAAC;GAEQ;GACE;GACC;GACD;KAJJ,MAAM,QAAQ,SAAS,QAK5B,CACF;GACS;;;;;;;AAoBjB,SAAS,aACP,OACa;AACb,KAAI,MAAM,MAAM,aAAa,MAAM,MAAM,YACvC,QAAO,oBAAC,uBAAoB,GAAI,QAAS;AAE3C,QAAO,oBAAC,sBAAmB,GAAI,QAAS;;;;;;;AAQ1C,SAAS,oBAAoE,EAC3E,OACA,SACA,UACA,WAC+C;CAE/C,MAAM,iBAAiB,cACf,kBAAkB,MAAM,UAAU,EACxC,CAAC,MAAM,UAAU,CAClB;CACD,MAAM,qBAAqB,cAAc;AACvC,MAAI,MAAM,QAAQ,MAAM,WAAW,CAAE,QAAO,MAAM;AAClD,MAAI,MAAM,WAAY,QAAO,CAAC,MAAM,WAAqB;AACzD,SAAO,EAAE;IACR,CAAC,MAAM,WAAW,CAAC;CAGtB,MAAM,mBAAmB,OAAiB,EAAE,CAAC;CAC7C,MAAM,gBAAgB,cAAc;EAClC,MAAM,OAAO,MAAM,KACjB,IAAI,IAAI,CAAC,GAAG,oBAAoB,GAAG,eAAe,CAAC,CACpD;AAED,MACE,KAAK,WAAW,iBAAiB,QAAQ,UACzC,KAAK,OAAO,GAAG,MAAM,MAAM,iBAAiB,QAAQ,GAAG,CAEvD,QAAO,iBAAiB;AAE1B,mBAAiB,UAAU;AAC3B,SAAO;IACN,CAAC,oBAAoB,eAAe,CAAC;CAKxC,MAAM,aAAa,cAAc,SAAS,IACtC,SAAS;EAAE;EAAS,MAAM;EAA2D,CAAC,GACtF,SAAS,EAAE,SAAS,CAAC;CAGzB,MAAM,iBAAiB,OAAO,WAAW;CACzC,MAAM,gBAAgB,cAAc;AAClC,MAAI,aAAa,eAAe,SAAS,WAAW,CAClD,QAAO,eAAe;AAExB,iBAAe,UAAU;AACzB,SAAO;IACN,CAAC,WAAW,CAAC;CAGhB,MAAM,gBAAgB,cAAc;AAClC,MAAI,cAAc,SAAS,KAAK,MAAM,QAAQ,cAAc,CAC1D,QAAO,cAAc,QAClB,KAAK,MAAM,OAAO;GAAE,GAAG;IAAM,OAAO,cAAc;GAAI,GACvD,EAAE,CACH;AAEH,SAAO;IACN,CAAC,eAAe,cAAc,CAAC;CAElC,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM,WAAW,EAAE,CAAC;CAC3D,MAAM,CAAC,WAAW,gBAAgB,SAAS,MAAM;CAEjD,MAAM,aAAa,OAA6C,KAAK;AAErE,iBAAgB;AACd,MAAI,CAAC,MAAM,YAAa;EAExB,IAAI,WAAW;EAEf,MAAM,oBAAoB;GACxB,MAAM,MAAM,MAAM,YAChB,cACD;AACD,OAAI,eAAe,SAAS;AAC1B,iBAAa,KAAK;AAClB,QACG,MAAM,eAAe;AACpB,SAAI,SAAU,YAAW,WAAW;MACpC,CACD,OAAO,QAAiB;AACvB,SAAI,SACF,KAAI,MAAM,YACR,OAAM,YAAY,IAAI;SAEtB,SAAQ,MAAM,gCAAgC,IAAI;MAGtD,CACD,cAAc;AACb,SAAI,SAAU,cAAa,MAAM;MACjC;UACC;AACL,eAAW,IAAI;AACf,iBAAa,MAAM;;;AAIvB,MAAI,MAAM,cAAc,MAAM,aAAa,GAAG;AAC5C,OAAI,WAAW,QAAS,cAAa,WAAW,QAAQ;AACxD,cAAW,UAAU,WAAW,aAAa,MAAM,WAAW;QAE9D,cAAa;AAGf,eAAa;AACX,cAAW;AACX,OAAI,WAAW,QAAS,cAAa,WAAW,QAAQ;;IAEzD;EAAC;EAAe,MAAM;EAAa,MAAM;EAAY,MAAM;EAAY,CAAC;CAI3E,MAAM,eAAe,MAAM,cAAc,YAAY;CACrD,MAAM,eAAe,eAAwC;EAC3D,GAAG;EACH,SAAS,MAAM,cAAc,UAAU,MAAM;EAC7C,WAAW;EACZ,GAA8B;EAAC;EAAO;EAAS;EAAa,CAAC;AAG9D,KACE,CAAC,kBACC,MAAM,WACN,cACD,CAED,QAAO;AAGT,QACE,oBAAC;EACC,OAAO;EACE;EACC;EACD;EACT,WAAW;GACX;;;;;;;AAkBN,SAAS,mBAAmE,EAC1E,OACA,SACA,UACA,SACA,aACqD;CAErD,MAAM,EAAE,eAAe,eAAe;CACtC,MAAM,YAAY,MAAM;CACxB,MAAM,EAAE,QAAQ,aAAa,kBAAkB,aAAa;EAC1D;EACA,MAAM;EACP,CAAC;CAGF,MAAM,aAAa,YAAY,MAAM;CACrC,MAAM,UAAU,UAAU,UAAU;CACpC,MAAM,aAAa,eACjB,QACA,UACD;CACD,MAAM,UAAU,QACd,eAAe,aAAwC,UAAU,CAClE;CACD,MAAM,YAAY,QAChB,eAAe,eAA0C,UAAU,CACpE;CACD,MAAM,aAAa,eACV;EACL,SAAS,CAAC,CAAC;EACX;EACA;EACA,cAAc;EACd,OAAO;EACR,GACD;EAAC;EAAY;EAAS;EAAU,CACjC;CACD,MAAM,gBAAgB,MAAM,WAAW;AAGvC,KAAI,MAAM,OACR,QACE,oBAAC;EACC,WAAW,GACT,iBACA,MAAM,aAAa,iBACnB,MAAM,UACP;EACD,IAAI;EACJ,sBAAoB;EACpB,mBAAiB,MAAM;YAEtB,MAAM,OAAO;GACZ,GAAG;GACH;GACS;GACT,UAAU;GACV,SAAS;GACT,OAAO;GACP;GACA;GACA;GACD,CAAsC;GACnC;AAcV,KACE,CAT2B,QAC3B,WAAW,MAAM,SACd,iBACC,WAAW,kBACX,OAAO,WAAW,mBAAmB,YACpC,WAAW,eAA2C,MAAM,MAClE,IAIC,MAAM,cACN,MAAM,WAAW,SAAS,GAC1B;AACA,MAAI,MAAM,SAAS,QACjB,QACE,oBAAC;GACQ;GACE;GACT,UAAU;GACV,SAAS;IACT;AAKN,SACE,oBAAC;GACC,WAAW,GACT,uBACA,MAAM,aAAa,iBACnB,MAAM,UACP;GACD,sBAAoB;GACpB,mBAAiB,MAAM;aAEvB,oBAAC;IACC,QAAQ,MAAM;IACL;IACT,UAAU;IACV,SAAS;KACT;IACE;;CAIV,MAAM,iBAAiB,kBAAkB,MAAM,MAAM,cAAc;AAEnE,KAAI,CAAC,eACH,QAAO;AAGT,QACE,oBAAC;EACC,WAAW,GACT,iBACA,MAAM,aAAa,iBACnB,MAAM,UACP;EACD,IAAI;EACJ,sBAAoB;EACpB,mBAAiB,MAAM;YAEvB,oBAAC;GACC,GAAK;GACE;GACE;GACT,UAAU;GACV,SAAS;GACT,OAAO;GACK;GACH;GACE;IACX;GACE;;AAQV,SAAS,mBAAmE,EAC1E,OACA,SACA,UACA,WAC+C;CAC/C,MAAM,EAAE,QAAQ,QAAQ,WAAW,cAAc;EAC/C;EACA,MAAM,MAAM;EACb,CAAC;AAEF,QACE,qBAAC;EACC,WAAW,GACT,2CACA,MAAM,aAAa,iBACnB,MAAM,UACP;EACD,sBAAoB,MAAM;EAC1B,mBAAgB;;GAEhB,oBAAC;IAAI,WAAU;cACZ,MAAM,SACL,oBAAC;KAAM,WAAU;eAAiB,MAAM;MAAc;KAEpD;GAEL,OAAO,KAAK,MAAM,UACjB,qBAAC;IAEC,WAAU;eAEV,oBAAC;KACC,QACE,MAAM,YAAY,KAAK,OAAO;MAC5B,GAAG;MACH,MAAM,GAAG,MAAM,KAAe,GAAG,MAAM,GAAG,EAAE;MAC7C,EAAE;KAEI;KACC;KACD;MACT,EACF,oBAAC;KACC,MAAK;KACL,eAAe,OAAO,MAAM;KAC5B,WAAU;eACX;MAEQ;MApBJ,KAAK,GAqBN,CACN;GACF,oBAAC;IACC,MAAK;IACL,eAAe,OAAO,EAAE,CAAyE;IACvF;IACV,WAAU;cACX;KAEQ;;GACL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3oBV,MAAa,QAAQ;CAInB,OACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,QACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,aAAa;EACb,GAAG;EACJ;CAKD,MACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,aAAa;EACb,GAAG;EACJ;CAKD,MACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,aAAa;EACb,GAAG;EACJ;CAKD,WACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,SACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,KAAK;EACL,GAAG;EACJ;CAKD,WACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,MAAM;EACN,GAAG;EACJ;CAKD,SACE,MACA,OACA,SACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA;EACA,GAAG;EACJ;CAKD,WACE,MACA,OACA,SACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA;EACA,GAAG;EACJ;CAKD,cACE,MACA,OACA,SACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA;EACA,aAAa;EACb,GAAG;EACJ;CAKD,kBACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,SACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,UACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,WACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,QACE,MACA,OACA,SACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA;EACA,GAAG;EACJ;CAKD,OACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,OACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,aAAa;EACb,GAAG;EACJ;CAKD,OACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,aAAa;EACb,GAAG;EACJ;CAKD,OACE,MACA,OACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA,GAAG;EACJ;CAKD,SACE,MACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA,GAAG;EACJ;CAeD,QACE,MACA,OACA,YACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA;EACA,GAAG;EACJ;CAcD,QACE,MACA,OACA,YACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACA;EACA,GAAG;EACJ;CAaD,SACE,MACA,OACA,QACA,QAAoB,EAAE,MACP;EACf,MAAM;EACN;EACA;EACQ;EACR,GAAG;EACJ;CACF;;;;;;;;;;;;;;;;;AAsBD,SAAgB,QACd,IACA,OACA,QACA,QAAoC,EAAE,EACf;CACvB,MAAM,EAAE,OAAO,GAAG,GAAG,SAAS;AAC9B,QAAO;EACL;EACA;EACA;EACA;EACA,GAAG;EACJ;;;;;;AAOH,SAAgB,gBACd,QACA,QAAqD,EAAE,EAChC;CACvB,MAAM,EAAE,OAAO,GAAG,GAAG,SAAS;AAC9B,QAAO;EACL;EACA;EACA,SAAS;EACT,GAAG;EACJ;;;;;;;;;;;;;;;;;;;;;;;;AC9aH,SAAgB,WACd,SACgC;CAChC,MAAM,EAAE,QAAQ,UAAU,SAAS,WAAW,eAAe,GAAG,gBAC9D;CAIF,MAAM,iBAAiB;EACrB,GAFqB,qBAAqB,OAAO;EAGjD,GAAI,OAAO,kBAAkB,YAAY,kBAAkB,OACvD,gBACA,EAAE;EACP;CAED,MAAM,OAAO,QAAsB;EACjC,GAAG;EACH,eAAe;EAChB,CAAC;CAEF,MAAM,iBAAiB,eACd;EACL;EACA,SAAS,KAAK;EACd;EACA;EACA;EACD,GACD;EAAC;EAAQ,KAAK;EAAS;EAAU;EAAS;EAAU,CACrD;AAMD,QAAO,OAAO,OAAO,MAAM,EAAE,gBAAgB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/formkit",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Headless, type-safe form generation engine for React 19. Schema-driven with full TypeScript support.",
5
5
  "author": "Classytic",
6
6
  "license": "MIT",