@classytic/formkit 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ 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.4.0] - 2026-05-26
9
+
10
+ ### Added
11
+
12
+ - New schema helpers exported from `./schema`: `extractDefaultValuesAsync`, field-type predicates (`isChoiceField`, `isTextField`, `isNumericField`, `isDateField`, `isContainerField`, `isArrayField`, `isDynamicField`, `isConditionalField`), schema composition (`mergeSchemas`, `extendSection`, `pickFields`, `omitFields`, `flattenSchema`), and `applyServerErrors`.
13
+ - New exported types: `SectionRendererProps`, `GridRendererProps`, `FieldWrapperProps`, `ValidationRuleObject`, `PatternRuleObject`.
14
+ - Conditional package exports add `module-sync` condition for better React Server Components / sync-import interop.
15
+
16
+ ### Changed
17
+
18
+ - `main` / `module` fields removed from `package.json` in favor of pure conditional `exports`.
19
+
8
20
  ## [1.3.0] - 2026-02-27
9
21
 
10
22
  ### Added
package/README.md CHANGED
@@ -20,7 +20,7 @@ Headless, type-safe form generation engine for React 19. Schema-driven with full
20
20
  - **Responsive layouts** - Multi-column grid layouts
21
21
  - **Accessibility** - Auto-generated `fieldId`, `error`, and `fieldState` props
22
22
  - **Validation helpers** - `buildValidationRules` generates RHF rules from schema props
23
- - **Lightweight** - ~7KB gzipped, tree-shakeable
23
+ - **Lightweight** - ~12KB gzipped (peer deps excluded), tree-shakeable
24
24
 
25
25
  ## Requirements
26
26
 
@@ -54,28 +54,41 @@ import { Label } from "@/components/ui/label";
54
54
 
55
55
  export function FormInput({
56
56
  control,
57
- field,
57
+ name,
58
+ rules, // pre-computed RHF rules from schema (required, minLength, pattern, validate…)
58
59
  label,
59
60
  placeholder,
60
61
  required,
62
+ fieldId, // use as id on <input> and htmlFor on <Label>
63
+ errorId, // use as id on error <p> and aria-errormessage on <input>
64
+ shouldShowError, // true only after touch/submit — mirrors :user-invalid timing
61
65
  error,
62
- fieldId,
63
66
  }: FieldComponentProps) {
64
67
  return (
65
68
  <Controller
66
- name={field.name}
69
+ name={name}
67
70
  control={control}
68
- render={({ field: rhfField }) => (
71
+ rules={rules}
72
+ render={({ field }) => (
69
73
  <div className="space-y-2">
70
74
  {label && (
71
75
  <Label htmlFor={fieldId}>
72
76
  {label}
73
- {required && <span className="text-red-500 ml-1">*</span>}
77
+ {required && <span aria-hidden="true" className="text-red-500 ml-1">*</span>}
74
78
  </Label>
75
79
  )}
76
- <Input {...rhfField} id={fieldId} placeholder={placeholder} />
77
- {error && (
78
- <p className="text-sm text-red-500">{error.message}</p>
80
+ <Input
81
+ {...field}
82
+ id={fieldId}
83
+ placeholder={placeholder}
84
+ aria-required={required || undefined}
85
+ aria-invalid={shouldShowError || undefined}
86
+ aria-errormessage={shouldShowError ? errorId : undefined}
87
+ />
88
+ {shouldShowError && (
89
+ <p id={errorId} role="alert" className="text-sm text-red-500">
90
+ {error?.message}
91
+ </p>
79
92
  )}
80
93
  </div>
81
94
  )}
@@ -277,7 +290,11 @@ interface Section<T> {
277
290
 
278
291
  ```ts
279
292
  interface BaseField<T> {
280
- name: string; // Field name (required)
293
+ // name accepts Path<T> or any string.
294
+ // Use field.for<T>() builders for call-site enforcement of valid paths.
295
+ // Relative names are correct for nameSpace sections and itemFields children —
296
+ // FormGenerator prefixes them at render time (e.g. "street" → "address.street").
297
+ name: Path<T> | string; // Field name (required)
281
298
  type: FieldType; // Field type (required)
282
299
  label?: string; // Field label
283
300
  placeholder?: string; // Placeholder text
@@ -298,8 +315,10 @@ interface BaseField<T> {
298
315
  loadOptions?: (formValues: Partial<T>) => Promise<FieldOption[]> | FieldOption[];
299
316
  debounceMs?: number;
300
317
 
301
- // For array/grouped types
302
- itemFields?: BaseField<T>[];
318
+ // Sub-fields for group and array types.
319
+ // Children use relative names ("street") — FormGenerator prefixes with parent name.
320
+ // Intentionally untyped to T because they resolve at render time, not authoring time.
321
+ itemFields?: BaseField[];
303
322
 
304
323
  // For select/radio/checkbox
305
324
  options?: FieldOption[];