From 4bb5f0bbcef010f144439e3a6bfc04d343b8811c Mon Sep 17 00:00:00 2001 From: Hunter Johnston Date: Thu, 12 Dec 2024 22:02:55 -0500 Subject: [PATCH] shutup check --- docs/.velite/docs.json | 1110 +++++++++++++++++++-------------------- docs/.velite/index.d.ts | 8 +- docs/.velite/index.js | 2 +- docs/vite.config.ts | 1 + 4 files changed, 561 insertions(+), 560 deletions(-) diff --git a/docs/.velite/docs.json b/docs/.velite/docs.json index 037eead..c8b43a8 100644 --- a/docs/.velite/docs.json +++ b/docs/.velite/docs.json @@ -1,556 +1,556 @@ [ - { - "title": "Introduction", - "description": "What is this?", - "path": "index", - "content": "

Formsnap takes the already incredible sveltekit-superforms (winner of Svelte Hack 2023 for best library), made by the brilliant Andreas Söderlund and wraps it with components that make it simpler to use while making your forms accessible by default.

\n

The Same Form, Two Ways

\n

To showcase the value provided by Formsnap, let's take a look at a simple sign up form using only Superforms, and then using Superforms with Formsnap.

\n

Superforms Only

\n
<script lang=\"ts\">\n\timport type { PageData } from \"./$types\";\n\timport { superForm } from \"sveltekit-superforms\";\n\timport { zodClient } from \"sveltekit-superforms/adapters\";\n\timport { signupFormSchema } from \"./schema\";\n\tlet { data } = $props();\n\n\tconst { form, errors, enhance, constraints } = superForm(data.form, {\n\t\tvalidators: zodClient(signupFormSchema),\n\t});\n</script>\n\n<form method=\"POST\" use:enhance>\n\t<label for=\"name\">Name</label>\n\t<input\n\t\tid=\"name\"\n\t\tname=\"name\"\n\t\taria-describedby={$errors.name ? \"name-error name-desc\" : \"name-desc\"}\n\t\taria-invalid={$errors.name ? \"true\" : undefined}\n\t\taria-required={$constraints.name?.required ? \"true\" : undefined}\n\t\tbind:value={$form.name}\n\t/>\n\t<span id=\"name-desc\">Be sure to use your real name.</span>\n\t<span id=\"name-error\" aria-live=\"assertive\">\n\t\t{#if $errors.name.length}\n\t\t\t{#each $errors.name as err}\n\t\t\t\t{err}\n\t\t\t{/each}\n\t\t{/if}\n\t</span>\n\t<label for=\"email\">Email</label>\n\t<input\n\t\tid=\"email\"\n\t\tname=\"email\"\n\t\ttype=\"email\"\n\t\taria-describedby={$errors.email ? \"email-error email-desc\" : \"email-desc\"}\n\t\taria-invalid={$errors.email ? \"true\" : undefined}\n\t\taria-required={$constraints.email?.required ? \"true\" : undefined}\n\t\tbind:value={$form.email}\n\t/>\n\t<span id=\"email-desc\">It's preferred that you use your company email.</span>\n\t<span id=\"email-error\" aria-live=\"assertive\">\n\t\t{#if $errors.email.length}\n\t\t\t{#each $errors.email as err}\n\t\t\t\t{err}\n\t\t\t{/each}\n\t\t{/if}\n\t</span>\n\t<label for=\"password\">Password</label>\n\t<input\n\t\tid=\"password\"\n\t\tname=\"password\"\n\t\ttype=\"password\"\n\t\taria-describedby={$errors.password ? \"password-error password-desc\" : \"password-desc\"}\n\t\taria-invalid={$errors.password ? \"true\" : undefined}\n\t\taria-required={$constraints.password?.required ? \"true\" : undefined}\n\t\tbind:value={$form.password}\n\t/>\n\t<span id=\"password-desc\">Ensure the password is at least 10 characters.</span>\n\t<span id=\"password-error\" aria-live=\"assertive\">\n\t\t{#if $errors.password.length}\n\t\t\t{#each $errors.password as err}\n\t\t\t\t{err}\n\t\t\t{/each}\n\t\t{/if}\n\t</span>\n\t<button>Submit</button>\n</form>\n
\n

That's quite a bit of code required to get a simple, accessible form up and running. We can't move as quickly as we'd like to, it's not very DRY, and is ripe for copy-paste errors.

\n

All is not lost though, as the whole idea behind Formsnap is to make this process simpler, without sacrificing the flexibility that Superforms provides.

\n

Superforms + Formsnap

\n
<script lang=\"ts\">\n\timport { Field, Control, Label, FieldErrors, Description } from \"formsnap\";\n\timport { signupFormSchema } from \"./schema.ts\";\n\timport { zodClient } from \"sveltekit-superforms/adapters\";\n\timport { superForm } from \"sveltekit-superforms\";\n\tlet { data } = $props();\n\n\tconst form = superForm(data.form, {\n\t\tvalidators: zodClient(signupFormSchema),\n\t});\n\tconst { form: formData, enhance } = form;\n</script>\n\n<form method=\"POST\" use:enhance>\n\t<Field {form} name=\"name\">\n\t\t<Control>\n\t\t\t{#snippet children({ props })}\n\t\t\t\t<Label>Name</Label>\n\t\t\t\t<input {...props} bind:value={$formData.name} />\n\t\t\t{/snippet}\n\t\t</Control>\n\t\t<Description>Be sure to use your real name.</Description>\n\t\t<FieldErrors />\n\t</Field>\n\t<Field {form} name=\"email\">\n\t\t<Control>\n\t\t\t{#snippet children({ props })}\n\t\t\t\t<Label>Email</Label>\n\t\t\t\t<input {...props} type=\"email\" bind:value={$formData.email} />\n\t\t\t{/snippet}\n\t\t</Control>\n\t\t<Description>It's preferred that you use your company email.</Description>\n\t\t<FieldErrors />\n\t</Field>\n\t<Field {form} name=\"password\">\n\t\t<Control>\n\t\t\t{#snippet children({ props })}\n\t\t\t\t<Label>Password</Label>\n\t\t\t\t<input {...props} type=\"password\" bind:value={$formData.password} />\n\t\t\t{/snippet}\n\t\t</Control>\n\t\t<Description>Ensure the password is at least 10 characters.</Description>\n\t\t<FieldErrors />\n\t</Field>\n</form>\n
\n

That's it! We just condensed a bunch of code, while retaining the same functionality.

\n

Next Steps

\n

To get started using Formsnap, head over to the Quick start section of the docs, where you'll learn how to install and use the library.

", - "raw": "Formsnap takes the already incredible [sveltekit-superforms](https://github.com/ciscoheat/sveltekit-superforms) (winner of [Svelte Hack 2023](https://hack.sveltesociety.dev/winners) for best library), made by the brilliant [Andreas Söderlund](https://github.com/ciscoheat) and wraps it with components that make it simpler to use while making your forms accessible by default.\n\n## The Same Form, Two Ways\n\nTo showcase the value provided by Formsnap, let's take a look at a simple sign up form using only Superforms, and then using Superforms with Formsnap.\n\n### Superforms Only\n\n```svelte title=\"+page.svelte\"\n\n\n
\n\t\n\t\n\tBe sure to use your real name.\n\t\n\t\t{#if $errors.name.length}\n\t\t\t{#each $errors.name as err}\n\t\t\t\t{err}\n\t\t\t{/each}\n\t\t{/if}\n\t\n\t\n\t\n\tIt's preferred that you use your company email.\n\t\n\t\t{#if $errors.email.length}\n\t\t\t{#each $errors.email as err}\n\t\t\t\t{err}\n\t\t\t{/each}\n\t\t{/if}\n\t\n\t\n\t\n\tEnsure the password is at least 10 characters.\n\t\n\t\t{#if $errors.password.length}\n\t\t\t{#each $errors.password as err}\n\t\t\t\t{err}\n\t\t\t{/each}\n\t\t{/if}\n\t\n\t\n\n```\n\nThat's quite a bit of code required to get a simple, accessible form up and running. We can't move as quickly as we'd like to, it's not very DRY, and is ripe for copy-paste errors.\n\nAll is not lost though, as the whole idea behind Formsnap is to make this process simpler, without sacrificing the flexibility that Superforms provides.\n\n### Superforms + Formsnap\n\n```svelte title=\"+page.svelte\"\n\n\n
\n\t\n\t\t\n\t\t\t{#snippet children({ props })}\n\t\t\t\t\n\t\t\t\t\n\t\t\t{/snippet}\n\t\t\n\t\tBe sure to use your real name.\n\t\t\n\t\n\t\n\t\t\n\t\t\t{#snippet children({ props })}\n\t\t\t\t\n\t\t\t\t\n\t\t\t{/snippet}\n\t\t\n\t\tIt's preferred that you use your company email.\n\t\t\n\t\n\t\n\t\t\n\t\t\t{#snippet children({ props })}\n\t\t\t\t\n\t\t\t\t\n\t\t\t{/snippet}\n\t\t\n\t\tEnsure the password is at least 10 characters.\n\t\t\n\t\n
\n```\n\nThat's it! We just condensed a bunch of code, while retaining the same functionality.\n\n## Next Steps\n\nTo get started using Formsnap, head over to the [Quick start](/docs/quick-start) section of the docs, where you'll learn how to install and use the library.", - "toc": [ - { - "title": "The Same Form, Two Ways", - "url": "#the-same-form-two-ways", - "items": [ - { - "title": "Superforms Only", - "url": "#superforms-only", - "items": [] - }, - { - "title": "Superforms + Formsnap", - "url": "#superforms--formsnap", - "items": [] - } - ] - }, - { - "title": "Next Steps", - "url": "#next-steps", - "items": [] - } - ], - "section": "Anchors", - "slug": "index", - "slugFull": "/index" - }, - { - "title": "Quick start", - "description": "Learn how to take off with Formsnap by building a settings form.", - "path": "quick-start", - "content": "\n

Installation

\n

Since Formsnap is built on top of Superforms, you'll need to install it as well as a schema validation library of your choice. We'll use Zod.

\n
npm install formsnap sveltekit-superforms zod\n
\n

Tutorial: Build a settings form

\n

Before diving into this tutorial, it's important to be confident with Superforms, as Formsnap is built on top of it and uses the same APIs.

\n\n

Define a Zod schema

\n

This schema will represent the shape of our form data. It's used to validate the form data on the client (optional) and server, along with some other useful things.

\n
import { z } from \"zod\";\n\nexport const themes = [\"light\", \"dark\"] as const;\nexport const languages = [\"en\", \"es\", \"fr\"] as const;\nexport const allergies = [\"peanuts\", \"dairy\", \"gluten\", \"soy\", \"shellfish\"] as const;\n\nexport const schema = z.object({\n\temail: z.string().email(\"Please enter a valid email.\"),\n\tbio: z.string().optional(),\n\ttheme: z.enum(themes).default(\"light\"),\n\tlanguage: z.enum(languages).default(\"en\"),\n\tmarketingEmails: z.boolean().default(true),\n\tallergies: z.array(z.enum(allergies)),\n});\n
\n

Looking at the schema above, we know we'll need a few different input types to represent the different data types. Here's how we'll map the schema to input types:

\n
    \n
  • email -> <input type=\"email\">
  • \n
  • bio -> <textarea>
  • \n
  • theme -> <input type=\"radio\">
  • \n
  • language -> <select>
  • \n
  • marketingEmails -> <input type=\"checkbox>
  • \n
  • allergies -> <input type=\"checkbox\"> (group/multiple)
  • \n
\n

Of course, there are other ways to represent the data, but this is the approach we'll take for this tutorial.

\n

Return the form from a load function

\n

In Superforms fashion, we'll return the form from a load function to seamlessly merge our PageData and ActionData.

\n
import type { PageServerLoad } from \"./$types\";\nimport { schema } from \"./schema\";\nimport { superValidate } from \"sveltekit-superforms\";\nimport { zod } from \"sveltekit-superforms/adapters\";\n\nexport const load: PageServerLoad = async () => {\n\treturn {\n\t\tform: await superValidate(zod(schema)),\n\t};\n};\n
\n

Setup the form in the page component

\n

Now that we have our form in the PageData object, we can use it, along with the schema we defined earlier, to setup the form in our page component.

\n
<script lang=\"ts\">\n\timport { superForm } from \"sveltekit-superforms\";\n\timport { Field } from \"formsnap\";\n\timport { zodClient } from \"sveltekit-superforms/adapters\";\n\timport { allergies, schema, themes } from \"./schema.js\";\n\timport SuperDebug from \"sveltekit-superforms\";\n\n\tlet { data } = $props();\n\n\tconst form = superForm(data.form, {\n\t\tvalidators: zodClient(schema),\n\t});\n\tconst { form: formData, enhance } = form;\n</script>\n\n<form method=\"POST\" use:enhance>\n\t<!-- ... -->\n</form>\n<SuperDebug data={$formData} />\n
\n

We'll initialize the super form using superForm and pass in the form from the PageData. We'll also enable client-side validation by passing the validators option. Then, we'll setup the form using the enhance function, which will progressively enhance the form with client-side validation and other features.

\n

Constructing a form field

\n

You can think of form fields as the building blocks of your form. Each property of the schema will have a corresponding form field, which will be responsible for displaying the error messages and description.

\n

We'll start with the email field and work our way down.

\n
<script lang=\"ts\">\n\timport { superForm } from \"sveltekit-superforms\";\n\timport { zodClient } from \"sveltekit-superforms/adapters\";\n\timport { allergies, schema, themes } from \"./schema.js\";\n\timport SuperDebug from \"sveltekit-superforms\";\n\n\tlet { data } = $props();\n\n\tconst form = superForm(data.form, {\n\t\tvalidators: zodClient(schema),\n\t});\n\tconst { form: formData, enhance } = form;\n</script>\n\n<form method=\"POST\" use:enhance>\n\t<Field {form} name=\"email\">\n\t\t<!-- ... -->\n\t</Field>\n</form>\n<SuperDebug data={$formData} />\n
\n

We pass the form and name to the Field component, which will be used to setup the context for the field. The name is typed to the keys of the schema, so it's type-safe.

\n

Now let's add the remaining parts of the field:

\n
<script lang=\"ts\">\n\timport { superForm } from \"sveltekit-superforms\";\n\timport { Field, Control, Label, Description, FieldErrors } from \"formsnap\";\n\timport { zodClient } from \"sveltekit-superforms/adapters\";\n\timport { allergies, schema, themes } from \"./schema.js\";\n\timport SuperDebug from \"sveltekit-superforms\";\n\n\tlet { data } = $props();\n\n\tconst form = superForm(data.form, {\n\t\tvalidators: zodClient(schema),\n\t});\n\tconst { form: formData, enhance } = form;\n</script>\n\n<form method=\"POST\" use:enhance>\n\t<Field {form} name=\"email\">\n\t\t<Control>\n\t\t\t{#snippet children({ props })}\n\t\t\t\t<Label>Email</Label>\n\t\t\t\t<input {...props} type=\"email\" bind:value={$formData.email} />\n\t\t\t{/snippet}\n\t\t</Control>\n\t\t<Description>Use your company email if you have one.</Description>\n\t\t<FieldErrors />\n\t</Field>\n</form>\n<SuperDebug data={$formData} />\n
\n

We've first added the Control component. Controls are used to represent a form control and its label. They keep the control and label in sync via the props snippet prop, which is spread onto the control. Inside the Control, we've added the Label component, which will automatically associate itself with the control the props are spread onto. We've also added the control itself, which is an input that we're binding to the email property of the form data.

\n

The Description component is optional, but it's useful for providing additional context to the user about the field. It'll be synced with the aria-describedby attribute on the input, so it's accessible to screen readers.

\n

The FieldErrors component is used to display validation errors to the user. It also is synced with the aria-describedby attribute on the input, which can receive multiple IDs, so that screen readers are able to read the error messages in addition to the description.

\n

And that's really all it takes to setup a form field. Let's continue on with the rest of the fields.

\n

Add remaining form fields

\n
<script lang=\"ts\">\n\timport { superForm } from \"sveltekit-superforms\";\n\timport { Field, Control, Label, Description, FieldErrors, Fieldset, Legend } from \"formsnap\";\n\timport { zodClient } from \"sveltekit-superforms/adapters\";\n\timport { allergies, schema, themes } from \"./schema.js\";\n\timport SuperDebug from \"sveltekit-superforms\";\n\n\tlet { data } = $props();\n\n\tconst form = superForm(data.form, {\n\t\tvalidators: zodClient(schema),\n\t});\n\tconst { form: formData, enhance } = form;\n</script>\n\n<form use:enhance class=\"mx-auto flex max-w-md flex-col\" method=\"POST\">\n\t<Field {form} name=\"email\">\n\t\t<Control>\n\t\t\t{#snippet children({ props })}\n\t\t\t\t<Label>Email</Label>\n\t\t\t\t<input {...props} type=\"email\" bind:value={$formData.email} />\n\t\t\t{/snippet}\n\t\t</Control>\n\t\t<Description>Company email is preferred</Description>\n\t\t<FieldErrors />\n\t</Field>\n\t<Field {form} name=\"bio\">\n\t\t<Control>\n\t\t\t{#snippet children({ props })}\n\t\t\t\t<Label>Bio</Label>\n\t\t\t\t<textarea {...props} bind:value={$formData.bio} />\n\t\t\t{/snippet}\n\t\t</Control>\n\t\t<Description>Tell us a bit about yourself.</Description>\n\t\t<FieldErrors />\n\t</Field>\n\t<Field {form} name=\"language\">\n\t\t<Control>\n\t\t\t{#snippet children({ props })}\n\t\t\t\t<Label>Language</Label>\n\t\t\t\t<select {...props} bind:value={$formData.language}>\n\t\t\t\t\t<option value=\"fr\">French</option>\n\t\t\t\t\t<option value=\"es\">Spanish</option>\n\t\t\t\t\t<option value=\"en\">English</option>\n\t\t\t\t</select>\n\t\t\t{/snippet}\n\t\t</Control>\n\t\t<Description>Help us address you properly.</Description>\n\t\t<FieldErrors />\n\t</Field>\n\t<Fieldset {form} name=\"theme\">\n\t\t<Legend>Select your theme</Legend>\n\t\t{#each themes as theme}\n\t\t\t<Control>\n\t\t\t\t{#snippet children({ props })}\n\t\t\t\t\t<Label>{theme}</Label>\n\t\t\t\t\t<input {...props} type=\"radio\" value={theme} bind:group={$formData.theme} />\n\t\t\t\t{/snippet}\n\t\t\t</Control>\n\t\t{/each}\n\t\t<Description>We prefer dark mode, but the choice is yours.</Description>\n\t\t<FieldErrors />\n\t</Fieldset>\n\t<Field {form} name=\"marketingEmails\">\n\t\t<Control>\n\t\t\t{#snippet children({ props })}\n\t\t\t\t<input {...props} type=\"checkbox\" bind:checked={$formData.marketingEmails} />\n\t\t\t\t<Label>I want to receive marketing emails</Label>\n\t\t\t{/snippet}\n\t\t</Control>\n\t\t<Description>Stay up to date with our latest news and offers.</Description>\n\t\t<FieldErrors />\n\t</Field>\n\t<Fieldset {form} name=\"allergies\">\n\t\t<Legend>Food allergies</Legend>\n\t\t{#each allergies as allergy}\n\t\t\t<Control>\n\t\t\t\t{#snippet children({ props })}\n\t\t\t\t\t<input\n\t\t\t\t\t\t{...props}\n\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\tbind:group={$formData.allergies}\n\t\t\t\t\t\tvalue={allergy}\n\t\t\t\t\t/>\n\t\t\t\t\t<Label>{allergy}</Label>\n\t\t\t\t{/snippet}\n\t\t\t</Control>\n\t\t{/each}\n\t\t<Description>When we provide lunch, we'll accommodate your needs.</Description>\n\t\t<FieldErrors />\n\t</Fieldset>\n\t<button>Submit</button>\n</form>\n<SuperDebug data={$formData} />\n
\n

You may have noticed for the allergies and theme fields, we used the Fieldset and Legend components. These are used to group related fields together and provide a title for the group, which is great for accessibility and organization. Additionally, we only use a single FieldError and Description component for the entire group, and use an Control for each field in the group to associate the label with the control.

\n
\n

And that's it! You've now successfully built a settings form with Formsnap!

\n

Next Steps

\n

Now that you've built your first form, you're ready to start building more complex forms with Formsnap & Superforms. Be sure to check out the rest of the documentation to learn more about the different components and APIs available to you.

", - "raw": "\n\n## Installation\n\nSince Formsnap is built on top of [Superforms](https://superforms.rocks), you'll need to install it as well as a schema validation library of your choice. We'll use [Zod](https://zod.dev).\n\n```bash\nnpm install formsnap sveltekit-superforms zod\n```\n\n## Tutorial: Build a settings form\n\nBefore diving into this tutorial, it's important to be confident with [Superforms](https://superforms.rocks), as Formsnap is built on top of it and uses the same APIs.\n\n\n\nDefine a Zod schema\n\nThis schema will represent the shape of our form data. It's used to validate the form data on the client (optional) and server, along with some other useful things.\n\n```ts title=\"src/routes/settings/schema.ts\"\nimport { z } from \"zod\";\n\nexport const themes = [\"light\", \"dark\"] as const;\nexport const languages = [\"en\", \"es\", \"fr\"] as const;\nexport const allergies = [\"peanuts\", \"dairy\", \"gluten\", \"soy\", \"shellfish\"] as const;\n\nexport const schema = z.object({\n\temail: z.string().email(\"Please enter a valid email.\"),\n\tbio: z.string().optional(),\n\ttheme: z.enum(themes).default(\"light\"),\n\tlanguage: z.enum(languages).default(\"en\"),\n\tmarketingEmails: z.boolean().default(true),\n\tallergies: z.array(z.enum(allergies)),\n});\n```\n\nLooking at the schema above, we know we'll need a few different input types to represent the different data types. Here's how we'll map the schema to input types:\n\n- `email` -> ``\n- `bio` -> `