/*! * Original code by Remix Sofware Inc * MIT Licensed, Copyright(c) 2021 Remix software Inc, see LICENSE.remix.md for details * * Credits to the Remix team for the Form implementation: * https://github.com/remix-run/remix/blob/main/packages/remix-react/components.tsx#L865 */ import { ComponentProps, createEffect, mergeProps, onCleanup, splitProps } from "solid-js"; export interface FormAction { action: string; method: string; formData: Data; encType: string; } export { FormError } from "./FormError"; export { FormImpl as Form }; type FormEncType = "application/x-www-form-urlencoded" | "multipart/form-data"; export interface SubmitOptions { /** * The HTTP method used to submit the form. Overrides `
`. * Defaults to "GET". */ method?: FormMethod; /** * The action URL path used to submit the form. Overrides ``. * Defaults to the path of the current route. * * Note: It is assumed the path is already resolved. If you need to resolve a * relative path, use `useFormAction`. */ action?: string; /** * The action URL used to submit the form. Overrides ``. * Defaults to "application/x-www-form-urlencoded". */ encType?: FormEncType; /** * Set `true` to replace the current entry in the browser's history stack * instead of creating a new one (i.e. stay on "the same page"). Defaults * to `false`. */ replace?: boolean; } /** * Submits a HTML `` to the server without reloading the page. */ export interface SubmitFunction { ( /** * Specifies the `` to be submitted to the server, a specific * ` //
// // formData.get("something") should be "whatever", but we don't get that // unless we call submit on the clicked button itself. // // To figure out which button triggered the submit, we'll attach a click // event listener to the form. The click event is always triggered before // the submit event (even when submitting via keyboard when focused on // another form field, yeeeeet) so we should have access to that button's // data for use in the submit handler. let clickedButtonRef; let form: HTMLFormElement | null = null; createEffect(() => { if (!form) return; function handleClick(event: MouseEvent) { if (!(event.target instanceof HTMLElement)) return; let submitButton = event.target.closest( "button,input[type=submit]" ); if (submitButton && submitButton.type === "submit") { clickedButtonRef = submitButton; } } form.addEventListener("click", handleClick); onCleanup(() => { form && form.removeEventListener("click", handleClick); }); }, []); return (
{ form = f; if (typeof props.ref === "function") props.ref(f); }} method={formMethod} action={_props.action} // encType={encType} onSubmit={ props.reloadDocument ? undefined : event => { props.onSubmit && props.onSubmit(event); if (event.defaultPrevented) return; event.preventDefault(); submit(clickedButtonRef || event.currentTarget, { method: props.method, replace: props.replace }); clickedButtonRef = null; } } {...rest} > {props.children}
); }; export interface SubmitOptions { /** * The HTTP method used to submit the form. Overrides `
`. * Defaults to "GET". */ method?: FormMethod; /** * The action URL path used to submit the form. Overrides ``. * Defaults to the path of the current route. * * Note: It is assumed the path is already resolved. If you need to resolve a * relative path, use `useFormAction`. */ action?: string; /** * The action URL used to submit the form. Overrides ``. * Defaults to "application/x-www-form-urlencoded". */ // encType?: FormEncType; /** * Set `true` to replace the current entry in the browser's history stack * instead of creating a new one (i.e. stay on "the same page"). Defaults * to `false`. */ replace?: boolean; } export function useSubmitImpl( onSubmission: (sub: FormAction) => void ): SubmitFunction { return (target, options = {}) => { let method: string; let action: string; let encType: string; let formData: FormData; if (isFormElement(target)) { let submissionTrigger: HTMLButtonElement | HTMLInputElement = (options as any) .submissionTrigger; method = options.method || target.method; action = options.action || target.action; encType = options.encType || target.enctype; formData = new FormData(target); if (submissionTrigger && submissionTrigger.name) { formData.append(submissionTrigger.name, submissionTrigger.value); } } else if ( isButtonElement(target) || (isInputElement(target) && (target.type === "submit" || target.type === "image")) ) { let form = target.form; if (form == null) { throw new Error(`Cannot submit a