@formisch/svelte 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +9 -0
- package/README.md +81 -0
- package/dist/components/Field/Field.svelte +31 -0
- package/dist/components/Field/Field.svelte.d.ts +36 -0
- package/dist/components/Field/index.d.ts +1 -0
- package/dist/components/Field/index.js +1 -0
- package/dist/components/FieldArray/FieldArray.svelte +36 -0
- package/dist/components/FieldArray/FieldArray.svelte.d.ts +36 -0
- package/dist/components/FieldArray/index.d.ts +1 -0
- package/dist/components/FieldArray/index.js +1 -0
- package/dist/components/Form/Form.svelte +28 -0
- package/dist/components/Form/Form.svelte.d.ts +33 -0
- package/dist/components/Form/index.d.ts +1 -0
- package/dist/components/Form/index.js +1 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.js +3 -0
- package/dist/core/index.svelte.d.ts +256 -0
- package/dist/core/index.svelte.js +445 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +4 -0
- package/dist/methods/index.svelte.d.ts +127 -0
- package/dist/methods/index.svelte.js +211 -0
- package/dist/runes/createForm/createForm.svelte.d.ts +3 -0
- package/dist/runes/createForm/createForm.svelte.js +38 -0
- package/dist/runes/createForm/index.d.ts +1 -0
- package/dist/runes/createForm/index.js +1 -0
- package/dist/runes/index.d.ts +3 -0
- package/dist/runes/index.js +3 -0
- package/dist/runes/useField/index.d.ts +1 -0
- package/dist/runes/useField/index.js +1 -0
- package/dist/runes/useField/useField.svelte.d.ts +7 -0
- package/dist/runes/useField/useField.svelte.js +58 -0
- package/dist/runes/useFieldArray/index.d.ts +1 -0
- package/dist/runes/useFieldArray/index.js +1 -0
- package/dist/runes/useFieldArray/useFieldArray.svelte.d.ts +7 -0
- package/dist/runes/useFieldArray/useFieldArray.svelte.js +29 -0
- package/dist/types/field.d.ts +38 -0
- package/dist/types/field.js +1 -0
- package/dist/types/form.d.ts +10 -0
- package/dist/types/form.js +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.js +3 -0
- package/dist/types/utils.d.ts +4 -0
- package/dist/types/utils.js +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/unwrap/index.d.ts +1 -0
- package/dist/utils/unwrap/index.js +1 -0
- package/dist/utils/unwrap/unwrap.d.ts +2 -0
- package/dist/utils/unwrap/unwrap.js +6 -0
- package/package.json +75 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Fabian Hiller
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Formisch for Svelte
|
|
2
|
+
|
|
3
|
+
Formisch is a schema-based, headless form library for Svelte. It manages form state and validation. It is type-safe, fast by default and its bundle size is small due to its modular design. Try it out in our [playground](https://stackblitz.com/edit/formisch-playground-svelte)!
|
|
4
|
+
|
|
5
|
+
Formisch is also available for [Preact][formisch-preact], [Qwik][formisch-qwik], [SolidJS][formisch-solid], and [Vue][formisch-vue].
|
|
6
|
+
|
|
7
|
+
## Highlights
|
|
8
|
+
|
|
9
|
+
- Small bundle size starting at 2.5 kB
|
|
10
|
+
- Schema-based validation with Valibot
|
|
11
|
+
- Type safety with autocompletion in editor
|
|
12
|
+
- It's fast – DOM updates are fine-grained
|
|
13
|
+
- Minimal, readable and well thought out API
|
|
14
|
+
- Supports all native HTML form fields
|
|
15
|
+
|
|
16
|
+
## Example
|
|
17
|
+
|
|
18
|
+
Every form starts with the `createForm` function. It initializes your form's store based on the provided Valibot schema and infers its types. Next, wrap your form in the `<Form />` component. It's a thin layer around the native `<form />` element that handles form validation and submission. Then, you can access the state of a field with the `useField` function or the `<Field />` component to connect your inputs.
|
|
19
|
+
|
|
20
|
+
```svelte
|
|
21
|
+
<script lang="ts">
|
|
22
|
+
import { createForm, Field, Form } from '@formisch/svelte';
|
|
23
|
+
import * as v from 'valibot';
|
|
24
|
+
|
|
25
|
+
const LoginSchema = v.object({
|
|
26
|
+
email: v.pipe(v.string(), v.email()),
|
|
27
|
+
password: v.pipe(v.string(), v.minLength(8)),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const loginForm = createForm({ schema: LoginSchema });
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<Form of={loginForm} onsubmit={(output) => console.log(output)}>
|
|
34
|
+
<Field of={loginForm} path={['email']}>
|
|
35
|
+
{#snippet children(field)}
|
|
36
|
+
<div>
|
|
37
|
+
<input {...field.props} value={field.input} type="email" />
|
|
38
|
+
{#if field.errors}
|
|
39
|
+
<div>{field.errors[0]}</div>
|
|
40
|
+
{/if}
|
|
41
|
+
</div>
|
|
42
|
+
{/snippet}
|
|
43
|
+
</Field>
|
|
44
|
+
<Field of={loginForm} path={['password']}>
|
|
45
|
+
{#snippet children(field)}
|
|
46
|
+
<div>
|
|
47
|
+
<input {...field.props} value={field.input} type="password" />
|
|
48
|
+
{#if field.errors}
|
|
49
|
+
<div>{field.errors[0]}</div>
|
|
50
|
+
{/if}
|
|
51
|
+
</div>
|
|
52
|
+
{/snippet}
|
|
53
|
+
</Field>
|
|
54
|
+
<button type="submit">Login</button>
|
|
55
|
+
</Form>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
In addition, Formisch offers several functions (we call them "methods") that can be used to read and manipulate the form state. These include `focus`, `getErrors`, `getAllErrors`, `getInput`, `insert`, `move`, `remove`, `replace`, `reset`, `setErrors`, `setInput`, `submit`, `swap` and `validate`. These methods allow you to control the form programmatically.
|
|
59
|
+
|
|
60
|
+
## Comparison
|
|
61
|
+
|
|
62
|
+
What makes Formisch unique is its framework-agnostic core, which is fully native to the framework you are using. It works by inserting framework-specific reactivity blocks when the core package is built. The result is a small bundle size and native performance for any UI update. This feature, along with a few others, distinguishes Formisch from other form libraries. My vision for Formisch is to create a framework-agnostic platform similar to [Vite](https://vite.dev/), but for forms.
|
|
63
|
+
|
|
64
|
+
## Partners
|
|
65
|
+
|
|
66
|
+
Thanks to our partners who support the development! [Join them](https://github.com/sponsors/fabian-hiller) and contribute to the sustainability of open source software!
|
|
67
|
+
|
|
68
|
+

|
|
69
|
+
|
|
70
|
+
## Feedback
|
|
71
|
+
|
|
72
|
+
Find a bug or have an idea how to improve the library? Please fill out an [issue](https://github.com/fabian-hiller/formisch/issues/new). Together we can make forms even better!
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
This project is available free of charge and licensed under the [MIT license](https://github.com/fabian-hiller/formisch/blob/main/LICENSE.md).
|
|
77
|
+
|
|
78
|
+
[formisch-preact]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/preact
|
|
79
|
+
[formisch-qwik]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/qwik
|
|
80
|
+
[formisch-solid]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/solid
|
|
81
|
+
[formisch-vue]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/vue
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<script
|
|
2
|
+
lang="ts"
|
|
3
|
+
generics="TSchema extends Schema, TFieldPath extends RequiredPath"
|
|
4
|
+
>
|
|
5
|
+
import type { RequiredPath, Schema, ValidPath } from '../../core/index.svelte';
|
|
6
|
+
import type * as v from 'valibot';
|
|
7
|
+
import { useField } from '../../runes/index';
|
|
8
|
+
import type { FieldStore, FormStore } from '../../types/index';
|
|
9
|
+
import type { Snippet } from 'svelte';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Properties of the `Field` component.
|
|
13
|
+
*/
|
|
14
|
+
export interface FieldProps<
|
|
15
|
+
TSchema extends Schema = Schema,
|
|
16
|
+
TFieldPath extends RequiredPath = RequiredPath,
|
|
17
|
+
> {
|
|
18
|
+
readonly of: FormStore<TSchema>;
|
|
19
|
+
readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
|
|
20
|
+
readonly children: Snippet<[FieldStore<TSchema, TFieldPath>]>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let { of, path, children }: FieldProps<TSchema, TFieldPath> = $props();
|
|
24
|
+
|
|
25
|
+
const field = useField(
|
|
26
|
+
() => of,
|
|
27
|
+
() => ({ path })
|
|
28
|
+
);
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
{@render children(field)}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { RequiredPath, Schema, ValidPath } from '../../core/index.svelte';
|
|
2
|
+
import type * as v from 'valibot';
|
|
3
|
+
import type { FieldStore, FormStore } from '../../types/index.ts';
|
|
4
|
+
import type { Snippet } from 'svelte';
|
|
5
|
+
/**
|
|
6
|
+
* Properties of the `Field` component.
|
|
7
|
+
*/
|
|
8
|
+
export interface FieldProps<TSchema extends Schema = Schema, TFieldPath extends RequiredPath = RequiredPath> {
|
|
9
|
+
readonly of: FormStore<TSchema>;
|
|
10
|
+
readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
|
|
11
|
+
readonly children: Snippet<[FieldStore<TSchema, TFieldPath>]>;
|
|
12
|
+
}
|
|
13
|
+
declare function $$render<TSchema extends Schema, TFieldPath extends RequiredPath>(): {
|
|
14
|
+
props: FieldProps<TSchema, TFieldPath>;
|
|
15
|
+
exports: {};
|
|
16
|
+
bindings: "";
|
|
17
|
+
slots: {};
|
|
18
|
+
events: {};
|
|
19
|
+
};
|
|
20
|
+
declare class __sveltets_Render<TSchema extends Schema, TFieldPath extends RequiredPath> {
|
|
21
|
+
props(): ReturnType<typeof $$render<TSchema, TFieldPath>>['props'];
|
|
22
|
+
events(): ReturnType<typeof $$render<TSchema, TFieldPath>>['events'];
|
|
23
|
+
slots(): ReturnType<typeof $$render<TSchema, TFieldPath>>['slots'];
|
|
24
|
+
bindings(): "";
|
|
25
|
+
exports(): {};
|
|
26
|
+
}
|
|
27
|
+
interface $$IsomorphicComponent {
|
|
28
|
+
new <TSchema extends Schema, TFieldPath extends RequiredPath>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TSchema, TFieldPath>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TSchema, TFieldPath>['props']>, ReturnType<__sveltets_Render<TSchema, TFieldPath>['events']>, ReturnType<__sveltets_Render<TSchema, TFieldPath>['slots']>> & {
|
|
29
|
+
$$bindings?: ReturnType<__sveltets_Render<TSchema, TFieldPath>['bindings']>;
|
|
30
|
+
} & ReturnType<__sveltets_Render<TSchema, TFieldPath>['exports']>;
|
|
31
|
+
<TSchema extends Schema, TFieldPath extends RequiredPath>(internal: unknown, props: ReturnType<__sveltets_Render<TSchema, TFieldPath>['props']> & {}): ReturnType<__sveltets_Render<TSchema, TFieldPath>['exports']>;
|
|
32
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any, any>['bindings']>;
|
|
33
|
+
}
|
|
34
|
+
declare const Field: $$IsomorphicComponent;
|
|
35
|
+
type Field<TSchema extends Schema, TFieldPath extends RequiredPath> = InstanceType<typeof Field<TSchema, TFieldPath>>;
|
|
36
|
+
export default Field;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Field } from './Field.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Field } from './Field.svelte';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script
|
|
2
|
+
lang="ts"
|
|
3
|
+
generics="TSchema extends Schema, TFieldArrayPath extends RequiredPath"
|
|
4
|
+
>
|
|
5
|
+
import type {
|
|
6
|
+
RequiredPath,
|
|
7
|
+
Schema,
|
|
8
|
+
ValidArrayPath,
|
|
9
|
+
} from '../../core/index.svelte';
|
|
10
|
+
import type * as v from 'valibot';
|
|
11
|
+
import { useFieldArray } from '../../runes/index';
|
|
12
|
+
import type { FieldArrayStore, FormStore } from '../../types/index';
|
|
13
|
+
import type { Snippet } from 'svelte';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Properties of the `FieldArray` component.
|
|
17
|
+
*/
|
|
18
|
+
export interface FieldArrayProps<
|
|
19
|
+
TSchema extends Schema = Schema,
|
|
20
|
+
TFieldArrayPath extends RequiredPath = RequiredPath,
|
|
21
|
+
> {
|
|
22
|
+
readonly of: FormStore<TSchema>;
|
|
23
|
+
readonly path: ValidArrayPath<v.InferInput<TSchema>, TFieldArrayPath>;
|
|
24
|
+
readonly children: Snippet<[FieldArrayStore<TSchema, TFieldArrayPath>]>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let { of, path, children }: FieldArrayProps<TSchema, TFieldArrayPath> =
|
|
28
|
+
$props();
|
|
29
|
+
|
|
30
|
+
const field = useFieldArray(
|
|
31
|
+
() => of,
|
|
32
|
+
() => ({ path })
|
|
33
|
+
);
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
{@render children(field)}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { RequiredPath, Schema, ValidArrayPath } from '../../core/index.svelte';
|
|
2
|
+
import type * as v from 'valibot';
|
|
3
|
+
import type { FieldArrayStore, FormStore } from '../../types/index.ts';
|
|
4
|
+
import type { Snippet } from 'svelte';
|
|
5
|
+
/**
|
|
6
|
+
* Properties of the `FieldArray` component.
|
|
7
|
+
*/
|
|
8
|
+
export interface FieldArrayProps<TSchema extends Schema = Schema, TFieldArrayPath extends RequiredPath = RequiredPath> {
|
|
9
|
+
readonly of: FormStore<TSchema>;
|
|
10
|
+
readonly path: ValidArrayPath<v.InferInput<TSchema>, TFieldArrayPath>;
|
|
11
|
+
readonly children: Snippet<[FieldArrayStore<TSchema, TFieldArrayPath>]>;
|
|
12
|
+
}
|
|
13
|
+
declare function $$render<TSchema extends Schema, TFieldArrayPath extends RequiredPath>(): {
|
|
14
|
+
props: FieldArrayProps<TSchema, TFieldArrayPath>;
|
|
15
|
+
exports: {};
|
|
16
|
+
bindings: "";
|
|
17
|
+
slots: {};
|
|
18
|
+
events: {};
|
|
19
|
+
};
|
|
20
|
+
declare class __sveltets_Render<TSchema extends Schema, TFieldArrayPath extends RequiredPath> {
|
|
21
|
+
props(): ReturnType<typeof $$render<TSchema, TFieldArrayPath>>['props'];
|
|
22
|
+
events(): ReturnType<typeof $$render<TSchema, TFieldArrayPath>>['events'];
|
|
23
|
+
slots(): ReturnType<typeof $$render<TSchema, TFieldArrayPath>>['slots'];
|
|
24
|
+
bindings(): "";
|
|
25
|
+
exports(): {};
|
|
26
|
+
}
|
|
27
|
+
interface $$IsomorphicComponent {
|
|
28
|
+
new <TSchema extends Schema, TFieldArrayPath extends RequiredPath>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TSchema, TFieldArrayPath>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TSchema, TFieldArrayPath>['props']>, ReturnType<__sveltets_Render<TSchema, TFieldArrayPath>['events']>, ReturnType<__sveltets_Render<TSchema, TFieldArrayPath>['slots']>> & {
|
|
29
|
+
$$bindings?: ReturnType<__sveltets_Render<TSchema, TFieldArrayPath>['bindings']>;
|
|
30
|
+
} & ReturnType<__sveltets_Render<TSchema, TFieldArrayPath>['exports']>;
|
|
31
|
+
<TSchema extends Schema, TFieldArrayPath extends RequiredPath>(internal: unknown, props: ReturnType<__sveltets_Render<TSchema, TFieldArrayPath>['props']> & {}): ReturnType<__sveltets_Render<TSchema, TFieldArrayPath>['exports']>;
|
|
32
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any, any>['bindings']>;
|
|
33
|
+
}
|
|
34
|
+
declare const FieldArray: $$IsomorphicComponent;
|
|
35
|
+
type FieldArray<TSchema extends Schema, TFieldArrayPath extends RequiredPath> = InstanceType<typeof FieldArray<TSchema, TFieldArrayPath>>;
|
|
36
|
+
export default FieldArray;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as FieldArray } from './FieldArray.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as FieldArray } from './FieldArray.svelte';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script lang="ts" generics="TSchema extends Schema = Schema">
|
|
2
|
+
import {
|
|
3
|
+
INTERNAL,
|
|
4
|
+
type Schema,
|
|
5
|
+
type SubmitHandler,
|
|
6
|
+
} from '../../core/index.svelte';
|
|
7
|
+
import { handleSubmit } from '../../methods/index.svelte';
|
|
8
|
+
import type { FormStore } from '../../types/index';
|
|
9
|
+
import type { Snippet } from 'svelte';
|
|
10
|
+
import type { HTMLFormAttributes } from 'svelte/elements';
|
|
11
|
+
|
|
12
|
+
export type FormProps<TSchema extends Schema = Schema> = Omit<
|
|
13
|
+
HTMLFormAttributes,
|
|
14
|
+
'on:submit' | 'onsubmit' | 'novalidate'
|
|
15
|
+
> & {
|
|
16
|
+
of: FormStore<TSchema>;
|
|
17
|
+
onsubmit: SubmitHandler<TSchema>;
|
|
18
|
+
children: Snippet;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
let { of, onsubmit, children, ...other }: FormProps<TSchema> = $props();
|
|
22
|
+
|
|
23
|
+
const handler = handleSubmit(of, onsubmit);
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<form {...other} novalidate onsubmit={handler} bind:this={of[INTERNAL].element}>
|
|
27
|
+
{@render children()}
|
|
28
|
+
</form>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type Schema, type SubmitHandler } from '../../core/index.svelte';
|
|
2
|
+
import type { FormStore } from '../../types/index.ts';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
import type { HTMLFormAttributes } from 'svelte/elements';
|
|
5
|
+
export type FormProps<TSchema extends Schema = Schema> = Omit<HTMLFormAttributes, 'on:submit' | 'onsubmit' | 'novalidate'> & {
|
|
6
|
+
of: FormStore<TSchema>;
|
|
7
|
+
onsubmit: SubmitHandler<TSchema>;
|
|
8
|
+
children: Snippet;
|
|
9
|
+
};
|
|
10
|
+
declare function $$render<TSchema extends Schema = Schema>(): {
|
|
11
|
+
props: FormProps<TSchema>;
|
|
12
|
+
exports: {};
|
|
13
|
+
bindings: "";
|
|
14
|
+
slots: {};
|
|
15
|
+
events: {};
|
|
16
|
+
};
|
|
17
|
+
declare class __sveltets_Render<TSchema extends Schema = Schema> {
|
|
18
|
+
props(): ReturnType<typeof $$render<TSchema>>['props'];
|
|
19
|
+
events(): ReturnType<typeof $$render<TSchema>>['events'];
|
|
20
|
+
slots(): ReturnType<typeof $$render<TSchema>>['slots'];
|
|
21
|
+
bindings(): "";
|
|
22
|
+
exports(): {};
|
|
23
|
+
}
|
|
24
|
+
interface $$IsomorphicComponent {
|
|
25
|
+
new <TSchema extends Schema = Schema>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TSchema>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TSchema>['props']>, ReturnType<__sveltets_Render<TSchema>['events']>, ReturnType<__sveltets_Render<TSchema>['slots']>> & {
|
|
26
|
+
$$bindings?: ReturnType<__sveltets_Render<TSchema>['bindings']>;
|
|
27
|
+
} & ReturnType<__sveltets_Render<TSchema>['exports']>;
|
|
28
|
+
<TSchema extends Schema = Schema>(internal: unknown, props: ReturnType<__sveltets_Render<TSchema>['props']> & {}): ReturnType<__sveltets_Render<TSchema>['exports']>;
|
|
29
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
30
|
+
}
|
|
31
|
+
declare const Form: $$IsomorphicComponent;
|
|
32
|
+
type Form<TSchema extends Schema = Schema> = InstanceType<typeof Form<TSchema>>;
|
|
33
|
+
export default Form;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Form } from './Form.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Form } from './Form.svelte';
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import * as v from "valibot";
|
|
2
|
+
import { untrack } from "svelte";
|
|
3
|
+
|
|
4
|
+
//#region src/types/schema.d.ts
|
|
5
|
+
type Schema = v.GenericSchema | v.GenericSchemaAsync;
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/types/signal.d.ts
|
|
8
|
+
interface Signal<T> {
|
|
9
|
+
value: T;
|
|
10
|
+
}
|
|
11
|
+
interface Batch {
|
|
12
|
+
<T>(fn: () => T): T;
|
|
13
|
+
}
|
|
14
|
+
interface Untrack {
|
|
15
|
+
<T>(fn: () => T): T;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/types/field.d.ts
|
|
19
|
+
/**
|
|
20
|
+
* Value type of the field element.
|
|
21
|
+
*/
|
|
22
|
+
type FieldElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
|
|
23
|
+
interface InternalBaseStore {
|
|
24
|
+
kind: "array" | "object" | "value";
|
|
25
|
+
name: string;
|
|
26
|
+
schema: Schema;
|
|
27
|
+
elements: FieldElement[];
|
|
28
|
+
errors: Signal<[string, ...string[]] | null>;
|
|
29
|
+
}
|
|
30
|
+
interface InternalArrayStore extends InternalBaseStore {
|
|
31
|
+
kind: "array";
|
|
32
|
+
children: InternalFieldStore[];
|
|
33
|
+
initialItems: Signal<string[]>;
|
|
34
|
+
startItems: Signal<string[]>;
|
|
35
|
+
items: Signal<string[]>;
|
|
36
|
+
isTouched: Signal<boolean>;
|
|
37
|
+
isDirty: Signal<boolean>;
|
|
38
|
+
}
|
|
39
|
+
interface InternalObjectStore extends InternalBaseStore {
|
|
40
|
+
kind: "object";
|
|
41
|
+
children: Record<string, InternalFieldStore>;
|
|
42
|
+
}
|
|
43
|
+
interface InternalValueStore extends InternalBaseStore {
|
|
44
|
+
kind: "value";
|
|
45
|
+
initialInput: Signal<unknown>;
|
|
46
|
+
startInput: Signal<unknown>;
|
|
47
|
+
input: Signal<unknown>;
|
|
48
|
+
isTouched: Signal<boolean>;
|
|
49
|
+
isDirty: Signal<boolean>;
|
|
50
|
+
}
|
|
51
|
+
type InternalFieldStore = InternalArrayStore | InternalObjectStore | InternalValueStore;
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/values.d.ts
|
|
54
|
+
declare const INTERNAL: "~internal";
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/types/utils.d.ts
|
|
57
|
+
/**
|
|
58
|
+
* Checks if a type is `any`.
|
|
59
|
+
*/
|
|
60
|
+
type IsAny<Type> = 0 extends 1 & Type ? true : false;
|
|
61
|
+
/**
|
|
62
|
+
* Checks if a type is `never`.
|
|
63
|
+
*/
|
|
64
|
+
type IsNever<Type> = [Type] extends [never] ? true : false;
|
|
65
|
+
/**
|
|
66
|
+
* Constructs a type that is maybe a promise.
|
|
67
|
+
*/
|
|
68
|
+
type MaybePromise<TValue> = TValue | Promise<TValue>;
|
|
69
|
+
/**
|
|
70
|
+
* Makes all properties deeply optional.
|
|
71
|
+
*/
|
|
72
|
+
type DeepPartial<TValue> = TValue extends readonly unknown[] ? number extends TValue["length"] ? TValue : { [Key in keyof TValue]?: DeepPartial<TValue[Key]> | undefined } : TValue extends Record<PropertyKey, unknown> ? { [Key in keyof TValue]?: DeepPartial<TValue[Key]> | undefined } : TValue | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Makes all value properties optional.
|
|
75
|
+
*/
|
|
76
|
+
type PartialValues<TValue> = TValue extends readonly unknown[] ? number extends TValue["length"] ? TValue : { [Key in keyof TValue]: PartialValues<TValue[Key]> } : TValue extends Record<PropertyKey, unknown> ? { [Key in keyof TValue]: PartialValues<TValue[Key]> } : TValue | undefined;
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/types/form.d.ts
|
|
79
|
+
/**
|
|
80
|
+
* Value type of the validation mode.
|
|
81
|
+
*/
|
|
82
|
+
type ValidationMode = "initial" | "touch" | "input" | "change" | "blur" | "submit";
|
|
83
|
+
interface FormConfig<TSchema extends Schema = Schema> {
|
|
84
|
+
readonly schema: TSchema;
|
|
85
|
+
readonly initialInput?: DeepPartial<v.InferInput<TSchema>> | undefined;
|
|
86
|
+
readonly validate?: ValidationMode | undefined;
|
|
87
|
+
readonly revalidate?: Exclude<ValidationMode, "initial"> | undefined;
|
|
88
|
+
}
|
|
89
|
+
interface InternalFormStore<TSchema extends Schema = Schema> extends InternalObjectStore {
|
|
90
|
+
element?: HTMLFormElement;
|
|
91
|
+
validators: number;
|
|
92
|
+
validate: ValidationMode;
|
|
93
|
+
revalidate: Exclude<ValidationMode, "initial">;
|
|
94
|
+
parse: (input: unknown) => Promise<v.SafeParseResult<TSchema>>;
|
|
95
|
+
isSubmitting: Signal<boolean>;
|
|
96
|
+
isSubmitted: Signal<boolean>;
|
|
97
|
+
isValidating: Signal<boolean>;
|
|
98
|
+
}
|
|
99
|
+
interface BaseFormStore<TSchema extends Schema = Schema> {
|
|
100
|
+
[INTERNAL]: InternalFormStore<TSchema>;
|
|
101
|
+
}
|
|
102
|
+
type SubmitHandler<TSchema extends Schema> = (output: v.InferOutput<TSchema>, event: SubmitEvent) => MaybePromise<unknown>;
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/types/path.d.ts
|
|
105
|
+
/**
|
|
106
|
+
* Path key type.
|
|
107
|
+
*/
|
|
108
|
+
type PathKey = string | number;
|
|
109
|
+
/**
|
|
110
|
+
* Path type.
|
|
111
|
+
*/
|
|
112
|
+
type Path = readonly PathKey[];
|
|
113
|
+
/**
|
|
114
|
+
* Required path type.
|
|
115
|
+
*/
|
|
116
|
+
type RequiredPath = readonly [PathKey, ...Path];
|
|
117
|
+
/**
|
|
118
|
+
* Extracts the exact keys of a tuple, array or object.
|
|
119
|
+
*/
|
|
120
|
+
type KeyOf<TValue> = IsAny<TValue> extends true ? never : TValue extends readonly unknown[] ? number extends TValue["length"] ? number : { [TKey in keyof TValue]: TKey extends `${infer TIndex extends number}` ? TIndex : never }[number] : TValue extends Record<string, unknown> ? keyof TValue & PathKey : never;
|
|
121
|
+
/**
|
|
122
|
+
* Merges array and object unions into a single object.
|
|
123
|
+
*
|
|
124
|
+
* Hint: This is necessary to make any property accessible. By default,
|
|
125
|
+
* properties that do not exist in all union options are not accessible
|
|
126
|
+
* and result in "any" when accessed.
|
|
127
|
+
*/
|
|
128
|
+
type MergeUnion<T> = { [K in KeyOf<T>]: T extends Record<K, infer V> ? V : never };
|
|
129
|
+
/**
|
|
130
|
+
* Lazily evaluate only the first valid path segment based on the given value.
|
|
131
|
+
*/
|
|
132
|
+
type LazyPath<TValue, TPathToCheck extends Path, TValidPath extends Path = readonly []> = TPathToCheck extends readonly [] ? TValidPath : TPathToCheck extends readonly [infer TFirstKey extends KeyOf<TValue>, ...infer TPathRest extends Path] ? LazyPath<Required<MergeUnion<TValue>[TFirstKey]>, TPathRest, readonly [...TValidPath, TFirstKey]> : IsNever<KeyOf<TValue>> extends false ? readonly [...TValidPath, KeyOf<TValue>] : TValidPath;
|
|
133
|
+
/**
|
|
134
|
+
* Returns the path if valid, otherwise the first possible valid path based on
|
|
135
|
+
* the given value.
|
|
136
|
+
*/
|
|
137
|
+
type ValidPath<TValue, TPath extends RequiredPath> = TPath extends LazyPath<Required<TValue>, TPath> ? TPath : LazyPath<Required<TValue>, TPath>;
|
|
138
|
+
/**
|
|
139
|
+
* Extracts the value type at the given path.
|
|
140
|
+
*/
|
|
141
|
+
type PathValue<TValue, TPath extends Path> = TPath extends readonly [infer TKey, ...infer TRest extends Path] ? TKey extends KeyOf<Required<TValue>> ? PathValue<MergeUnion<Required<TValue>>[TKey], TRest> : unknown : TValue;
|
|
142
|
+
/**
|
|
143
|
+
* Checks if a value is an array or contains one.
|
|
144
|
+
*/
|
|
145
|
+
type IsOrHasArray<TValue> = IsAny<TValue> extends true ? false : TValue extends readonly unknown[] ? true : TValue extends Record<string, unknown> ? true extends { [TKey in keyof TValue]: IsOrHasArray<TValue[TKey]> }[keyof TValue] ? true : false : false;
|
|
146
|
+
/**
|
|
147
|
+
* Extracts the exact keys of a tuple, array or object that contain arrays.
|
|
148
|
+
*/
|
|
149
|
+
type KeyOfArrayPath<TValue> = IsAny<TValue> extends true ? never : TValue extends readonly (infer TItem)[] ? number extends TValue["length"] ? IsOrHasArray<TItem> extends true ? number : never : { [TKey in keyof TValue]: TKey extends `${infer TIndex extends number}` ? IsOrHasArray<NonNullable<TValue[TKey]>> extends true ? TIndex : never : never }[number] : TValue extends Record<string, unknown> ? { [TKey in keyof TValue]: IsOrHasArray<NonNullable<TValue[TKey]>> extends true ? TKey : never }[keyof TValue] & PathKey : never;
|
|
150
|
+
/**
|
|
151
|
+
* Lazily evaluate only the first valid array path segment based on the given value.
|
|
152
|
+
*/
|
|
153
|
+
type LazyArrayPath<TValue, TPathToCheck extends Path, TValidPath extends Path = readonly []> = TPathToCheck extends readonly [] ? TValue extends readonly unknown[] ? TValidPath : readonly [...TValidPath, KeyOfArrayPath<TValue>] : TPathToCheck extends readonly [infer TFirstKey extends KeyOfArrayPath<TValue>, ...infer TPathRest extends Path] ? LazyArrayPath<Required<MergeUnion<TValue>[TFirstKey]>, TPathRest, readonly [...TValidPath, TFirstKey]> : IsNever<KeyOfArrayPath<TValue>> extends false ? readonly [...TValidPath, KeyOfArrayPath<TValue>] : never;
|
|
154
|
+
/**
|
|
155
|
+
* Returns the path if valid, otherwise the first possible valid array path based on
|
|
156
|
+
* the given value.
|
|
157
|
+
*/
|
|
158
|
+
type ValidArrayPath<TValue, TPath extends RequiredPath> = TPath extends LazyArrayPath<Required<TValue>, TPath> ? TPath : LazyArrayPath<Required<TValue>, TPath>;
|
|
159
|
+
//#endregion
|
|
160
|
+
//#region src/array/copyItemState/copyItemState.d.ts
|
|
161
|
+
/**
|
|
162
|
+
* Copies the deeply nested state (signal values) from one array item to another.
|
|
163
|
+
* This includes the `isTouched`, `isDirty`, `startInput`, `input`, `startItems`, and `items` properties.
|
|
164
|
+
* Recursively walks through the field stores and copies all signal values.
|
|
165
|
+
*
|
|
166
|
+
* @param internalArrayStore - The field store of the array (not the array item)
|
|
167
|
+
* @param fromIndex - The source index to copy from
|
|
168
|
+
* @param toIndex - The destination index to copy to
|
|
169
|
+
*/
|
|
170
|
+
declare function copyItemState(fromInternalFieldStore: InternalFieldStore, toInternalFieldStore: InternalFieldStore): void;
|
|
171
|
+
//#endregion
|
|
172
|
+
//#region src/array/resetItemState/resetItemState.d.ts
|
|
173
|
+
/**
|
|
174
|
+
* Resets the state of an array item (signal values) deeply nested.
|
|
175
|
+
* Sets `isTouched` and `isDirty` to `false` and `startInput`, `input`,
|
|
176
|
+
* `startItems` and `items` to the new input.
|
|
177
|
+
* Keeps the `initialInput` and `initialItems` state unchanged for form reset functionality.
|
|
178
|
+
*
|
|
179
|
+
* @param internalFieldStore - The field store of the array item
|
|
180
|
+
* @param initialInput - The new input value (can be any type including array or object)
|
|
181
|
+
*/
|
|
182
|
+
declare function resetItemState(internalFieldStore: InternalFieldStore, initialInput: unknown): void;
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region src/array/swapItemState/swapItemState.d.ts
|
|
185
|
+
/**
|
|
186
|
+
* Swaps the deeply nested state (signal values) between two field stores.
|
|
187
|
+
* This includes the `isTouched`, `isDirty`, `startInput`, `input`, `startItems`, and `items` properties.
|
|
188
|
+
* Recursively walks through the field stores and swaps all signal values.
|
|
189
|
+
*
|
|
190
|
+
* @param firstInternalFieldStore - The first field store to swap
|
|
191
|
+
* @param secondInternalFieldStore - The second field store to swap
|
|
192
|
+
*/
|
|
193
|
+
declare function swapItemState(firstInternalFieldStore: InternalFieldStore, secondInternalFieldStore: InternalFieldStore): void;
|
|
194
|
+
//#endregion
|
|
195
|
+
//#region src/field/getElementInput/getElementInput.d.ts
|
|
196
|
+
/**
|
|
197
|
+
* Returns the current input of the element.
|
|
198
|
+
*
|
|
199
|
+
* @param element The field element.
|
|
200
|
+
* @param interalFieldStore The interal field store.
|
|
201
|
+
*
|
|
202
|
+
* @returns The element input.
|
|
203
|
+
*/
|
|
204
|
+
declare function getElementInput(element: FieldElement, internalFieldStore: InternalFieldStore): unknown;
|
|
205
|
+
//#endregion
|
|
206
|
+
//#region src/field/getFieldBool/getFieldBool.d.ts
|
|
207
|
+
declare function getFieldBool(internalFieldStore: InternalFieldStore, type: "errors" | "isTouched" | "isDirty"): boolean;
|
|
208
|
+
//#endregion
|
|
209
|
+
//#region src/field/getFieldInput/getFieldInput.d.ts
|
|
210
|
+
declare function getFieldInput(internalFieldStore: InternalFieldStore): unknown;
|
|
211
|
+
//#endregion
|
|
212
|
+
//#region src/field/getFieldStore/getFieldStore.d.ts
|
|
213
|
+
declare function getFieldStore(internalFormStore: InternalFormStore, path: Path): InternalFieldStore;
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region src/field/initializeFieldStore/initializeFieldStore.d.ts
|
|
216
|
+
type FieldSchema = v.ArraySchema<v.BaseSchema<unknown, unknown, v.BaseIssue<unknown>>, v.ErrorMessage<v.ArrayIssue> | undefined> | v.ExactOptionalSchema<any, any> | v.IntersectSchema<any, any> | v.LazySchema<any> | v.LooseObjectSchema<any, any> | v.LooseTupleSchema<any, any> | v.NonNullableSchema<any, any> | v.NonNullishSchema<any, any> | v.NonOptionalSchema<any, any> | v.NullableSchema<any, any> | v.NullishSchema<any, any> | v.ObjectSchema<v.ObjectEntries, v.ErrorMessage<v.ObjectIssue> | undefined> | v.ObjectWithRestSchema<v.ObjectEntries, v.BaseSchema<unknown, unknown, v.BaseIssue<unknown>>, v.ErrorMessage<v.ObjectWithRestIssue> | undefined> | v.OptionalSchema<any, any> | v.PromiseSchema<any> | v.RecordSchema<any, any, any> | v.StrictObjectSchema<any, any> | v.StrictTupleSchema<any, any> | v.TupleSchema<v.TupleItems, v.ErrorMessage<v.TupleIssue> | undefined> | v.TupleWithRestSchema<any, any, any> | v.UndefinedableSchema<any, any> | v.UnionSchema<any, any> | v.VariantSchema<any, any, any>;
|
|
217
|
+
/**
|
|
218
|
+
* TODO: Add comment
|
|
219
|
+
* TODO: Should this stay in /primitives or move to /utils?
|
|
220
|
+
*/
|
|
221
|
+
declare function initializeFieldStore(internalFieldStore: Partial<InternalFieldStore>, schema: FieldSchema, initialInput: unknown, path: PathKey[]): void;
|
|
222
|
+
//#endregion
|
|
223
|
+
//#region src/field/setFieldBool/setFieldBool.d.ts
|
|
224
|
+
declare function setFieldBool(internalFieldStore: InternalFieldStore, type: "isTouched" | "isDirty", bool: boolean): void;
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region src/field/setFieldInput/setFieldInput.d.ts
|
|
227
|
+
declare function setFieldInput(internalFieldStore: InternalFieldStore, input: unknown): void;
|
|
228
|
+
//#endregion
|
|
229
|
+
//#region src/field/setInitialFieldInput/setInitialFieldInput.d.ts
|
|
230
|
+
declare function setInitialFieldInput(internalFieldStore: InternalFieldStore, initialInput: unknown): void;
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/field/walkFieldStore/walkFieldStore.d.ts
|
|
233
|
+
declare function walkFieldStore(internalFieldStore: InternalFieldStore, callback: (internalFieldStore: InternalFieldStore) => void): void;
|
|
234
|
+
//#endregion
|
|
235
|
+
//#region src/form/createFormStore/createFormStore.d.ts
|
|
236
|
+
declare function createFormStore(config: FormConfig, parse: (input: unknown) => Promise<v.SafeParseResult<Schema>>): InternalFormStore;
|
|
237
|
+
//#endregion
|
|
238
|
+
//#region src/form/validateFormInput/validateFormInput.d.ts
|
|
239
|
+
interface ValidateFormInputConfig {
|
|
240
|
+
readonly shouldFocus?: boolean | undefined;
|
|
241
|
+
}
|
|
242
|
+
declare function validateFormInput(internalFormStore: InternalFormStore, config?: ValidateFormInputConfig): Promise<v.SafeParseResult<Schema>>;
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region src/form/validateIfRequired/validateIfRequired.d.ts
|
|
245
|
+
declare function validateIfRequired(internalFormStore: InternalFormStore, internalFieldStore: InternalFieldStore, validationModes: ValidationMode): void;
|
|
246
|
+
//#endregion
|
|
247
|
+
//#region src/framework/index.d.ts
|
|
248
|
+
type Framework = "preact" | "qwik" | "solid" | "svelte" | "vue";
|
|
249
|
+
//#endregion
|
|
250
|
+
//#region src/framework/index.svelte.d.ts
|
|
251
|
+
declare const framework: Framework;
|
|
252
|
+
declare function createId(): string;
|
|
253
|
+
declare function createSignal<T>(initialValue: T): Signal<T>;
|
|
254
|
+
declare function batch<T>(fn: () => T): T;
|
|
255
|
+
//#endregion
|
|
256
|
+
export { BaseFormStore, Batch, DeepPartial, FieldElement, FieldSchema, FormConfig, INTERNAL, InternalArrayStore, InternalBaseStore, InternalFieldStore, InternalFormStore, InternalObjectStore, InternalValueStore, IsAny, IsNever, MaybePromise, PartialValues, Path, PathKey, PathValue, RequiredPath, Schema, Signal, SubmitHandler, Untrack, ValidArrayPath, ValidPath, ValidateFormInputConfig, ValidationMode, batch, copyItemState, createFormStore, createId, createSignal, framework, getElementInput, getFieldBool, getFieldInput, getFieldStore, initializeFieldStore, resetItemState, setFieldBool, setFieldInput, setInitialFieldInput, swapItemState, untrack, validateFormInput, validateIfRequired, walkFieldStore };
|