add disableSubmitOnError prop to NativeForm and export getFlashMessage (#162)

Introduced a `disableSubmitOnError` prop to NativeForm to control submit button behavior when errors are present. Also exported `getFlashMessage` from the core for external usage.
This commit is contained in:
dswbx
2025-04-24 04:59:44 -07:00
committed by GitHub
parent 11f76d788a
commit a762789e93
2 changed files with 27 additions and 14 deletions
+1
View File
@@ -25,6 +25,7 @@ export {
isBooleanLike, isBooleanLike,
} from "./object/query/query"; } from "./object/query/query";
export { Registry, type Constructor } from "./registry/Registry"; export { Registry, type Constructor } from "./registry/Registry";
export { getFlashMessage } from "./server/flash";
export * from "./console"; export * from "./console";
export * from "./events"; export * from "./events";
@@ -28,6 +28,7 @@ export type NativeFormProps = {
ctx: { event: FormEvent<HTMLFormElement> }, ctx: { event: FormEvent<HTMLFormElement> },
) => Promise<void> | void; ) => Promise<void> | void;
onError?: (errors: InputError[]) => void; onError?: (errors: InputError[]) => void;
disableSubmitOnError?: boolean;
onChange?: ( onChange?: (
data: any, data: any,
ctx: { event: ChangeEvent<HTMLFormElement>; key: string; value: any; errors: InputError[] }, ctx: { event: ChangeEvent<HTMLFormElement>; key: string; value: any; errors: InputError[] },
@@ -50,6 +51,7 @@ export function NativeForm({
onSubmitInvalid, onSubmitInvalid,
onError, onError,
clean, clean,
disableSubmitOnError = true,
...props ...props
}: NativeFormProps) { }: NativeFormProps) {
const formRef = useRef<HTMLFormElement>(null); const formRef = useRef<HTMLFormElement>(null);
@@ -74,7 +76,7 @@ export function NativeForm({
onError?.(errors); onError?.(errors);
}, [errors]); }, [errors]);
const validateElement = useEvent((el: InputElement | null, opts?: { report?: boolean }) => { const validateElement = (el: InputElement | null, opts?: { report?: boolean }) => {
if (props.noValidate || !el || !("name" in el)) return; if (props.noValidate || !el || !("name" in el)) return;
const errorElement = formRef.current?.querySelector( const errorElement = formRef.current?.querySelector(
errorFieldSelector?.(el.name) ?? `[data-role="input-error"][data-name="${el.name}"]`, errorFieldSelector?.(el.name) ?? `[data-role="input-error"][data-name="${el.name}"]`,
@@ -104,9 +106,9 @@ export function NativeForm({
} }
return; return;
}); };
const validate = useEvent((opts?: { report?: boolean }) => { const validate = (opts?: { report?: boolean }) => {
if (!formRef.current || props.noValidate) return []; if (!formRef.current || props.noValidate) return [];
const errors: InputError[] = []; const errors: InputError[] = [];
@@ -118,10 +120,20 @@ export function NativeForm({
} }
}); });
return errors; if (disableSubmitOnError) {
}); formRef.current.querySelectorAll("[type=submit]").forEach((submit) => {
if (errors.length > 0) {
submit.setAttribute("disabled", "disabled");
} else {
submit.removeAttribute("disabled");
}
});
}
const getFormValues = useEvent(() => { return errors;
};
const getFormValues = () => {
if (!formRef.current) return {}; if (!formRef.current) return {};
const formData = new FormData(formRef.current); const formData = new FormData(formRef.current);
@@ -148,15 +160,15 @@ export function NativeForm({
if (typeof clean === "undefined") return obj; if (typeof clean === "undefined") return obj;
return cleanObject(obj, clean === true ? undefined : clean); return cleanObject(obj, clean === true ? undefined : clean);
}); };
const handleChange = useEvent(async (e: ChangeEvent<HTMLFormElement>) => { const handleChange = async (e: ChangeEvent<HTMLFormElement>) => {
const form = formRef.current; const form = formRef.current;
if (!form) return; if (!form) return;
const target = getFormTarget(e); const target = getFormTarget(e);
if (!target) return; if (!target) return;
if (validateOn === "change") { if (validateOn === "change" || errors.length > 0) {
validateElement(target, { report: true }); validateElement(target, { report: true });
} }
@@ -168,9 +180,9 @@ export function NativeForm({
errors, errors,
}); });
} }
}); };
const handleSubmit = useEvent(async (e: FormEvent<HTMLFormElement>) => { const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault(); e.preventDefault();
const form = formRef.current; const form = formRef.current;
if (!form) return; if (!form) return;
@@ -186,9 +198,9 @@ export function NativeForm({
} else { } else {
form.submit(); form.submit();
} }
}); };
const handleKeyDown = useEvent((e: KeyboardEvent) => { const handleKeyDown = (e: KeyboardEvent) => {
if (!formRef.current) return; if (!formRef.current) return;
// if is enter key, submit is disabled, report errors // if is enter key, submit is disabled, report errors
@@ -198,7 +210,7 @@ export function NativeForm({
formRef.current.reportValidity(); formRef.current.reportValidity();
} }
} }
}); };
return ( return (
<form <form