el-form-react
Version:
React form components and hooks powered by Zod validation
948 lines (943 loc) • 31.8 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/components.ts
var components_exports = {};
__export(components_exports, {
AutoForm: () => AutoForm
});
module.exports = __toCommonJS(components_exports);
// src/useForm.ts
var import_react = require("react");
var import_zod = require("zod");
var import_el_form_core2 = require("el-form-core");
// src/utils/index.ts
var import_el_form_core = require("el-form-core");
function addArrayItemReact(obj, path, item) {
const result = { ...obj };
const normalizedPath = path.replace(/\[(\d+)\]/g, ".$1");
const keys = normalizedPath.split(".").filter((key) => key !== "");
let current = result;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!isNaN(Number(key))) {
if (Array.isArray(current)) {
current[Number(key)] = Array.isArray(current[Number(key)]) ? [...current[Number(key)]] : { ...current[Number(key)] };
current = current[Number(key)];
}
} else {
if (typeof current[key] !== "object" || current[key] === null) {
current[key] = {};
} else {
current[key] = Array.isArray(current[key]) ? [...current[key]] : { ...current[key] };
}
current = current[key];
}
}
const arrayKey = keys[keys.length - 1];
if (!isNaN(Number(arrayKey))) {
if (Array.isArray(current)) {
current = [...current];
current[Number(arrayKey)] = item;
}
} else {
if (!Array.isArray(current[arrayKey])) {
current[arrayKey] = [];
} else {
current[arrayKey] = [...current[arrayKey]];
}
current[arrayKey].push(item);
}
return result;
}
// src/useForm.ts
function useForm(options) {
const {
schema,
initialValues = {},
validateOnChange = false,
validateOnBlur = false
} = options;
const fieldRefs = (0, import_react.useRef)(/* @__PURE__ */ new Map());
const [formState, setFormState] = (0, import_react.useState)({
values: initialValues,
errors: {},
touched: {},
isSubmitting: false,
isValid: false,
isDirty: false
});
const validate = (0, import_react.useCallback)(
(values) => {
try {
schema.parse(values);
return { isValid: true, errors: {} };
} catch (error) {
if (error instanceof import_zod.z.ZodError) {
return {
isValid: false,
errors: (0, import_el_form_core2.parseZodErrors)(error)
};
}
return { isValid: false, errors: {} };
}
},
[schema]
);
const checkIsDirty = (0, import_react.useCallback)(
(currentValues) => {
return JSON.stringify(initialValues || {}) !== JSON.stringify(currentValues || {});
},
[initialValues]
);
const checkFieldIsDirty = (0, import_react.useCallback)(
(fieldName) => {
const initialValue = initialValues[fieldName];
const currentValue = formState.values[fieldName];
return JSON.stringify(initialValue) !== JSON.stringify(currentValue);
},
[initialValues, formState.values]
);
const register = (0, import_react.useCallback)(
(name) => {
const fieldValue = name.includes(".") ? (0, import_el_form_core2.getNestedValue)(formState.values, name) : formState.values[name];
const isCheckbox = typeof fieldValue === "boolean";
const baseProps = {
name,
onChange: (e) => {
const target = e.target;
const value = target.type === "checkbox" ? target.checked : target.type === "number" ? target.value ? Number(target.value) : void 0 : target.value;
setFormState((prev) => {
const newValues = name.includes(".") ? (0, import_el_form_core2.setNestedValue)(prev.values, name, value) : { ...prev.values, [name]: value };
let newErrors = { ...prev.errors };
if (name.includes(".")) {
const nestedError = (0, import_el_form_core2.getNestedValue)(newErrors, name);
if (nestedError) {
newErrors = (0, import_el_form_core2.setNestedValue)(newErrors, name, void 0);
}
} else {
delete newErrors[name];
}
if (validateOnChange) {
const { errors } = validate(newValues);
newErrors = errors;
}
return {
...prev,
values: newValues,
errors: newErrors,
isDirty: checkIsDirty(newValues)
};
});
},
onBlur: (_e) => {
setFormState((prev) => {
const newTouched = name.includes(".") ? (0, import_el_form_core2.setNestedValue)(prev.touched, name, true) : { ...prev.touched, [name]: true };
let newErrors = prev.errors;
if (validateOnBlur) {
const { errors } = validate(prev.values);
newErrors = errors;
}
return {
...prev,
touched: newTouched,
errors: newErrors,
isDirty: checkIsDirty(prev.values)
};
});
}
};
if (isCheckbox) {
return {
...baseProps,
checked: Boolean(fieldValue)
};
}
return {
...baseProps,
value: fieldValue || ""
};
},
[formState.values, validateOnChange, validateOnBlur, validate, checkIsDirty]
);
const handleSubmit = (0, import_react.useCallback)(
(onValid, onError) => {
return (e) => {
e.preventDefault();
setFormState((prev) => ({ ...prev, isSubmitting: true }));
const { isValid, errors } = validate(formState.values);
setFormState((prev) => ({
...prev,
errors,
isValid,
isSubmitting: false,
isDirty: checkIsDirty(formState.values)
}));
if (isValid) {
onValid(formState.values);
} else {
if (onError) {
onError(errors);
}
}
};
},
[formState.values, validate, checkIsDirty]
);
const reset = (0, import_react.useCallback)(
(options2) => {
const newValues = options2?.values ?? initialValues;
setFormState({
values: newValues,
errors: options2?.keepErrors ? formState.errors : {},
touched: options2?.keepTouched ? formState.touched : {},
isSubmitting: false,
isValid: false,
isDirty: options2?.keepDirty ? formState.isDirty : false
});
},
[initialValues, formState]
);
const setValue = (0, import_react.useCallback)(
(path, value) => {
setFormState((prev) => {
const newValues = (0, import_el_form_core2.setNestedValue)(prev.values, path, value);
const { errors } = validate(newValues);
return {
...prev,
values: newValues,
errors,
isDirty: checkIsDirty(newValues)
};
});
},
[validate, checkIsDirty]
);
const addArrayItemHandler = (0, import_react.useCallback)(
(path, item) => {
setFormState((prev) => {
const newValues = addArrayItemReact(prev.values, path, item);
const { errors } = validate(newValues);
return {
...prev,
values: newValues,
errors,
isDirty: checkIsDirty(newValues)
};
});
},
[validate, checkIsDirty]
);
const removeArrayItemHandler = (0, import_react.useCallback)(
(path, index) => {
setFormState((prev) => {
const newValues = (0, import_el_form_core2.removeArrayItem)(prev.values, path, index);
const { errors } = validate(newValues);
return {
...prev,
values: newValues,
errors,
isDirty: checkIsDirty(newValues)
};
});
},
[validate, checkIsDirty]
);
const watch = (0, import_react.useCallback)(
(nameOrNames) => {
if (!nameOrNames) {
return formState.values;
}
if (Array.isArray(nameOrNames)) {
const result = {};
nameOrNames.forEach((name) => {
result[name] = formState.values[name];
});
return result;
}
return formState.values[nameOrNames];
},
[formState.values]
);
const isDirty = (0, import_react.useCallback)(
(name) => {
if (name) {
return checkFieldIsDirty(name);
}
return formState.isDirty;
},
[formState.isDirty, checkFieldIsDirty]
);
const getFieldState = (0, import_react.useCallback)(
(name) => {
return {
isDirty: checkFieldIsDirty(name),
isTouched: !!formState.touched[name],
error: formState.errors[name]
};
},
[formState, checkFieldIsDirty]
);
const getDirtyFields = (0, import_react.useCallback)(() => {
const dirtyFields = {};
Object.keys(formState.values).forEach((key) => {
const fieldName = key;
if (checkFieldIsDirty(fieldName)) {
dirtyFields[fieldName] = true;
}
});
return dirtyFields;
}, [formState.values, checkFieldIsDirty]);
const getTouchedFields = (0, import_react.useCallback)(() => {
return { ...formState.touched };
}, [formState.touched]);
const trigger = (0, import_react.useCallback)(
async (nameOrNames) => {
if (!nameOrNames) {
const { isValid: isValid2 } = validate(formState.values);
return isValid2;
}
if (Array.isArray(nameOrNames)) {
const fieldsToValidate = {};
nameOrNames.forEach((name) => {
fieldsToValidate[name] = formState.values[name];
});
const { isValid: isValid2 } = validate(fieldsToValidate);
return isValid2;
}
const fieldToValidate = {};
fieldToValidate[nameOrNames] = formState.values[nameOrNames];
const { isValid } = validate(fieldToValidate);
return isValid;
},
[formState.values, validate]
);
const clearErrors = (0, import_react.useCallback)((name) => {
setFormState((prev) => {
if (name) {
const newErrors = { ...prev.errors };
delete newErrors[name];
return { ...prev, errors: newErrors };
}
return { ...prev, errors: {} };
});
}, []);
const setError = (0, import_react.useCallback)(
(name, error) => {
setFormState((prev) => ({
...prev,
errors: { ...prev.errors, [name]: error }
}));
},
[]
);
const setFocus = (0, import_react.useCallback)(
(name, options2) => {
const fieldRef = fieldRefs.current.get(name);
if (fieldRef) {
fieldRef.focus();
if (options2?.shouldSelect && "select" in fieldRef) {
fieldRef.select();
}
}
},
[]
);
const resetField = (0, import_react.useCallback)(
(name) => {
setFormState((prev) => {
const newValues = { ...prev.values };
newValues[name] = initialValues[name];
const newErrors = { ...prev.errors };
delete newErrors[name];
const newTouched = { ...prev.touched };
delete newTouched[name];
return {
...prev,
values: newValues,
errors: newErrors,
touched: newTouched,
isDirty: checkIsDirty(newValues)
};
});
},
[initialValues, checkIsDirty]
);
return {
register,
handleSubmit,
formState,
reset,
setValue,
watch,
getFieldState,
isDirty,
getDirtyFields,
getTouchedFields,
trigger,
clearErrors,
setError,
setFocus,
addArrayItem: addArrayItemHandler,
removeArrayItem: removeArrayItemHandler,
resetField
};
}
// src/AutoForm.tsx
var import_zod2 = require("zod");
var import_jsx_runtime = require("react/jsx-runtime");
var DefaultErrorComponent = ({
errors,
touched
}) => {
const errorEntries = Object.entries(errors).filter(
([field]) => touched[field]
);
if (errorEntries.length === 0) return null;
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "el-form-error-summary", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u26A0\uFE0F Please fix the following errors:" }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { children: errorEntries.map(([field, error]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "#ef4444", marginRight: "0.5rem" }, children: "\u2022" }),
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { textTransform: "capitalize" }, children: [
field,
":"
] }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { marginLeft: "0.25rem" }, children: String(error) })
] }, field)) })
] });
};
var DefaultField = ({
name,
label,
type = "text",
placeholder,
value,
onChange,
onBlur,
error,
touched,
options
}) => {
const fieldId = `field-${name}`;
if (type === "checkbox") {
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-x-2", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"input",
{
id: fieldId,
name,
type: "checkbox",
checked: !!value,
onChange,
onBlur,
className: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
}
),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: fieldId, className: "text-sm font-medium text-gray-900", children: label })
] });
}
const inputClasses = `
w-full px-3 py-2 border rounded-md text-sm text-gray-900 placeholder-gray-500
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500
${touched && error ? "border-red-500 focus:ring-red-500 focus:border-red-500" : "border-gray-300"}
`.trim().replace(/\s+/g, " ");
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1", children: [
label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"label",
{
htmlFor: fieldId,
className: "block text-sm font-medium text-gray-700",
children: label
}
),
type === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"textarea",
{
id: fieldId,
name,
value: value || "",
onChange,
onBlur,
placeholder,
className: `${inputClasses} resize-none`,
rows: 4
}
) : type === "select" && options ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
"select",
{
id: fieldId,
name,
value: value || "",
onChange,
onBlur,
className: inputClasses,
children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "", children: placeholder || "Select an option" }),
options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: option.value, children: option.label }, option.value))
]
}
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"input",
{
id: fieldId,
name,
type,
value: value || "",
onChange,
onBlur,
placeholder,
className: inputClasses
}
),
touched && error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-red-500 text-xs mt-1", children: error })
] });
};
var ArrayField = ({
fieldConfig,
value = [],
path,
onAddItem,
onRemoveItem,
onValueChange,
register,
formState
}) => {
const arrayValue = Array.isArray(value) ? value : [];
const createEmptyItem = () => {
if (!fieldConfig.fields) return {};
if (fieldConfig.fields.length === 1 && fieldConfig.fields[0].name === "value") {
const fieldType = fieldConfig.fields[0].type;
if (fieldType === "number") {
return 0;
} else if (fieldType === "checkbox") {
return false;
} else {
return "";
}
}
const emptyItem = {};
fieldConfig.fields.forEach((field) => {
if (field.type === "array") {
emptyItem[field.name] = [];
} else if (field.type === "number") {
emptyItem[field.name] = 0;
} else {
emptyItem[field.name] = "";
}
});
return emptyItem;
};
const handleAddItem = () => {
onAddItem(path, createEmptyItem());
};
const handleRemoveItem = (index) => {
onRemoveItem(path, index);
};
const renderNestedField = (nestedFieldConfig, itemIndex, itemPath) => {
if (nestedFieldConfig.name === "value") {
const fieldValue2 = arrayValue[itemIndex] || "";
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "space-y-1", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"input",
{
type: nestedFieldConfig.type || "text",
value: fieldValue2,
onChange: (e) => {
const newValue = nestedFieldConfig.type === "number" ? e.target.value ? Number(e.target.value) : 0 : e.target.value;
onValueChange(itemPath, newValue);
},
placeholder: nestedFieldConfig.placeholder || "Enter value",
className: "w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
}
) }, itemPath);
}
const fieldPath = `${itemPath}.${nestedFieldConfig.name}`;
const fieldValue = arrayValue[itemIndex]?.[nestedFieldConfig.name] || "";
if (nestedFieldConfig.type === "array") {
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
ArrayField,
{
fieldConfig: nestedFieldConfig,
value: fieldValue,
path: fieldPath,
onAddItem,
onRemoveItem,
onValueChange,
register,
formState
},
fieldPath
);
}
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1", children: [
nestedFieldConfig.label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "block text-sm font-medium text-gray-700", children: nestedFieldConfig.label }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"input",
{
type: nestedFieldConfig.type || "text",
value: fieldValue,
onChange: (e) => {
const newValue = nestedFieldConfig.type === "number" ? e.target.value ? Number(e.target.value) : 0 : e.target.value;
onValueChange(fieldPath, newValue);
},
placeholder: nestedFieldConfig.placeholder,
className: "w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
}
)
] }, fieldPath);
};
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-3", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "block text-sm font-medium text-gray-700", children: fieldConfig.label || fieldConfig.name }),
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
"button",
{
type: "button",
onClick: handleAddItem,
className: "px-3 py-1 bg-green-600 text-white text-xs rounded-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500",
children: [
"+ Add ",
fieldConfig.label || fieldConfig.name
]
}
)
] }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "space-y-4", children: arrayValue.map((_, index) => {
const itemPath = `${path}[${index}]`;
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
"div",
{
className: "p-4 border border-gray-200 rounded-lg bg-gray-50",
children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex justify-between items-center mb-3", children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h4", { className: "text-sm font-medium text-gray-700", children: [
fieldConfig.label || fieldConfig.name,
" #",
index + 1
] }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"button",
{
type: "button",
onClick: () => handleRemoveItem(index),
className: "px-2 py-1 bg-red-600 text-white text-xs rounded hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500",
children: "Remove"
}
)
] }),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: fieldConfig.fields?.map(
(nestedField) => renderNestedField(nestedField, index, itemPath)
) })
]
},
index
);
}) }),
arrayValue.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "text-gray-500 text-sm italic text-center py-4", children: [
"No ",
fieldConfig.label?.toLowerCase() || fieldConfig.name,
' added yet. Click "Add" to create one.'
] })
] });
};
function generateFieldsFromSchema(schema) {
if (!(schema instanceof import_zod2.z.ZodObject)) {
return [];
}
const shape = schema.shape;
const fields = [];
for (const key in shape) {
if (Object.prototype.hasOwnProperty.call(shape, key)) {
const zodType = shape[key];
const typeName = zodType._def.typeName;
const fieldConfig = {
name: key,
label: key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()),
type: "text"
// Default to text
};
if (typeName === "ZodString") {
const checks = zodType._def.checks || [];
if (checks.some((c) => c.kind === "email")) {
fieldConfig.type = "email";
} else if (checks.some((c) => c.kind === "url")) {
fieldConfig.type = "url";
}
} else if (typeName === "ZodNumber") {
fieldConfig.type = "number";
} else if (typeName === "ZodBoolean") {
fieldConfig.type = "checkbox";
} else if (typeName === "ZodEnum") {
fieldConfig.type = "select";
fieldConfig.options = zodType._def.values.map((v) => ({
value: v,
label: v
}));
} else if (typeName === "ZodDate") {
fieldConfig.type = "date";
} else if (typeName === "ZodArray") {
fieldConfig.type = "array";
const arrayElementType = zodType._def.type;
if (arrayElementType instanceof import_zod2.z.ZodObject) {
fieldConfig.fields = generateFieldsFromSchema(arrayElementType);
} else {
const elementTypeName = arrayElementType._def.typeName;
let elementType = "text";
if (elementTypeName === "ZodString") {
elementType = "text";
} else if (elementTypeName === "ZodNumber") {
elementType = "number";
} else if (elementTypeName === "ZodBoolean") {
elementType = "checkbox";
}
fieldConfig.fields = [
{
name: "value",
type: elementType,
label: "Value"
}
];
}
}
fields.push(fieldConfig);
}
}
return fields;
}
function mergeFields(autoFields, manualFields) {
const manualFieldsMap = new Map(
manualFields.map((field) => [field.name, field])
);
const mergedFields = autoFields.map((autoField) => {
const manualField = manualFieldsMap.get(autoField.name);
if (manualField) {
return { ...autoField, ...manualField };
}
return autoField;
});
manualFields.forEach((manualField) => {
if (!autoFields.some((autoField) => autoField.name === manualField.name)) {
mergedFields.push(manualField);
}
});
return mergedFields;
}
function AutoForm({
schema,
fields,
initialValues = {},
layout = "flex",
columns = 12,
onSubmit,
onError,
children,
customErrorComponent,
componentMap
}) {
const formApi = useForm({
schema,
initialValues,
validateOnChange: true,
validateOnBlur: true
});
const {
register,
handleSubmit,
formState,
reset,
setValue,
addArrayItem,
removeArrayItem: removeArrayItem3
} = formApi;
const autoGeneratedFields = generateFieldsFromSchema(schema);
const fieldsToRender = fields ? mergeFields(autoGeneratedFields, fields) : autoGeneratedFields;
const ErrorComponent = customErrorComponent || DefaultErrorComponent;
const renderField = (fieldConfig) => {
const fieldName = fieldConfig.name;
const getColSpanClass = (colSpan) => {
const spanMap = {
1: "col-span-1",
2: "col-span-2",
3: "col-span-3",
4: "col-span-4",
5: "col-span-5",
6: "col-span-6",
7: "col-span-7",
8: "col-span-8",
9: "col-span-9",
10: "col-span-10",
11: "col-span-11",
12: "col-span-12"
};
return spanMap[colSpan || 1];
};
const getFlexClass = (colSpan) => {
const flexMap = {
1: "w-1/12",
2: "w-2/12",
3: "w-3/12",
4: "w-4/12",
5: "w-5/12",
6: "w-6/12",
7: "w-7/12",
8: "w-8/12",
9: "w-9/12",
10: "w-10/12",
11: "w-11/12",
12: "w-full"
};
return flexMap[colSpan || 12];
};
const fieldContainerClasses = layout === "grid" ? getColSpanClass(fieldConfig.colSpan) : `flex-none ${getFlexClass(fieldConfig.colSpan)}`;
if (fieldConfig.type === "array") {
const fieldProps2 = register(String(fieldName));
const fieldValue2 = "value" in fieldProps2 ? fieldProps2.value : [];
const arrayValue = Array.isArray(fieldValue2) ? fieldValue2 : [];
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fieldContainerClasses, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
ArrayField,
{
fieldConfig,
value: arrayValue,
path: fieldConfig.name,
onAddItem: addArrayItem,
onRemoveItem: removeArrayItem3,
onValueChange: setValue,
register,
formState
}
) }, fieldConfig.name);
}
const fieldProps = register(String(fieldName));
const error = formState.errors[fieldName];
const touched = formState.touched[fieldName];
const fieldValue = "checked" in fieldProps ? fieldProps.checked : "value" in fieldProps ? fieldProps.value : void 0;
const FieldComponent = fieldConfig.component || fieldConfig.type && componentMap?.[fieldConfig.type] || DefaultField;
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fieldContainerClasses, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
FieldComponent,
{
name: fieldConfig.name,
label: fieldConfig.label || fieldConfig.name,
type: fieldConfig.type,
placeholder: fieldConfig.placeholder,
value: fieldValue,
onChange: fieldProps.onChange,
onBlur: fieldProps.onBlur,
error,
touched,
options: fieldConfig.options
}
) }, fieldConfig.name);
};
const getGridClass = (cols) => {
const gridMap = {
1: "grid-cols-1",
2: "grid-cols-2",
3: "grid-cols-3",
4: "grid-cols-4",
5: "grid-cols-5",
6: "grid-cols-6",
7: "grid-cols-7",
8: "grid-cols-8",
9: "grid-cols-9",
10: "grid-cols-10",
11: "grid-cols-11",
12: "grid-cols-12"
};
return gridMap[cols];
};
const containerClasses = layout === "grid" ? `grid ${getGridClass(columns)} gap-4` : `flex flex-wrap gap-4`;
const defaultForm = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
"form",
{
onSubmit: handleSubmit(
(data) => onSubmit(data),
onError || ((errors) => console.error("Form validation errors:", errors))
),
className: "w-full",
children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
ErrorComponent,
{
errors: formState.errors,
touched: formState.touched
}
),
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: containerClasses, children: [
fieldsToRender.map(renderField),
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
"div",
{
className: `
flex gap-3 mt-6
${layout === "grid" ? "col-span-full" : "w-full"}
`.trim().replace(/\s+/g, " "),
children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"button",
{
type: "submit",
disabled: formState.isSubmitting,
className: "p-2 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-60 disabled:cursor-not-allowed transition-colors duration-200 cursor-pointer",
children: formState.isSubmitting ? "Submitting..." : "Submit"
}
),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"button",
{
type: "button",
onClick: () => reset(),
className: "p-2 bg-gray-600 text-white rounded-md text-sm font-medium hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition-colors duration-200 cursor-pointer",
children: "Reset"
}
)
]
}
)
] })
]
}
);
if (children) {
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-full", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
"form",
{
onSubmit: handleSubmit(
(data) => onSubmit(data),
onError || ((errors) => console.error("Form validation errors:", errors))
),
className: "w-full",
children: [
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
ErrorComponent,
{
errors: formState.errors,
touched: formState.touched
}
),
children(formApi),
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: containerClasses, children: fieldsToRender.map(renderField) })
]
}
) });
}
return defaultForm;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
AutoForm
});
//# sourceMappingURL=components.js.map