62 lines
1.4 KiB
Svelte
62 lines
1.4 KiB
Svelte
<script lang="ts">
|
|
import { createMachine, interpret } from 'xstate';
|
|
import { writable } from 'svelte/store';
|
|
|
|
export let form;
|
|
export let errors;
|
|
export let validate;
|
|
export let field;
|
|
export let constraints;
|
|
|
|
const machine = createMachine({
|
|
id: 'field',
|
|
initial: 'notValid',
|
|
states: {
|
|
notValid: {
|
|
on: {
|
|
VALIDATE: 'valid'
|
|
}
|
|
},
|
|
valid: {
|
|
on: {
|
|
INVALIDATE: 'notValid'
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
const service = interpret(machine);
|
|
service.start();
|
|
|
|
const state = writable(service.state.value);
|
|
|
|
form.subscribe(async (value) => {
|
|
const validationResult = await validate();
|
|
if (validationResult.valid) {
|
|
service.send('VALIDATE');
|
|
} else {
|
|
service.send('INVALIDATE');
|
|
}
|
|
state.set(service.state.value);
|
|
});
|
|
</script>
|
|
|
|
<div class="mb-4">
|
|
{#if $errors[field.name]}
|
|
<span class="block mb-2 font-semibold text-red-500">{$errors[field.name]}</span>
|
|
{:else}
|
|
<label for={field.name} class="block mb-2 font-semibold text-white"
|
|
>{field.name.charAt(0).toUpperCase() + field.name.slice(1)}</label
|
|
>
|
|
{/if}
|
|
|
|
<input
|
|
name={field.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[field.name]}
|
|
aria-invalid={$errors[field.name] ? 'true' : undefined}
|
|
{...constraints[field.name]}
|
|
/>
|
|
</div>
|