added a basic realtime validation example
This commit is contained in:
parent
47d26f8c46
commit
9c08a2cf11
@ -20,6 +20,7 @@
|
||||
"@skeletonlabs/skeleton": "^1.10.0",
|
||||
"@sveltejs/adapter-auto": "^2.0.0",
|
||||
"@sveltejs/kit": "^1.20.4",
|
||||
"@tailwindcss/forms": "^0.5.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||
"@typescript-eslint/parser": "^5.45.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
@ -31,11 +32,13 @@
|
||||
"prettier-plugin-svelte": "^2.10.1",
|
||||
"svelte": "^4.0.5",
|
||||
"svelte-check": "^3.4.3",
|
||||
"sveltekit-superforms": "^1.5.0",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^4.4.2",
|
||||
"vitest": "^0.32.2"
|
||||
"vitest": "^0.32.2",
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
@ -30,10 +30,10 @@ dependencies:
|
||||
version: 2.4.3(svelte@4.1.1)(vite@4.4.7)
|
||||
'@wagmi/core':
|
||||
specifier: ^1.3.8
|
||||
version: 1.3.8(react@18.2.0)(typescript@5.1.6)(viem@1.4.1)
|
||||
version: 1.3.8(react@18.2.0)(typescript@5.1.6)(viem@1.4.1)(zod@3.21.4)
|
||||
viem:
|
||||
specifier: ^1.3.0
|
||||
version: 1.4.1(typescript@5.1.6)
|
||||
version: 1.4.1(typescript@5.1.6)(zod@3.21.4)
|
||||
|
||||
devDependencies:
|
||||
'@iconify/svelte':
|
||||
@ -51,6 +51,9 @@ devDependencies:
|
||||
'@sveltejs/kit':
|
||||
specifier: ^1.20.4
|
||||
version: 1.22.3(svelte@4.1.1)(vite@4.4.7)
|
||||
'@tailwindcss/forms':
|
||||
specifier: ^0.5.4
|
||||
version: 0.5.4(tailwindcss@3.3.3)
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: ^5.45.0
|
||||
version: 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.45.0)(typescript@5.1.6)
|
||||
@ -84,6 +87,9 @@ devDependencies:
|
||||
svelte-check:
|
||||
specifier: ^3.4.3
|
||||
version: 3.4.6(postcss@8.4.27)(svelte@4.1.1)
|
||||
sveltekit-superforms:
|
||||
specifier: ^1.5.0
|
||||
version: 1.5.0(@sveltejs/kit@1.22.3)(svelte@4.1.1)(zod@3.21.4)
|
||||
tailwindcss:
|
||||
specifier: ^3.3.3
|
||||
version: 3.3.3
|
||||
@ -99,6 +105,9 @@ devDependencies:
|
||||
vitest:
|
||||
specifier: ^0.32.2
|
||||
version: 0.32.4
|
||||
zod:
|
||||
specifier: ^3.21.4
|
||||
version: 3.21.4
|
||||
|
||||
packages:
|
||||
|
||||
@ -1845,10 +1854,10 @@ packages:
|
||||
resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==}
|
||||
dev: false
|
||||
|
||||
/@safe-global/safe-apps-provider@0.17.1(typescript@5.1.6):
|
||||
/@safe-global/safe-apps-provider@0.17.1(typescript@5.1.6)(zod@3.21.4):
|
||||
resolution: {integrity: sha512-lYfRqrbbK1aKU1/UGkYWc/X7PgySYcumXKc5FB2uuwAs2Ghj8uETuW5BrwPqyjBknRxutFbTv+gth/JzjxAhdQ==}
|
||||
dependencies:
|
||||
'@safe-global/safe-apps-sdk': 8.0.0(typescript@5.1.6)
|
||||
'@safe-global/safe-apps-sdk': 8.0.0(typescript@5.1.6)(zod@3.21.4)
|
||||
events: 3.3.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
@ -1858,11 +1867,11 @@ packages:
|
||||
- zod
|
||||
dev: false
|
||||
|
||||
/@safe-global/safe-apps-sdk@8.0.0(typescript@5.1.6):
|
||||
/@safe-global/safe-apps-sdk@8.0.0(typescript@5.1.6)(zod@3.21.4):
|
||||
resolution: {integrity: sha512-gYw0ki/EAuV1oSyMxpqandHjnthZjYYy+YWpTAzf8BqfXM3ItcZLpjxfg+3+mXW8HIO+3jw6T9iiqEXsqHaMMw==}
|
||||
dependencies:
|
||||
'@safe-global/safe-gateway-typescript-sdk': 3.7.3
|
||||
viem: 1.4.1(typescript@5.1.6)
|
||||
viem: 1.4.1(typescript@5.1.6)(zod@3.21.4)
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- encoding
|
||||
@ -2184,6 +2193,15 @@ packages:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
/@tailwindcss/forms@0.5.4(tailwindcss@3.3.3):
|
||||
resolution: {integrity: sha512-YAm12D3R7/9Mh4jFbYSMnsd6jG++8KxogWgqs7hbdo/86aWjjlIEvL7+QYdVELmAI0InXTpZqFIg5e7aDVWI2Q==}
|
||||
peerDependencies:
|
||||
tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1'
|
||||
dependencies:
|
||||
mini-svg-data-uri: 1.4.4
|
||||
tailwindcss: 3.3.3
|
||||
dev: true
|
||||
|
||||
/@types/chai-subset@1.3.3:
|
||||
resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==}
|
||||
dependencies:
|
||||
@ -2433,7 +2451,7 @@ packages:
|
||||
typescript: 5.1.6
|
||||
dev: false
|
||||
|
||||
/@wagmi/connectors@2.6.6(@wagmi/chains@1.6.0)(react@18.2.0)(typescript@5.1.6)(viem@1.4.1):
|
||||
/@wagmi/connectors@2.6.6(@wagmi/chains@1.6.0)(react@18.2.0)(typescript@5.1.6)(viem@1.4.1)(zod@3.21.4):
|
||||
resolution: {integrity: sha512-/o1c/TCivQs8DOAUOcQvY2UIt3p2mWOAHi39D0LC74+ncpXzLC5/gyaWU38qnTxPM8s/PmTmaWDgz+VhICXrag==}
|
||||
peerDependencies:
|
||||
'@wagmi/chains': '>=1.3.0'
|
||||
@ -2447,17 +2465,17 @@ packages:
|
||||
dependencies:
|
||||
'@coinbase/wallet-sdk': 3.7.1
|
||||
'@ledgerhq/connect-kit-loader': 1.1.0
|
||||
'@safe-global/safe-apps-provider': 0.17.1(typescript@5.1.6)
|
||||
'@safe-global/safe-apps-sdk': 8.0.0(typescript@5.1.6)
|
||||
'@safe-global/safe-apps-provider': 0.17.1(typescript@5.1.6)(zod@3.21.4)
|
||||
'@safe-global/safe-apps-sdk': 8.0.0(typescript@5.1.6)(zod@3.21.4)
|
||||
'@wagmi/chains': 1.6.0(typescript@5.1.6)
|
||||
'@walletconnect/ethereum-provider': 2.9.0(@walletconnect/modal@2.5.9)
|
||||
'@walletconnect/legacy-provider': 2.0.0
|
||||
'@walletconnect/modal': 2.5.9(react@18.2.0)
|
||||
'@walletconnect/utils': 2.9.0
|
||||
abitype: 0.8.7(typescript@5.1.6)
|
||||
abitype: 0.8.7(typescript@5.1.6)(zod@3.21.4)
|
||||
eventemitter3: 4.0.7
|
||||
typescript: 5.1.6
|
||||
viem: 1.4.1(typescript@5.1.6)
|
||||
viem: 1.4.1(typescript@5.1.6)(zod@3.21.4)
|
||||
transitivePeerDependencies:
|
||||
- '@react-native-async-storage/async-storage'
|
||||
- bufferutil
|
||||
@ -2469,7 +2487,7 @@ packages:
|
||||
- zod
|
||||
dev: false
|
||||
|
||||
/@wagmi/core@1.3.8(react@18.2.0)(typescript@5.1.6)(viem@1.4.1):
|
||||
/@wagmi/core@1.3.8(react@18.2.0)(typescript@5.1.6)(viem@1.4.1)(zod@3.21.4):
|
||||
resolution: {integrity: sha512-OYSxikoMizqVnpSkFTwGE7PwFaz2k0PXteSiI0W2Mtk4j4sZzRFdP+9AWeDB6AYm0yU3WvgN1IATx0EEBKUe3w==}
|
||||
peerDependencies:
|
||||
typescript: '>=5.0.4'
|
||||
@ -2479,11 +2497,11 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@wagmi/chains': 1.6.0(typescript@5.1.6)
|
||||
'@wagmi/connectors': 2.6.6(@wagmi/chains@1.6.0)(react@18.2.0)(typescript@5.1.6)(viem@1.4.1)
|
||||
abitype: 0.8.7(typescript@5.1.6)
|
||||
'@wagmi/connectors': 2.6.6(@wagmi/chains@1.6.0)(react@18.2.0)(typescript@5.1.6)(viem@1.4.1)(zod@3.21.4)
|
||||
abitype: 0.8.7(typescript@5.1.6)(zod@3.21.4)
|
||||
eventemitter3: 4.0.7
|
||||
typescript: 5.1.6
|
||||
viem: 1.4.1(typescript@5.1.6)
|
||||
viem: 1.4.1(typescript@5.1.6)(zod@3.21.4)
|
||||
zustand: 4.3.9(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- '@react-native-async-storage/async-storage'
|
||||
@ -3250,7 +3268,7 @@ packages:
|
||||
through: 2.3.8
|
||||
dev: false
|
||||
|
||||
/abitype@0.8.7(typescript@5.1.6):
|
||||
/abitype@0.8.7(typescript@5.1.6)(zod@3.21.4):
|
||||
resolution: {integrity: sha512-wQ7hV8Yg/yKmGyFpqrNZufCxbszDe5es4AZGYPBitocfSqXtjrTG9JMWFcc4N30ukl2ve48aBTwt7NJxVQdU3w==}
|
||||
peerDependencies:
|
||||
typescript: '>=5.0.4'
|
||||
@ -3260,9 +3278,10 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
typescript: 5.1.6
|
||||
zod: 3.21.4
|
||||
dev: false
|
||||
|
||||
/abitype@0.9.3(typescript@5.1.6):
|
||||
/abitype@0.9.3(typescript@5.1.6)(zod@3.21.4):
|
||||
resolution: {integrity: sha512-dz4qCQLurx97FQhnb/EIYTk/ldQ+oafEDUqC0VVIeQS1Q48/YWt/9YNfMmp9SLFqN41ktxny3c8aYxHjmFIB/w==}
|
||||
peerDependencies:
|
||||
typescript: '>=5.0.4'
|
||||
@ -3274,6 +3293,7 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
typescript: 5.1.6
|
||||
zod: 3.21.4
|
||||
dev: false
|
||||
|
||||
/acorn-jsx@5.3.2(acorn@8.10.0):
|
||||
@ -5281,6 +5301,11 @@ packages:
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/mini-svg-data-uri@1.4.4:
|
||||
resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/minimalistic-assert@1.0.1:
|
||||
resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
|
||||
dev: false
|
||||
@ -6540,6 +6565,18 @@ packages:
|
||||
magic-string: 0.30.1
|
||||
periscopic: 3.1.0
|
||||
|
||||
/sveltekit-superforms@1.5.0(@sveltejs/kit@1.22.3)(svelte@4.1.1)(zod@3.21.4):
|
||||
resolution: {integrity: sha512-c/2v6zN9rtIAsOfsd6rBV7Kf0lB2+/o6sAFaOuMrYPlTBro5lpbz3iN/3nM5D3EuLE2Xt/iDdZYpkQdH8rq4nQ==}
|
||||
peerDependencies:
|
||||
'@sveltejs/kit': 1.x
|
||||
svelte: 3.x || 4.x
|
||||
zod: 3.x
|
||||
dependencies:
|
||||
'@sveltejs/kit': 1.22.3(svelte@4.1.1)(vite@4.4.7)
|
||||
svelte: 4.1.1
|
||||
zod: 3.21.4
|
||||
dev: true
|
||||
|
||||
/symbol-observable@2.0.3:
|
||||
resolution: {integrity: sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA==}
|
||||
engines: {node: '>=0.10'}
|
||||
@ -6841,7 +6878,7 @@ packages:
|
||||
resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==}
|
||||
dev: false
|
||||
|
||||
/viem@1.4.1(typescript@5.1.6):
|
||||
/viem@1.4.1(typescript@5.1.6)(zod@3.21.4):
|
||||
resolution: {integrity: sha512-MtaoBHDSJDqa+QyXKG5d+S6EQSebRO0tzw6anSP4zC7AbC614vMeg9Y8LbkmEkWCw8swFYkort+H9l7GkWB0uA==}
|
||||
peerDependencies:
|
||||
typescript: '>=5.0.4'
|
||||
@ -6855,7 +6892,7 @@ packages:
|
||||
'@scure/bip32': 1.3.0
|
||||
'@scure/bip39': 1.2.0
|
||||
'@wagmi/chains': 1.6.0(typescript@5.1.6)
|
||||
abitype: 0.9.3(typescript@5.1.6)
|
||||
abitype: 0.9.3(typescript@5.1.6)(zod@3.21.4)
|
||||
isomorphic-ws: 5.0.0(ws@8.12.0)
|
||||
typescript: 5.1.6
|
||||
ws: 8.12.0
|
||||
@ -7175,6 +7212,9 @@ packages:
|
||||
engines: {node: '>=12.20'}
|
||||
dev: true
|
||||
|
||||
/zod@3.21.4:
|
||||
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
|
||||
|
||||
/zustand@4.3.9(react@18.2.0):
|
||||
resolution: {integrity: sha512-Tat5r8jOMG1Vcsj8uldMyqYKC5IZvQif8zetmLHs9WoZlntTHmIoNM8TpLRY31ExncuUvUOXehd0kvahkuHjDw==}
|
||||
engines: {node: '>=12.7.0'}
|
||||
|
81
src/lib/components/Flows.svelte
Normal file
81
src/lib/components/Flows.svelte
Normal file
@ -0,0 +1,81 @@
|
||||
<script>
|
||||
import { Stepper, Step } from '@skeletonlabs/skeleton';
|
||||
import { form, field } from 'svelte-forms';
|
||||
import { required, between } from 'svelte-forms/validators';
|
||||
|
||||
let step = 1;
|
||||
let name = '';
|
||||
let age = '';
|
||||
let flowData = {};
|
||||
|
||||
const handleNextStep = () => {
|
||||
if (step === 1 && name.trim() === '') {
|
||||
alert('Please enter a valid name.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (step === 2 && age.trim() === '') {
|
||||
alert('Please enter a valid age.');
|
||||
return;
|
||||
}
|
||||
|
||||
step += 1;
|
||||
};
|
||||
|
||||
const handlePrevStep = () => {
|
||||
step -= 1;
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
flowData = {
|
||||
name,
|
||||
age
|
||||
};
|
||||
alert('Flow data confirmed: ' + JSON.stringify(flowData));
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
step = 1;
|
||||
name = '';
|
||||
age = '';
|
||||
flowData = {};
|
||||
};
|
||||
</script>
|
||||
|
||||
<Stepper start={step - 1}>
|
||||
<Step>
|
||||
<svelte:fragment slot="header">Step 1: Name</svelte:fragment>
|
||||
<div>
|
||||
<label for="name">Name:</label>
|
||||
<input class="text-black" type="text" id="name" bind:value={name} />
|
||||
</div>
|
||||
<div slot="navigation">
|
||||
<button class="btn variant-ghost" on:click={handleNextStep}>Next</button>
|
||||
</div>
|
||||
</Step>
|
||||
<Step>
|
||||
<svelte:fragment slot="header">Step 2: Age</svelte:fragment>
|
||||
<div>
|
||||
<label for="age">Age:</label>
|
||||
<input class="text-black" type="number" id="age" bind:value={age} />
|
||||
</div>
|
||||
<div slot="navigation">
|
||||
<button class="btn variant-ghost" on:click={handlePrevStep}>Previous</button>
|
||||
<button class="btn variant-ghost" on:click={handleNextStep}>Next</button>
|
||||
</div>
|
||||
</Step>
|
||||
<Step>
|
||||
<svelte:fragment slot="header">Step 3: Confirm Summary</svelte:fragment>
|
||||
<div>
|
||||
<h3>Confirm Summary:</h3>
|
||||
<p>Name: {name}</p>
|
||||
<p>Age: {age}</p>
|
||||
</div>
|
||||
<div slot="navigation">
|
||||
<button class="btn variant-ghost" on:click={handlePrevStep}>Previous</button>
|
||||
<button class="btn variant-ghost-primary" on:click={handleConfirm}>Confirm</button>
|
||||
</div>
|
||||
</Step>
|
||||
</Stepper>
|
||||
|
||||
<button on:click={handleReset}>Reset</button>
|
5
src/lib/types/UserSchema.ts
Normal file
5
src/lib/types/UserSchema.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const UserSchema = z.object({
|
||||
name: z.string().min(3).max(10)
|
||||
});
|
@ -11,9 +11,10 @@
|
||||
},
|
||||
layout: {
|
||||
areas: `
|
||||
"main"
|
||||
"footer";
|
||||
"main aside"
|
||||
"footer footer";
|
||||
`,
|
||||
columns: '1fr 1fr',
|
||||
rows: '1fr auto'
|
||||
},
|
||||
children: [
|
||||
@ -34,6 +35,11 @@
|
||||
},
|
||||
services: ['helloEarthAlert']
|
||||
},
|
||||
{
|
||||
id: 'testflows',
|
||||
component: 'Flows',
|
||||
slot: 'aside'
|
||||
},
|
||||
{
|
||||
id: 'terminal',
|
||||
component: 'Terminal',
|
||||
|
56
src/routes/validation/+page.svelte
Normal file
56
src/routes/validation/+page.svelte
Normal file
@ -0,0 +1,56 @@
|
||||
<script lang="ts">
|
||||
import { superForm } from 'sveltekit-superforms/client';
|
||||
import { UserSchema } from '$lib/types/UserSchema';
|
||||
|
||||
const initialFormData = { name: '' };
|
||||
|
||||
const { form, errors, validate, constraints } = superForm(initialFormData, {
|
||||
validators: UserSchema,
|
||||
warnings: {
|
||||
noValidationAndConstraints: false
|
||||
},
|
||||
validationMethod: 'oninput' // Trigger validation on input events
|
||||
});
|
||||
|
||||
async function handleSubmit() {
|
||||
// Manually validate the form
|
||||
const validationResult = await validate();
|
||||
|
||||
// Prevent submission if there are errors
|
||||
if (!validationResult.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Here, we'll just log the form data
|
||||
console.log(form);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex items-center justify-center min-h-screen">
|
||||
<form on:submit|preventDefault={handleSubmit} class="w-full max-w-md">
|
||||
<div class="mb-4">
|
||||
{#if $errors.name}
|
||||
<span class="block mb-2 font-semibold text-red-500">{$errors.name}</span>
|
||||
{:else}
|
||||
<label for="name" class="block mb-2 font-semibold text-white">Name</label>
|
||||
{/if}
|
||||
|
||||
<input
|
||||
name="name"
|
||||
type="text"
|
||||
class="w-full px-3 py-2 bg-transparent border-gray-100 rounded-md border-1 ring-0 ring-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
bind:value={$form.name}
|
||||
aria-invalid={$errors.name ? 'true' : undefined}
|
||||
{...constraints.name}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full px-4 py-2 text-white bg-blue-500 rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
disabled={$errors.name}
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
@ -16,6 +16,7 @@ module.exports = {
|
||||
},
|
||||
plugins: [
|
||||
// 3. Append the Skeleton plugin to the end of this list
|
||||
require('@tailwindcss/forms'),
|
||||
...require('@skeletonlabs/skeleton/tailwind/skeleton.cjs')()
|
||||
]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user