@classytic/formkit 1.3.0 → 1.3.1
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/dist/index.d.mts +1 -21
- package/dist/index.mjs +84 -72
- package/dist/server.d.mts +0 -20
- package/dist/server.mjs +14 -36
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -761,10 +761,6 @@ declare const field: {
|
|
|
761
761
|
* Multi-select field (tag choice).
|
|
762
762
|
*/
|
|
763
763
|
multiselect: (name: string, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps) => BaseField;
|
|
764
|
-
/**
|
|
765
|
-
* Tag choice field for selecting options as tags/chips.
|
|
766
|
-
*/
|
|
767
|
-
tagChoice: (name: string, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps) => BaseField;
|
|
768
764
|
/**
|
|
769
765
|
* Dependent select field that reacts to parent field changes.
|
|
770
766
|
*/
|
|
@@ -801,22 +797,6 @@ declare const field: {
|
|
|
801
797
|
* File upload field.
|
|
802
798
|
*/
|
|
803
799
|
file: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
804
|
-
/**
|
|
805
|
-
* OTP/PIN input field.
|
|
806
|
-
*/
|
|
807
|
-
otp: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
808
|
-
/**
|
|
809
|
-
* Async searchable combobox with server-side search.
|
|
810
|
-
*/
|
|
811
|
-
asyncCombobox: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
812
|
-
/**
|
|
813
|
-
* Async searchable multi-select with server-side search.
|
|
814
|
-
*/
|
|
815
|
-
asyncMultiselect: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
816
|
-
/**
|
|
817
|
-
* Date and optional time picker field.
|
|
818
|
-
*/
|
|
819
|
-
dateTime: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
820
800
|
/**
|
|
821
801
|
* Hidden field (no UI).
|
|
822
802
|
*/
|
|
@@ -930,4 +910,4 @@ interface UseFormKitReturn<TFieldValues extends FieldValues = FieldValues> exten
|
|
|
930
910
|
*/
|
|
931
911
|
declare function useFormKit<TFieldValues extends FieldValues = FieldValues>(options: UseFormKitOptions<TFieldValues>): UseFormKitReturn<TFieldValues>;
|
|
932
912
|
//#endregion
|
|
933
|
-
export { type BaseField, type ClassValue, type ComponentRegistry, type Condition, type ConditionConfig, type ConditionRule, type DefaultLayoutProps, type DefineField, type FieldComponent, type FieldComponentProps, type FieldOption, type FieldOptionGroup, type FieldType, FieldWrapper, type FormElement, FormGenerator, type FormGeneratorProps, type FormSchema, type FormSystemContextValue, FormSystemProvider, type FormSystemProviderProps, type GridLayoutProps, GridRenderer, type InferSchemaValues, type LayoutComponent, type LayoutComponentProps, type LayoutRegistry, type LayoutType, type SchemaFieldNames, type Section, type SectionLayoutProps, type SectionRenderProps, SectionRenderer, type UseFormKitOptions, type UseFormKitReturn, type ValidationRules, type Variant, buildValidationRules, cn, defineField, defineSchema, defineSection, evaluateCondition, extractDefaultValues, extractWatchNames, field, section, sectionUntitled, shallowEqual, useFieldComponent, useFormKit, useFormSystem, useLayoutComponent };
|
|
913
|
+
export { type BaseField, type ClassValue, type ComponentRegistry, type Condition, type ConditionConfig, type ConditionRule, type DefaultLayoutProps, type DefineField, type FieldComponent, type FieldComponentProps, type FieldOption, type FieldOptionGroup, type FieldType, FieldWrapper, type FieldWrapperProps, type FormElement, FormGenerator, type FormGeneratorProps, type FormSchema, type FormSystemContextValue, FormSystemProvider, type FormSystemProviderProps, type GridLayoutProps, GridRenderer, type GridRendererProps, type InferSchemaValues, type LayoutComponent, type LayoutComponentProps, type LayoutRegistry, type LayoutType, type SchemaFieldNames, type Section, type SectionLayoutProps, type SectionRenderProps, SectionRenderer, type SectionRendererProps, type UseFormKitOptions, type UseFormKitReturn, type ValidationRules, type Variant, buildValidationRules, cn, defineField, defineSchema, defineSection, evaluateCondition, extractDefaultValues, extractWatchNames, field, section, sectionUntitled, shallowEqual, useFieldComponent, useFormKit, useFormSystem, useLayoutComponent };
|
package/dist/index.mjs
CHANGED
|
@@ -279,7 +279,12 @@ function toRules(condition) {
|
|
|
279
279
|
*/
|
|
280
280
|
function evaluateCondition(condition, formValues) {
|
|
281
281
|
if (!condition) return true;
|
|
282
|
-
if (typeof condition === "function")
|
|
282
|
+
if (typeof condition === "function") try {
|
|
283
|
+
return condition(formValues);
|
|
284
|
+
} catch (err) {
|
|
285
|
+
console.warn("[FormKit] Condition function threw:", err);
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
283
288
|
const { rules, logic } = toRules(condition);
|
|
284
289
|
const evalFn = (rule) => evaluateRule(rule, formValues);
|
|
285
290
|
return logic === "or" ? rules.some(evalFn) : rules.every(evalFn);
|
|
@@ -369,10 +374,14 @@ function buildValidationRules(field) {
|
|
|
369
374
|
value: field.max,
|
|
370
375
|
message: `Must be at most ${field.max}`
|
|
371
376
|
};
|
|
372
|
-
if (field.pattern)
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
377
|
+
if (field.pattern) try {
|
|
378
|
+
rules.pattern = {
|
|
379
|
+
value: new RegExp(field.pattern),
|
|
380
|
+
message: "Invalid format"
|
|
381
|
+
};
|
|
382
|
+
} catch {
|
|
383
|
+
console.warn(`[FormKit] Invalid regex pattern "${field.pattern}" in field "${field.name}", skipping.`);
|
|
384
|
+
}
|
|
376
385
|
if (field.validate) rules.validate = field.validate;
|
|
377
386
|
return rules;
|
|
378
387
|
}
|
|
@@ -548,8 +557,50 @@ function GridRenderer({ fields, cols = 1, gap, control, disabled, variant }) {
|
|
|
548
557
|
*/
|
|
549
558
|
function FieldWrapper(props) {
|
|
550
559
|
if (props.field.condition || props.field.loadOptions) return /* @__PURE__ */ jsx(DynamicFieldWrapper, { ...props });
|
|
560
|
+
if (props.field.render) return /* @__PURE__ */ jsx(RenderedFieldWrapper, { ...props });
|
|
551
561
|
return /* @__PURE__ */ jsx(StaticFieldWrapper, { ...props });
|
|
552
562
|
}
|
|
563
|
+
function RenderedFieldWrapper({ field, control, disabled, variant }) {
|
|
564
|
+
const fieldName = field.name;
|
|
565
|
+
const fieldId = toFieldId(fieldName);
|
|
566
|
+
const activeVariant = field.variant ?? variant;
|
|
567
|
+
const isDisabled = disabled || field.disabled;
|
|
568
|
+
const { errors, dirtyFields, touchedFields } = useFormState({
|
|
569
|
+
control,
|
|
570
|
+
name: fieldName
|
|
571
|
+
});
|
|
572
|
+
const fieldError = getNestedError(errors, fieldName);
|
|
573
|
+
const isDirty = Boolean(getNestedValue(dirtyFields, fieldName));
|
|
574
|
+
const isTouched = Boolean(getNestedValue(touchedFields, fieldName));
|
|
575
|
+
const fieldState = useMemo(() => ({
|
|
576
|
+
invalid: !!fieldError,
|
|
577
|
+
isDirty,
|
|
578
|
+
isTouched,
|
|
579
|
+
isValidating: false,
|
|
580
|
+
error: fieldError
|
|
581
|
+
}), [
|
|
582
|
+
fieldError,
|
|
583
|
+
isDirty,
|
|
584
|
+
isTouched
|
|
585
|
+
]);
|
|
586
|
+
return /* @__PURE__ */ jsx("div", {
|
|
587
|
+
className: cn("formkit-field", field.fullWidth && "col-span-full", field.className),
|
|
588
|
+
id: fieldId,
|
|
589
|
+
"data-formkit-field": fieldName,
|
|
590
|
+
"data-field-type": field.type,
|
|
591
|
+
children: field.render?.({
|
|
592
|
+
...field,
|
|
593
|
+
field,
|
|
594
|
+
control,
|
|
595
|
+
disabled: isDisabled,
|
|
596
|
+
variant: activeVariant,
|
|
597
|
+
error: fieldError,
|
|
598
|
+
fieldState,
|
|
599
|
+
fieldId,
|
|
600
|
+
isLoading: void 0
|
|
601
|
+
})
|
|
602
|
+
});
|
|
603
|
+
}
|
|
553
604
|
/**
|
|
554
605
|
* Dynamic Field Wrapper
|
|
555
606
|
* Conditionally calls `useWatch` to trigger re-renders only when form values change.
|
|
@@ -615,7 +666,10 @@ function DynamicFieldWrapper({ field, control, disabled, variant }) {
|
|
|
615
666
|
} else executeLoad();
|
|
616
667
|
return () => {
|
|
617
668
|
isActive = false;
|
|
618
|
-
if (timeoutRef.current)
|
|
669
|
+
if (timeoutRef.current) {
|
|
670
|
+
clearTimeout(timeoutRef.current);
|
|
671
|
+
timeoutRef.current = null;
|
|
672
|
+
}
|
|
619
673
|
};
|
|
620
674
|
}, [
|
|
621
675
|
watchedValues,
|
|
@@ -671,23 +725,6 @@ function StaticFieldWrapper({ field, control, disabled, variant, isLoading }) {
|
|
|
671
725
|
isTouched
|
|
672
726
|
]);
|
|
673
727
|
const activeVariant = field.variant ?? variant;
|
|
674
|
-
if (field.render) return /* @__PURE__ */ jsx("div", {
|
|
675
|
-
className: cn("formkit-field", field.fullWidth && "col-span-full", field.className),
|
|
676
|
-
id: fieldId,
|
|
677
|
-
"data-formkit-field": fieldName,
|
|
678
|
-
"data-field-type": field.type,
|
|
679
|
-
children: field.render({
|
|
680
|
-
...field,
|
|
681
|
-
field,
|
|
682
|
-
control,
|
|
683
|
-
disabled: isDisabled,
|
|
684
|
-
variant: activeVariant,
|
|
685
|
-
error: fieldError,
|
|
686
|
-
fieldState,
|
|
687
|
-
fieldId,
|
|
688
|
-
isLoading
|
|
689
|
-
})
|
|
690
|
-
});
|
|
691
728
|
if (!Boolean(components[field.type] || activeVariant && components[activeVariant] && typeof components[activeVariant] === "object" && components[activeVariant][field.type]) && field.itemFields && field.itemFields.length > 0) {
|
|
692
729
|
if (field.type === "array") return /* @__PURE__ */ jsx(ArrayFieldFallback, {
|
|
693
730
|
field,
|
|
@@ -708,23 +745,24 @@ function StaticFieldWrapper({ field, control, disabled, variant, isLoading }) {
|
|
|
708
745
|
});
|
|
709
746
|
}
|
|
710
747
|
const FieldComponent = useFieldComponent(field.type, activeVariant);
|
|
711
|
-
if (!FieldComponent) return null;
|
|
748
|
+
if (!FieldComponent && !field.render) return null;
|
|
749
|
+
const fieldProps = {
|
|
750
|
+
...field,
|
|
751
|
+
field,
|
|
752
|
+
control,
|
|
753
|
+
disabled: isDisabled,
|
|
754
|
+
variant: activeVariant,
|
|
755
|
+
error: fieldError,
|
|
756
|
+
fieldState,
|
|
757
|
+
fieldId,
|
|
758
|
+
isLoading
|
|
759
|
+
};
|
|
712
760
|
return /* @__PURE__ */ jsx("div", {
|
|
713
761
|
className: cn("formkit-field", field.fullWidth && "col-span-full", field.className),
|
|
714
762
|
id: fieldId,
|
|
715
763
|
"data-formkit-field": fieldName,
|
|
716
764
|
"data-field-type": field.type,
|
|
717
|
-
children: /* @__PURE__ */ jsx(FieldComponent, {
|
|
718
|
-
...field,
|
|
719
|
-
field,
|
|
720
|
-
control,
|
|
721
|
-
disabled: isDisabled,
|
|
722
|
-
variant: activeVariant,
|
|
723
|
-
error: fieldError,
|
|
724
|
-
fieldState,
|
|
725
|
-
fieldId,
|
|
726
|
-
isLoading
|
|
727
|
-
})
|
|
765
|
+
children: field.render ? field.render(fieldProps) : /* @__PURE__ */ jsx(FieldComponent, { ...fieldProps })
|
|
728
766
|
});
|
|
729
767
|
}
|
|
730
768
|
function ArrayFieldFallback({ field, control, disabled, variant }) {
|
|
@@ -763,7 +801,13 @@ function ArrayFieldFallback({ field, control, disabled, variant }) {
|
|
|
763
801
|
}, item.id)),
|
|
764
802
|
/* @__PURE__ */ jsx("button", {
|
|
765
803
|
type: "button",
|
|
766
|
-
onClick: () =>
|
|
804
|
+
onClick: () => {
|
|
805
|
+
const defaults = {};
|
|
806
|
+
if (field.itemFields) {
|
|
807
|
+
for (const f of field.itemFields) if (f.defaultValue !== void 0) defaults[f.name] = f.defaultValue;
|
|
808
|
+
}
|
|
809
|
+
append(defaults);
|
|
810
|
+
},
|
|
767
811
|
disabled,
|
|
768
812
|
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",
|
|
769
813
|
children: "+ Add Item"
|
|
@@ -868,13 +912,6 @@ const field = {
|
|
|
868
912
|
placeholder: "Select options...",
|
|
869
913
|
...props
|
|
870
914
|
}),
|
|
871
|
-
tagChoice: (name, label, options, props = {}) => ({
|
|
872
|
-
type: "tagChoice",
|
|
873
|
-
name,
|
|
874
|
-
label,
|
|
875
|
-
options,
|
|
876
|
-
...props
|
|
877
|
-
}),
|
|
878
915
|
dependentSelect: (name, label, props = {}) => ({
|
|
879
916
|
type: "dependentSelect",
|
|
880
917
|
name,
|
|
@@ -932,30 +969,6 @@ const field = {
|
|
|
932
969
|
label,
|
|
933
970
|
...props
|
|
934
971
|
}),
|
|
935
|
-
otp: (name, label, props = {}) => ({
|
|
936
|
-
type: "otp",
|
|
937
|
-
name,
|
|
938
|
-
label,
|
|
939
|
-
...props
|
|
940
|
-
}),
|
|
941
|
-
asyncCombobox: (name, label, props = {}) => ({
|
|
942
|
-
type: "asyncCombobox",
|
|
943
|
-
name,
|
|
944
|
-
label,
|
|
945
|
-
...props
|
|
946
|
-
}),
|
|
947
|
-
asyncMultiselect: (name, label, props = {}) => ({
|
|
948
|
-
type: "asyncMultiselect",
|
|
949
|
-
name,
|
|
950
|
-
label,
|
|
951
|
-
...props
|
|
952
|
-
}),
|
|
953
|
-
dateTime: (name, label, props = {}) => ({
|
|
954
|
-
type: "dateTime",
|
|
955
|
-
name,
|
|
956
|
-
label,
|
|
957
|
-
...props
|
|
958
|
-
}),
|
|
959
972
|
hidden: (name, props = {}) => ({
|
|
960
973
|
type: "hidden",
|
|
961
974
|
name,
|
|
@@ -1046,13 +1059,12 @@ function sectionUntitled(fields, props = {}) {
|
|
|
1046
1059
|
*/
|
|
1047
1060
|
function useFormKit(options) {
|
|
1048
1061
|
const { schema, disabled, variant, className, defaultValues, ...formOptions } = options;
|
|
1049
|
-
const
|
|
1050
|
-
|
|
1062
|
+
const schemaDefaults = useMemo(() => extractDefaultValues(schema), [schema]);
|
|
1063
|
+
const mergedDefaults = useMemo(() => ({
|
|
1064
|
+
...schemaDefaults,
|
|
1051
1065
|
...typeof defaultValues === "object" && defaultValues !== null ? defaultValues : {}
|
|
1052
|
-
};
|
|
1066
|
+
}), [schemaDefaults, defaultValues]);
|
|
1053
1067
|
const form = useForm({
|
|
1054
|
-
mode: "onBlur",
|
|
1055
|
-
reValidateMode: "onChange",
|
|
1056
1068
|
...formOptions,
|
|
1057
1069
|
defaultValues: mergedDefaults
|
|
1058
1070
|
});
|
package/dist/server.d.mts
CHANGED
|
@@ -518,10 +518,6 @@ declare const field: {
|
|
|
518
518
|
* Multi-select field (tag choice).
|
|
519
519
|
*/
|
|
520
520
|
multiselect: (name: string, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps) => BaseField;
|
|
521
|
-
/**
|
|
522
|
-
* Tag choice field for selecting options as tags/chips.
|
|
523
|
-
*/
|
|
524
|
-
tagChoice: (name: string, label: string, options: (FieldOption | FieldOptionGroup)[], props?: FieldProps) => BaseField;
|
|
525
521
|
/**
|
|
526
522
|
* Dependent select field that reacts to parent field changes.
|
|
527
523
|
*/
|
|
@@ -558,22 +554,6 @@ declare const field: {
|
|
|
558
554
|
* File upload field.
|
|
559
555
|
*/
|
|
560
556
|
file: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
561
|
-
/**
|
|
562
|
-
* OTP/PIN input field.
|
|
563
|
-
*/
|
|
564
|
-
otp: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
565
|
-
/**
|
|
566
|
-
* Async searchable combobox with server-side search.
|
|
567
|
-
*/
|
|
568
|
-
asyncCombobox: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
569
|
-
/**
|
|
570
|
-
* Async searchable multi-select with server-side search.
|
|
571
|
-
*/
|
|
572
|
-
asyncMultiselect: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
573
|
-
/**
|
|
574
|
-
* Date and optional time picker field.
|
|
575
|
-
*/
|
|
576
|
-
dateTime: (name: string, label: string, props?: FieldProps) => BaseField;
|
|
577
557
|
/**
|
|
578
558
|
* Hidden field (no UI).
|
|
579
559
|
*/
|
package/dist/server.mjs
CHANGED
|
@@ -95,7 +95,12 @@ function toRules(condition) {
|
|
|
95
95
|
*/
|
|
96
96
|
function evaluateCondition(condition, formValues) {
|
|
97
97
|
if (!condition) return true;
|
|
98
|
-
if (typeof condition === "function")
|
|
98
|
+
if (typeof condition === "function") try {
|
|
99
|
+
return condition(formValues);
|
|
100
|
+
} catch (err) {
|
|
101
|
+
console.warn("[FormKit] Condition function threw:", err);
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
99
104
|
const { rules, logic } = toRules(condition);
|
|
100
105
|
const evalFn = (rule) => evaluateRule(rule, formValues);
|
|
101
106
|
return logic === "or" ? rules.some(evalFn) : rules.every(evalFn);
|
|
@@ -185,10 +190,14 @@ function buildValidationRules(field) {
|
|
|
185
190
|
value: field.max,
|
|
186
191
|
message: `Must be at most ${field.max}`
|
|
187
192
|
};
|
|
188
|
-
if (field.pattern)
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
193
|
+
if (field.pattern) try {
|
|
194
|
+
rules.pattern = {
|
|
195
|
+
value: new RegExp(field.pattern),
|
|
196
|
+
message: "Invalid format"
|
|
197
|
+
};
|
|
198
|
+
} catch {
|
|
199
|
+
console.warn(`[FormKit] Invalid regex pattern "${field.pattern}" in field "${field.name}", skipping.`);
|
|
200
|
+
}
|
|
192
201
|
if (field.validate) rules.validate = field.validate;
|
|
193
202
|
return rules;
|
|
194
203
|
}
|
|
@@ -289,13 +298,6 @@ const field = {
|
|
|
289
298
|
placeholder: "Select options...",
|
|
290
299
|
...props
|
|
291
300
|
}),
|
|
292
|
-
tagChoice: (name, label, options, props = {}) => ({
|
|
293
|
-
type: "tagChoice",
|
|
294
|
-
name,
|
|
295
|
-
label,
|
|
296
|
-
options,
|
|
297
|
-
...props
|
|
298
|
-
}),
|
|
299
301
|
dependentSelect: (name, label, props = {}) => ({
|
|
300
302
|
type: "dependentSelect",
|
|
301
303
|
name,
|
|
@@ -353,30 +355,6 @@ const field = {
|
|
|
353
355
|
label,
|
|
354
356
|
...props
|
|
355
357
|
}),
|
|
356
|
-
otp: (name, label, props = {}) => ({
|
|
357
|
-
type: "otp",
|
|
358
|
-
name,
|
|
359
|
-
label,
|
|
360
|
-
...props
|
|
361
|
-
}),
|
|
362
|
-
asyncCombobox: (name, label, props = {}) => ({
|
|
363
|
-
type: "asyncCombobox",
|
|
364
|
-
name,
|
|
365
|
-
label,
|
|
366
|
-
...props
|
|
367
|
-
}),
|
|
368
|
-
asyncMultiselect: (name, label, props = {}) => ({
|
|
369
|
-
type: "asyncMultiselect",
|
|
370
|
-
name,
|
|
371
|
-
label,
|
|
372
|
-
...props
|
|
373
|
-
}),
|
|
374
|
-
dateTime: (name, label, props = {}) => ({
|
|
375
|
-
type: "dateTime",
|
|
376
|
-
name,
|
|
377
|
-
label,
|
|
378
|
-
...props
|
|
379
|
-
}),
|
|
380
358
|
hidden: (name, props = {}) => ({
|
|
381
359
|
type: "hidden",
|
|
382
360
|
name,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/formkit",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Headless, type-safe form generation engine for React 19. Schema-driven with full TypeScript support.",
|
|
5
5
|
"author": "Classytic",
|
|
6
6
|
"license": "MIT",
|
|
@@ -110,4 +110,4 @@
|
|
|
110
110
|
"access": "public",
|
|
111
111
|
"registry": "https://registry.npmjs.org/"
|
|
112
112
|
}
|
|
113
|
-
}
|
|
113
|
+
}
|