Skip to content

Commit d50272f

Browse files
committed
Added cardinality inference for SuperStruct.
1 parent ba054f0 commit d50272f

File tree

3 files changed

+193
-1
lines changed

3 files changed

+193
-1
lines changed

src/lib/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,13 @@ type SuperStruct<T extends AnyZodObject, Data> = Partial<{
9393
? SuperStruct<IntersectUnion<UnwrappedEntity<T>>, Data>
9494
: UnwrappedRawShape<T, Property> extends AnyZodObject
9595
? SuperStruct<UnwrappedRawShape<T, Property>, Data>
96-
: UnwrappedRawShape<T, Property> extends ZodArray<infer A>
96+
: UnwrappedRawShape<T, Property> extends ZodArray<
97+
infer A,
98+
// Need to infer Cardinality for extend to work correctly, even though it's unused.
99+
// (nonempty changes the cardinality of arrays in the schema)
100+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
101+
infer Cardinality
102+
>
97103
? UnwrappedEntity<A> extends ZodUnion<ZodUnionOptions>
98104
? SuperStruct<IntersectUnion<UnwrappedEntity<A>>, Data>
99105
: UnwrappedEntity<A> extends AnyZodObject
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { superValidate, message, setError } from '$lib/server';
2+
import { fail } from '@sveltejs/kit';
3+
import { z } from 'zod';
4+
5+
import type { Actions, PageServerLoad } from './$types';
6+
7+
/*
8+
type FormType = {
9+
name: any;
10+
email: any;
11+
days: any;
12+
};
13+
*/
14+
15+
const raw = {
16+
name: z.string().min(1),
17+
email: z.string().email(),
18+
days: z.number().min(0).max(6).array().nonempty()
19+
};
20+
21+
type FormTypeOk = typeof raw;
22+
23+
type FormType = {
24+
name: any;
25+
email: any;
26+
days: z.ZodArray<z.ZodNumber, 'atleastone'>;
27+
};
28+
29+
const schema = z.object<FormType>({
30+
name: z.string().min(1),
31+
email: z.string().email(),
32+
days: z.number().min(0).max(6).array().nonempty()
33+
});
34+
35+
///// Load function /////
36+
37+
export const load: PageServerLoad = async () => {
38+
const form = await superValidate(schema);
39+
return { form };
40+
};
41+
42+
///// Form actions /////
43+
44+
export const actions: Actions = {
45+
default: async ({ request }) => {
46+
const form = await superValidate(request, schema);
47+
48+
const data = form.data;
49+
50+
if (!data.days?.length) {
51+
setError(form, 'days._errors', 'You have to select at least one day!');
52+
}
53+
54+
console.log('POST', form);
55+
56+
if (!form.valid) return fail(400, { form });
57+
58+
return message(form, 'Form posted successfully!');
59+
}
60+
};
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<script lang="ts">
2+
import { page } from '$app/stores';
3+
import { superForm } from '$lib/client';
4+
import SuperDebug from '$lib/client/SuperDebug.svelte';
5+
6+
export let data;
7+
8+
const Days = [
9+
'Saturday',
10+
'Sunday',
11+
'Monday',
12+
'Tuesday',
13+
'Wednesday',
14+
'Thursday',
15+
'Friday'
16+
];
17+
18+
const { form, errors, message, constraints, enhance } = superForm(
19+
data.form
20+
);
21+
</script>
22+
23+
<SuperDebug data={$form} />
24+
25+
<h3>Superforms testing ground</h3>
26+
27+
{#if $message}
28+
<div
29+
class="status"
30+
class:error={$page.status >= 400}
31+
class:success={$page.status == 200}
32+
>
33+
{$message}
34+
</div>
35+
{/if}
36+
37+
<form method="POST" use:enhance>
38+
<label>
39+
Name<br />
40+
<input
41+
name="name"
42+
aria-invalid={$errors.name ? 'true' : undefined}
43+
bind:value={$form.name}
44+
/>
45+
{#if $errors.name}<span class="invalid">{$errors.name}</span>{/if}
46+
</label>
47+
48+
<label>
49+
Email<br />
50+
<input
51+
name="email"
52+
type="email"
53+
aria-invalid={$errors.email ? 'true' : undefined}
54+
bind:value={$form.email}
55+
/>
56+
{#if $errors.email}<span class="invalid">{$errors.email}</span>{/if}
57+
</label>
58+
59+
<div class="checkboxes">
60+
{#each Days as day, i}
61+
<div class="checkbox">
62+
<input
63+
id="wday-{i}"
64+
type="checkbox"
65+
name="days"
66+
value={i}
67+
bind:group={$form.days}
68+
class="w-4 h-4 text-skin-accent bg-skin-fg rounded focus:ring-skin-accent focus:ring-2 cursor-pointer"
69+
/>
70+
<label for="wday-{i}" class="ml-2 text-sm font-medium cursor-pointer"
71+
>{day}</label
72+
>
73+
</div>
74+
{/each}
75+
</div>
76+
<p class="invalid">{$errors.days?._errors || 'No error'}</p>
77+
<button>Submit</button>
78+
</form>
79+
80+
<hr />
81+
<p>
82+
<a target="_blank" href="https://superforms.rocks/api">API Reference</a>
83+
</p>
84+
85+
<style>
86+
.invalid {
87+
color: red;
88+
}
89+
90+
.status {
91+
color: white;
92+
padding: 4px;
93+
padding-left: 8px;
94+
border-radius: 2px;
95+
font-weight: 500;
96+
}
97+
98+
.status.success {
99+
background-color: seagreen;
100+
}
101+
102+
.status.error {
103+
background-color: #ff2a02;
104+
}
105+
106+
input {
107+
background-color: #ddd;
108+
}
109+
110+
a {
111+
text-decoration: underline;
112+
}
113+
114+
hr {
115+
margin-top: 4rem;
116+
}
117+
118+
form {
119+
padding-top: 1rem;
120+
padding-bottom: 1rem;
121+
}
122+
.checkboxes,
123+
.checkbox {
124+
display: flex;
125+
}
126+
</style>

0 commit comments

Comments
 (0)