Last active
June 28, 2022 18:27
-
-
Save innocenzi/f5d1308e3fd14e6cc5e66beb295d7dce to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { VisitOptions } from '../router' | |
import { useForm as useSlimeForm, UseFormBuilder, UseFormRule } from 'slimeform' | |
import { reactive, readonly, ref, UnwrapNestedRefs } from 'vue' | |
import { router } from '../router' | |
type SubmitFunctionParameters = Omit<VisitOptions, 'data'> | |
interface FormOptions<FormT extends {}> extends Omit<VisitOptions, 'data'> { | |
timeout?: number | |
/** Target URL. */ | |
url: string | |
/** Actual fields. */ | |
fields: FormT | UseFormBuilder<FormT> | |
/** Optional transformations before submission. */ | |
transform?: <Transformed = any>(fields: UnwrapNestedRefs<FormT>) => Transformed | |
/** Verification rules. Applied **locally** before submission. */ | |
rules?: UseFormRule<FormT> | |
/** Form key, used for the error bag and history state. */ | |
key?: string | false | |
} | |
export function useForm<FormT extends {}>(options: FormOptions<FormT>) { | |
const { submitter, form, clearErrors, dirtyFields, isError, reset, status } = useSlimeForm({ | |
rule: options.rules, | |
form: typeof options.fields === 'function' | |
? options.fields as UseFormBuilder<FormT> | |
: (() => options.fields) as UseFormBuilder<FormT>, | |
}) | |
/** Whether the submission was recently successful. */ | |
const recentlySuccessful = ref(false) | |
/** Whether the submission was recently failed. */ | |
const recentlyFailed = ref(false) | |
/** Whether the submission is successful. */ | |
const successful = ref(false) | |
/** Whether the form is being processed. */ | |
const processing = ref(false) | |
const timeoutIds = { | |
recentlyFailed: undefined as ReturnType<typeof setTimeout> | undefined, | |
recentlySuccessful: undefined as ReturnType<typeof setTimeout> | undefined, | |
} | |
async function submit(overrides?: SubmitFunctionParameters) { | |
const { submit } = submitter(async({ form, clearErrors, status, reset }) => { | |
return await router.visit({ | |
method: overrides?.method ?? 'POST', | |
...options, | |
...overrides, | |
data: options.transform?.(form) ?? form, | |
preserveState: overrides?.preserveState === undefined && options.method !== 'GET' | |
? true | |
: overrides?.preserveState, | |
events: { | |
before: (visit) => { | |
successful.value = false | |
recentlySuccessful.value = false | |
clearTimeout(timeoutIds.recentlySuccessful!) | |
clearTimeout(timeoutIds.recentlyFailed!) | |
clearErrors() | |
return options.events?.before?.(visit) | |
}, | |
start: (context) => { | |
processing.value = true | |
return options.events?.start?.(context) | |
}, | |
error: (errors) => { | |
Object.keys(errors).forEach((error) => (status as any)[error].setError(errors[error], true)) | |
recentlyFailed.value = true | |
timeoutIds.recentlyFailed = setTimeout(() => recentlyFailed.value = false, options?.timeout ?? 5000) | |
return options.events?.error?.(errors) | |
}, | |
success: (payload) => { | |
reset() | |
successful.value = true | |
recentlySuccessful.value = true | |
timeoutIds.recentlySuccessful = setTimeout(() => recentlySuccessful.value = false, options?.timeout ?? 5000) | |
return options.events?.success?.(payload) | |
}, | |
after: (context) => { | |
processing.value = false | |
return options.events?.after?.(context) | |
}, | |
}, | |
}) | |
}, { | |
enableVerify: false, | |
}) | |
return await submit() | |
} | |
function abort() { | |
router.abort() | |
} | |
return reactive({ | |
submit, | |
processing: readonly(processing), | |
successful: readonly(successful), | |
recentlyFailed: readonly(recentlyFailed), | |
recentlySuccessful: readonly(recentlySuccessful), | |
fields: form, | |
clearErrors, | |
dirtyFields, | |
hasErrors: isError, | |
reset, | |
status, | |
abort, | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment