aboutsummaryrefslogtreecommitdiff
path: root/src/lib/form.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/form.ts')
-rw-r--r--src/lib/form.ts84
1 files changed, 84 insertions, 0 deletions
diff --git a/src/lib/form.ts b/src/lib/form.ts
new file mode 100644
index 0000000..787a397
--- /dev/null
+++ b/src/lib/form.ts
@@ -0,0 +1,84 @@
+import { invalidate } from '$app/navigation';
+
+// this action (https://svelte.dev/tutorial/actions) allows us to
+// progressively enhance a <form> that already works without JS
+export function enhance(
+ form: HTMLFormElement,
+ {
+ pending,
+ error,
+ result
+ }: {
+ pending?: ({ data, form }: { data: FormData; form: HTMLFormElement }) => void;
+ error?: ({
+ data,
+ form,
+ response,
+ error
+ }: {
+ data: FormData;
+ form: HTMLFormElement;
+ response: Response | null;
+ error: Error | null;
+ }) => void;
+ result?: ({
+ data,
+ form,
+ response
+ }: {
+ data: FormData;
+ response: Response;
+ form: HTMLFormElement;
+ }) => void;
+ } = {}
+): { destroy: () => void } {
+ let current_token: unknown;
+
+ async function handle_submit(e: Event) {
+ const token = (current_token = {});
+
+ e.preventDefault();
+
+ const data = new FormData(form);
+
+ if (pending) pending({ data, form });
+
+ try {
+ const response = await fetch(form.action, {
+ method: form.method,
+ headers: {
+ accept: 'application/json'
+ },
+ body: data
+ });
+
+ if (token !== current_token) return;
+
+ if (response.ok) {
+ if (result) result({ data, form, response });
+
+ const url = new URL(form.action);
+ url.search = url.hash = '';
+ invalidate(url.href);
+ } else if (error) {
+ error({ data, form, error: null, response });
+ } else {
+ console.error(await response.text());
+ }
+ } catch (e: any) {
+ if (error) {
+ error({ data, form, error: e, response: null });
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ form.addEventListener('submit', handle_submit);
+
+ return {
+ destroy() {
+ form.removeEventListener('submit', handle_submit);
+ }
+ };
+}