Skip to content

Commit de831c7

Browse files
committed
Component example.
1 parent caeea3f commit de831c7

File tree

7 files changed

+222
-1
lines changed

7 files changed

+222
-1
lines changed

src/routes/(v1)/proxies/ProxyField.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import type { FormPathLeaves } from '$lib/index.js';
88
import { dateProxy, formFieldProxy, type SuperForm } from '$lib/client/index.js';
99
10-
export let form: SuperForm<T, unknown>;
10+
export let form: SuperForm<T>;
1111
export let field: FormPathLeaves<T>;
1212
export let type:
1313
| 'text'

src/routes/(v2)/v2/Navigation.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
'array-proxy',
55
'boolean-same-union',
66
'catchall',
7+
'components',
78
'custom-tainted-dialog',
89
'defaults-fail',
910
'dynamic-validators',
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { superValidate, message } from '$lib/index.js';
2+
import { zod } from '$lib/adapters/zod.js';
3+
import { registerSchema, profileSchema } from './schema.js';
4+
import { fail } from '@sveltejs/kit';
5+
import type { Actions } from './$types.js';
6+
7+
export const load = async () => {
8+
// Server API:
9+
const regForm = await superValidate(zod(registerSchema));
10+
const profileForm = await superValidate(zod(profileSchema));
11+
12+
return { regForm, profileForm };
13+
};
14+
15+
export const actions = {
16+
register: async ({ request }) => {
17+
const regForm = await superValidate(request, zod(registerSchema));
18+
19+
console.log('register', regForm);
20+
21+
if (!regForm.valid) return fail(400, { regForm });
22+
23+
return message(regForm, { text: 'Form "register" posted successfully!' });
24+
},
25+
26+
edit: async ({ request }) => {
27+
const profileForm = await superValidate(request, zod(profileSchema));
28+
29+
console.log('edit', profileForm);
30+
31+
if (!profileForm.valid) return fail(400, { profileForm });
32+
33+
return message(profileForm, { text: 'Form "profile" posted successfully!' });
34+
}
35+
} satisfies Actions;
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<script lang="ts">
2+
import Form from './Form.svelte';
3+
import TextField from './TextField.svelte';
4+
5+
export let data;
6+
</script>
7+
8+
<h3>Multiple componentized Forms</h3>
9+
<hr />
10+
11+
<h4>Register Form</h4>
12+
13+
<!-- Form with dataType 'form' -->
14+
<Form action="?/register" data={data.regForm} invalidateAll={false} let:form let:message>
15+
{#if message}
16+
<div
17+
class="status"
18+
class:error={message.status >= 400}
19+
class:success={!message.status || message.status < 300}
20+
>
21+
{message.text}
22+
</div>
23+
{/if}
24+
25+
<TextField type="text" {form} field="name" label="Name"></TextField>
26+
<TextField type="text" {form} field="email" label="E-Mail"></TextField>
27+
<p>
28+
<button type="submit">submit</button>
29+
</p>
30+
</Form>
31+
32+
<hr />
33+
34+
<h4>Another Form</h4>
35+
36+
<!-- Form with dataType 'json' -->
37+
<Form
38+
action="?/edit"
39+
data={data?.profileForm}
40+
dataType="json"
41+
invalidateAll={false}
42+
let:form
43+
let:message
44+
>
45+
{#if message}
46+
<div
47+
class="status"
48+
class:error={message.status >= 400}
49+
class:success={!message.status || message.status < 300}
50+
>
51+
{message.text}
52+
</div>
53+
{/if}
54+
<TextField type="text" {form} field="name" label="Name"></TextField>
55+
<TextField type="number" {form} field="age" label="Age"></TextField>
56+
<p>
57+
<button type="submit">submit</button>
58+
</p>
59+
</Form>
60+
61+
<hr />
62+
<p>
63+
<a target="_blank" href="https://Forms.rocks/components"
64+
>Documentation about componentization here</a
65+
>
66+
</p>
67+
68+
<style>
69+
.status {
70+
color: white;
71+
padding: 6px;
72+
padding-left: 8px;
73+
border-radius: 2px;
74+
font-weight: 500;
75+
margin-block: 0.75em;
76+
}
77+
78+
.status.success {
79+
background-color: seagreen;
80+
}
81+
82+
.status.error {
83+
background-color: #ff2a02;
84+
}
85+
86+
hr {
87+
margin: 2rem 0;
88+
}
89+
</style>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<script lang="ts" context="module">
2+
type T = Record<string, unknown>;
3+
type M = unknown;
4+
</script>
5+
6+
<script lang="ts" generics="T extends Record<string, unknown>, M">
7+
import SuperDebug, { type SuperValidated } from '$lib/index.js';
8+
import { superForm } from '$lib/index.js';
9+
10+
export let data: SuperValidated<T, M>;
11+
export let dataType: 'form' | 'json' = 'form';
12+
export let invalidateAll = true; // set to false to keep form data using muliple forms on a page
13+
14+
export const theForm = superForm(data, {
15+
dataType,
16+
invalidateAll,
17+
onUpdated({ form }) {
18+
if (form.valid) {
19+
// Successful post! Do some more client-side stuff.
20+
}
21+
}
22+
});
23+
24+
const { form, message, delayed, errors, allErrors, enhance } = theForm;
25+
</script>
26+
27+
<form method="POST" use:enhance {...$$restProps}>
28+
<slot
29+
form={theForm}
30+
message={$message}
31+
errors={$errors}
32+
allErrors={$allErrors}
33+
delayed={$delayed}
34+
/>
35+
</form>
36+
37+
<SuperDebug data={$form}></SuperDebug>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<script lang="ts" context="module">
2+
type T = Record<string, unknown>;
3+
</script>
4+
5+
<script lang="ts" generics="T extends Record<string, unknown>">
6+
import { formFieldProxy, type SuperForm, type FormPathLeaves } from '$lib/index.js';
7+
8+
let _class = '';
9+
export { _class as class };
10+
11+
export let label = '';
12+
export let field: FormPathLeaves<T>;
13+
export let form: SuperForm<T>;
14+
15+
const { value, errors, constraints } = formFieldProxy(form, field);
16+
</script>
17+
18+
{#if label}
19+
<label class="label" for={field}>{label}</label>
20+
{/if}
21+
<div class="control">
22+
<input
23+
class={'input ' + _class}
24+
name={field}
25+
aria-invalid={$errors ? 'true' : undefined}
26+
placeholder=""
27+
bind:value={$value}
28+
{...$constraints}
29+
{...$$restProps}
30+
/>
31+
</div>
32+
{#if $errors}
33+
<p class="help is-danger">{$errors}</p>
34+
{/if}
35+
36+
<style>
37+
.is-danger {
38+
color: red;
39+
}
40+
41+
input {
42+
background-color: #e7e7e7;
43+
}
44+
45+
input:not(:placeholder-shown):invalid {
46+
box-shadow: inset 0px 0px 3px 1px #f00;
47+
}
48+
</style>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { z } from 'zod';
2+
3+
export const registerSchema = z.object({
4+
name: z.string().min(2),
5+
email: z.string().email()
6+
});
7+
8+
export const profileSchema = z.object({
9+
name: z.string().min(2),
10+
age: z.number().gte(16).default(18)
11+
});

0 commit comments

Comments
 (0)