Created
April 4, 2026 17:18
-
-
Save dualjack/36e1ad4fd01ec9e754bfba9aa5ce9719 to your computer and use it in GitHub Desktop.
SuperFormRunes - Svelte5 SuperForms with Runes support.
This file contains hidden or 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 {type FormOptions, superForm, type SuperValidated} from "sveltekit-superforms"; | |
| import {fromStoreTwoWayBinding} from "@dualjack/svelte-tools"; | |
| import {tick, untrack} from "svelte"; | |
| import {createAttachmentKey, fromAction} from "svelte/attachments"; | |
| export function superFormRunes< | |
| T extends Record<string, unknown> = Record<string, unknown>, | |
| M = any, | |
| In extends Record<string, unknown> = T | |
| >(formValidated: SuperValidated<T, M, In>|(() => SuperValidated<T, M, In>), formOptions?: FormOptions<T, M, In>){ | |
| const initialValidated = typeof formValidated === 'function' ? formValidated() : formValidated; | |
| const formProxy = superForm<T, M, In>( | |
| initialValidated, | |
| formOptions | |
| ); | |
| const form = fromStoreTwoWayBinding(formProxy.form); | |
| const formId = fromStoreTwoWayBinding(formProxy.formId); | |
| const submitting = fromStoreTwoWayBinding(formProxy.submitting); | |
| const message = fromStoreTwoWayBinding(formProxy.message); | |
| const allErrors = fromStoreTwoWayBinding(formProxy.allErrors); | |
| const errors = fromStoreTwoWayBinding(formProxy.errors); | |
| const delayed = fromStoreTwoWayBinding(formProxy.delayed); | |
| const posted = fromStoreTwoWayBinding(formProxy.posted); | |
| const timeout = fromStoreTwoWayBinding(formProxy.timeout); | |
| const tainted = fromStoreTwoWayBinding(formProxy.tainted); | |
| const constraints = fromStoreTwoWayBinding(formProxy.constraints); | |
| // Logic for reacting to changes in the form validated | |
| // data (for example page invalidation). | |
| let isFirstCycle = true; | |
| $effect(() => { | |
| if(typeof formValidated !== 'function') return; | |
| const next = formValidated(); | |
| if(isFirstCycle){ | |
| isFirstCycle = false; | |
| return; | |
| } | |
| untrack(() => { | |
| formProxy.formId.set(next.id); | |
| formProxy.form.set(next.data); | |
| formProxy.errors.set(next.errors); | |
| formProxy.message.set(next.message); | |
| // constraints are optional in SuperValidated payloads | |
| if(next.constraints){ | |
| formProxy.constraints.set(next.constraints); | |
| } | |
| }); | |
| }); | |
| const enhanceKey = createAttachmentKey(); | |
| // Return wrapped rune-based stores. | |
| return { | |
| ...formProxy, | |
| get form() { return form.current }, | |
| set form(x) { form.current = x }, | |
| get data() { return form.current }, | |
| set data(x) { form.current = x }, | |
| get formId() { return formId.current }, | |
| set formId(x) { formId.current = x }, | |
| get submitting() { return submitting.current }, | |
| set submitting(x) { submitting.current = x }, | |
| get message() { return message.current }, | |
| set message(x) { message.current = x }, | |
| get allErrors() { return allErrors.current }, | |
| set allErrors(x) { allErrors.current = x }, | |
| get errors() { return errors.current }, | |
| set errors(x) { errors.current = x }, | |
| get delayed() { return delayed.current }, | |
| set delayed(x) { delayed.current = x }, | |
| get posted() { return posted.current }, | |
| set posted(x) { posted.current = x }, | |
| get timeout() { return timeout.current }, | |
| set timeout(x) { timeout.current = x }, | |
| get tainted() { return tainted.current }, | |
| set tainted(x) { tainted.current = x }, | |
| get constraints() { return constraints.current }, | |
| set constraints(x) { constraints.current = x }, | |
| enhance: { | |
| [enhanceKey]: fromAction(formProxy.enhance) | |
| }, | |
| async submit(){ | |
| await tick(); | |
| formProxy.submit(); | |
| } | |
| } satisfies { [key in keyof typeof formProxy]: any } & any | |
| } | |
| export type SuperFormRunes< | |
| T extends Record<string, unknown> = Record<string, unknown>, | |
| M = any, | |
| In extends Record<string, unknown> = T | |
| > = ReturnType<typeof superFormRunes<T, M, In>> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment