@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 +11 -1
- package/README.md +96 -55
- package/dist/index.d.mts +4 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +14 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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.
|
|
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
|
-
{
|
|
158
|
-
|
|
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
|
-
{
|
|
165
|
-
|
|
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
|
|
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,
|
|
202
|
-
variant: "compact",
|
|
203
|
-
className: "my-form",
|
|
204
|
-
mode: "onBlur",
|
|
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}
|
|
224
|
-
control={form.control}
|
|
225
|
-
disabled={false}
|
|
226
|
-
variant="default"
|
|
227
|
-
className="my-form"
|
|
228
|
-
ref={formRef}
|
|
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;
|
|
245
|
-
title?: string;
|
|
246
|
-
description?: string;
|
|
247
|
-
icon?: ReactNode;
|
|
248
|
-
fields?: BaseField<T>[];
|
|
249
|
-
cols?: number;
|
|
250
|
-
gap?: number;
|
|
251
|
-
variant?: string;
|
|
252
|
-
className?: string;
|
|
253
|
-
collapsible?: boolean;
|
|
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;
|
|
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;
|
|
270
|
-
type: FieldType;
|
|
271
|
-
label?: string;
|
|
272
|
-
placeholder?: string;
|
|
273
|
-
helperText?: string;
|
|
274
|
-
disabled?: boolean;
|
|
275
|
-
required?: boolean;
|
|
276
|
-
readOnly?: boolean;
|
|
277
|
-
variant?: string;
|
|
278
|
-
fullWidth?: boolean;
|
|
279
|
-
className?: string;
|
|
280
|
-
defaultValue?: unknown;
|
|
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[];
|
|
317
|
+
watchNames?: string | string[]; // Optimize useWatch performance
|
|
285
318
|
|
|
286
319
|
// Dynamic options loading
|
|
287
|
-
loadOptions?: (
|
|
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<
|
|
323
|
-
extends
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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;
|
|
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 {
|
|
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<
|
|
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<
|
|
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 */
|
package/dist/index.d.mts.map
CHANGED
|
@@ -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":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1023,16 +1023,20 @@ function useFormKit(options) {
|
|
|
1023
1023
|
...formOptions,
|
|
1024
1024
|
defaultValues: mergedDefaults
|
|
1025
1025
|
});
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
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
|
package/dist/index.mjs.map
CHANGED
|
@@ -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":"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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;;;;;;;;;;;;;;;;;;;;;;;;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