@tanstack/svelte-form 1.6.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.
@@ -0,0 +1,269 @@
1
+ <script module lang="ts">
2
+ import {
3
+ type DeepKeys,
4
+ type DeepValue,
5
+ FieldApi,
6
+ type FieldAsyncValidateOrFn,
7
+ type FieldValidateOrFn,
8
+ type FormAsyncValidateOrFn,
9
+ type FormValidateOrFn,
10
+ } from '@tanstack/form-core'
11
+ import { useStore } from '@tanstack/svelte-store'
12
+ import { onMount, type Snippet } from 'svelte'
13
+ import Field from './Field.svelte'
14
+ import type { CreateFieldOptions, SvelteFieldApi } from './types.js'
15
+
16
+ export function createField<
17
+ TParentData,
18
+ TName extends DeepKeys<TParentData>,
19
+ TData extends DeepValue<TParentData, TName>,
20
+ TOnMount extends undefined | FieldValidateOrFn<TParentData, TName, TData>,
21
+ TOnChange extends undefined | FieldValidateOrFn<TParentData, TName, TData>,
22
+ TOnChangeAsync extends
23
+ | undefined
24
+ | FieldAsyncValidateOrFn<TParentData, TName, TData>,
25
+ TOnBlur extends undefined | FieldValidateOrFn<TParentData, TName, TData>,
26
+ TOnBlurAsync extends
27
+ | undefined
28
+ | FieldAsyncValidateOrFn<TParentData, TName, TData>,
29
+ TOnSubmit extends undefined | FieldValidateOrFn<TParentData, TName, TData>,
30
+ TOnSubmitAsync extends
31
+ | undefined
32
+ | FieldAsyncValidateOrFn<TParentData, TName, TData>,
33
+ TFormOnMount extends undefined | FormValidateOrFn<TParentData>,
34
+ TFormOnChange extends undefined | FormValidateOrFn<TParentData>,
35
+ TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
36
+ TFormOnBlur extends undefined | FormValidateOrFn<TParentData>,
37
+ TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
38
+ TFormOnSubmit extends undefined | FormValidateOrFn<TParentData>,
39
+ TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
40
+ TFormOnServer extends undefined | FormAsyncValidateOrFn<TParentData>,
41
+ TParentSubmitMeta,
42
+ >(
43
+ opts: () => CreateFieldOptions<
44
+ TParentData,
45
+ TName,
46
+ TData,
47
+ TOnMount,
48
+ TOnChange,
49
+ TOnChangeAsync,
50
+ TOnBlur,
51
+ TOnBlurAsync,
52
+ TOnSubmit,
53
+ TOnSubmitAsync,
54
+ TFormOnMount,
55
+ TFormOnChange,
56
+ TFormOnChangeAsync,
57
+ TFormOnBlur,
58
+ TFormOnBlurAsync,
59
+ TFormOnSubmit,
60
+ TFormOnSubmitAsync,
61
+ TFormOnServer,
62
+ TParentSubmitMeta
63
+ >,
64
+ ) {
65
+ const options = opts()
66
+
67
+ const api = new FieldApi(options)
68
+
69
+ const extendedApi: typeof api &
70
+ SvelteFieldApi<
71
+ TParentData,
72
+ TFormOnMount,
73
+ TFormOnChange,
74
+ TFormOnChangeAsync,
75
+ TFormOnBlur,
76
+ TFormOnBlurAsync,
77
+ TFormOnSubmit,
78
+ TFormOnSubmitAsync,
79
+ TFormOnServer,
80
+ TParentSubmitMeta
81
+ > = api as never
82
+
83
+ extendedApi.Field = Field as never
84
+
85
+ let mounted = false
86
+ // Instantiates field meta and removes it when unrendered
87
+ onMount(() => {
88
+ const cleanupFn = api.mount()
89
+ mounted = true
90
+ return () => {
91
+ cleanupFn()
92
+ mounted = false
93
+ }
94
+ })
95
+
96
+ $effect.pre(() => {
97
+ // Invoke options function before mounted check, else it wouldn't rerun on changes to options.
98
+ // Changes to options are seen by the effect because signals inside them are picked up.
99
+ const current = opts()
100
+ if (!mounted) return
101
+ api.update(current)
102
+ })
103
+
104
+ const storeSub = useStore(api.store)
105
+ Object.defineProperty(extendedApi, 'state', {
106
+ get() {
107
+ return storeSub.current
108
+ },
109
+ })
110
+
111
+ return extendedApi
112
+ }
113
+ </script>
114
+
115
+ <script
116
+ lang="ts"
117
+ generics="
118
+ TParentData,
119
+ TName extends DeepKeys<TParentData>,
120
+ TData extends DeepValue<TParentData, TName>,
121
+ TOnMount extends undefined | FieldValidateOrFn<TParentData, TName, TData>,
122
+ TOnChange extends undefined | FieldValidateOrFn<TParentData, TName, TData>,
123
+ TOnChangeAsync extends
124
+ | undefined
125
+ | FieldAsyncValidateOrFn<TParentData, TName, TData>,
126
+ TOnBlur extends undefined | FieldValidateOrFn<TParentData, TName, TData>,
127
+ TOnBlurAsync extends
128
+ | undefined
129
+ | FieldAsyncValidateOrFn<TParentData, TName, TData>,
130
+ TOnSubmit extends undefined | FieldValidateOrFn<TParentData, TName, TData>,
131
+ TOnSubmitAsync extends
132
+ | undefined
133
+ | FieldAsyncValidateOrFn<TParentData, TName, TData>,
134
+ TFormOnMount extends undefined | FormValidateOrFn<TParentData>,
135
+ TFormOnChange extends undefined | FormValidateOrFn<TParentData>,
136
+ TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
137
+ TFormOnBlur extends undefined | FormValidateOrFn<TParentData>,
138
+ TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
139
+ TFormOnSubmit extends undefined | FormValidateOrFn<TParentData>,
140
+ TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
141
+ TFormOnServer extends undefined | FormAsyncValidateOrFn<TParentData>,
142
+ TParentSubmitMeta,
143
+ "
144
+ >
145
+ type Props<
146
+ TParentData,
147
+ TName extends DeepKeys<TParentData>,
148
+ TData extends DeepValue<TParentData, TName>,
149
+ TOnMount extends undefined | FieldValidateOrFn<TParentData, TName, TData>,
150
+ TOnChange extends undefined | FieldValidateOrFn<TParentData, TName, TData>,
151
+ TOnChangeAsync extends
152
+ | undefined
153
+ | FieldAsyncValidateOrFn<TParentData, TName, TData>,
154
+ TOnBlur extends undefined | FieldValidateOrFn<TParentData, TName, TData>,
155
+ TOnBlurAsync extends
156
+ | undefined
157
+ | FieldAsyncValidateOrFn<TParentData, TName, TData>,
158
+ TOnSubmit extends undefined | FieldValidateOrFn<TParentData, TName, TData>,
159
+ TOnSubmitAsync extends
160
+ | undefined
161
+ | FieldAsyncValidateOrFn<TParentData, TName, TData>,
162
+ TFormOnMount extends undefined | FormValidateOrFn<TParentData>,
163
+ TFormOnChange extends undefined | FormValidateOrFn<TParentData>,
164
+ TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
165
+ TFormOnBlur extends undefined | FormValidateOrFn<TParentData>,
166
+ TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
167
+ TFormOnSubmit extends undefined | FormValidateOrFn<TParentData>,
168
+ TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
169
+ TFormOnServer extends undefined | FormAsyncValidateOrFn<TParentData>,
170
+ TParentSubmitMeta,
171
+ > = {
172
+ children: Snippet<
173
+ [
174
+ FieldApi<
175
+ TParentData,
176
+ TName,
177
+ TData,
178
+ TOnMount,
179
+ TOnChange,
180
+ TOnChangeAsync,
181
+ TOnBlur,
182
+ TOnBlurAsync,
183
+ TOnSubmit,
184
+ TOnSubmitAsync,
185
+ TFormOnMount,
186
+ TFormOnChange,
187
+ TFormOnChangeAsync,
188
+ TFormOnBlur,
189
+ TFormOnBlurAsync,
190
+ TFormOnSubmit,
191
+ TFormOnSubmitAsync,
192
+ TFormOnServer,
193
+ TParentSubmitMeta
194
+ >,
195
+ ]
196
+ >
197
+ } & CreateFieldOptions<
198
+ TParentData,
199
+ TName,
200
+ TData,
201
+ TOnMount,
202
+ TOnChange,
203
+ TOnChangeAsync,
204
+ TOnBlur,
205
+ TOnBlurAsync,
206
+ TOnSubmit,
207
+ TOnSubmitAsync,
208
+ TFormOnMount,
209
+ TFormOnChange,
210
+ TFormOnChangeAsync,
211
+ TFormOnBlur,
212
+ TFormOnBlurAsync,
213
+ TFormOnSubmit,
214
+ TFormOnSubmitAsync,
215
+ TFormOnServer,
216
+ TParentSubmitMeta
217
+ >
218
+
219
+ let {
220
+ children,
221
+ ...fieldOptions
222
+ }: Props<
223
+ TParentData,
224
+ TName,
225
+ TData,
226
+ TOnMount,
227
+ TOnChange,
228
+ TOnChangeAsync,
229
+ TOnBlur,
230
+ TOnBlurAsync,
231
+ TOnSubmit,
232
+ TOnSubmitAsync,
233
+ TFormOnMount,
234
+ TFormOnChange,
235
+ TFormOnChangeAsync,
236
+ TFormOnBlur,
237
+ TFormOnBlurAsync,
238
+ TFormOnSubmit,
239
+ TFormOnSubmitAsync,
240
+ TFormOnServer,
241
+ TParentSubmitMeta
242
+ > = $props()
243
+
244
+ const fieldApi = createField<
245
+ TParentData,
246
+ TName,
247
+ TData,
248
+ TOnMount,
249
+ TOnChange,
250
+ TOnChangeAsync,
251
+ TOnBlur,
252
+ TOnBlurAsync,
253
+ TOnSubmit,
254
+ TOnSubmitAsync,
255
+ TFormOnMount,
256
+ TFormOnChange,
257
+ TFormOnChangeAsync,
258
+ TFormOnBlur,
259
+ TFormOnBlurAsync,
260
+ TFormOnSubmit,
261
+ TFormOnSubmitAsync,
262
+ TFormOnServer,
263
+ TParentSubmitMeta
264
+ >(() => {
265
+ return fieldOptions
266
+ })
267
+ </script>
268
+
269
+ {@render children(fieldApi)}
@@ -0,0 +1,16 @@
1
+ <script lang="ts">
2
+ import { useStore } from '@tanstack/svelte-store'
3
+
4
+ // Don't bother typing this out, this component is only usable through a wrapper
5
+ interface Props {
6
+ children: any
7
+ store: any
8
+ selector?: (state: any) => any
9
+ }
10
+
11
+ let { children, store, selector = (state) => state }: Props = $props()
12
+
13
+ const value = useStore(store, selector)
14
+ </script>
15
+
16
+ {@render children(value.current)}
@@ -0,0 +1,235 @@
1
+ import { FormApi } from '@tanstack/form-core'
2
+ import { useStore } from '@tanstack/svelte-store'
3
+ import { onMount } from 'svelte'
4
+ import Field, { createField } from './Field.svelte'
5
+ import Subscribe from './Subscribe.svelte'
6
+ import type {
7
+ Component,
8
+ ComponentConstructorOptions,
9
+ Snippet,
10
+ SvelteComponent,
11
+ } from 'svelte'
12
+ import type {
13
+ FormAsyncValidateOrFn,
14
+ FormOptions,
15
+ FormState,
16
+ FormValidateOrFn,
17
+ } from '@tanstack/form-core'
18
+ import type { CreateField, FieldComponent, WithoutFunction } from './types.js'
19
+
20
+ export interface SvelteFormApi<
21
+ TParentData,
22
+ TFormOnMount extends undefined | FormValidateOrFn<TParentData>,
23
+ TFormOnChange extends undefined | FormValidateOrFn<TParentData>,
24
+ TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
25
+ TFormOnBlur extends undefined | FormValidateOrFn<TParentData>,
26
+ TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
27
+ TFormOnSubmit extends undefined | FormValidateOrFn<TParentData>,
28
+ TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
29
+ TFormOnServer extends undefined | FormAsyncValidateOrFn<TParentData>,
30
+ TSubmitMeta,
31
+ > {
32
+ Field: FieldComponent<
33
+ TParentData,
34
+ TFormOnMount,
35
+ TFormOnChange,
36
+ TFormOnChangeAsync,
37
+ TFormOnBlur,
38
+ TFormOnBlurAsync,
39
+ TFormOnSubmit,
40
+ TFormOnSubmitAsync,
41
+ TFormOnServer,
42
+ TSubmitMeta
43
+ >
44
+ createField: CreateField<
45
+ TParentData,
46
+ TFormOnMount,
47
+ TFormOnChange,
48
+ TFormOnChangeAsync,
49
+ TFormOnBlur,
50
+ TFormOnBlurAsync,
51
+ TFormOnSubmit,
52
+ TFormOnSubmitAsync,
53
+ TFormOnServer,
54
+ TSubmitMeta
55
+ >
56
+ useStore: <
57
+ TSelected = NoInfer<
58
+ FormState<
59
+ TParentData,
60
+ TFormOnMount,
61
+ TFormOnChange,
62
+ TFormOnChangeAsync,
63
+ TFormOnBlur,
64
+ TFormOnBlurAsync,
65
+ TFormOnSubmit,
66
+ TFormOnSubmitAsync,
67
+ TFormOnServer
68
+ >
69
+ >,
70
+ >(
71
+ selector?: (
72
+ state: NoInfer<
73
+ FormState<
74
+ TParentData,
75
+ TFormOnMount,
76
+ TFormOnChange,
77
+ TFormOnChangeAsync,
78
+ TFormOnBlur,
79
+ TFormOnBlurAsync,
80
+ TFormOnSubmit,
81
+ TFormOnSubmitAsync,
82
+ TFormOnServer
83
+ >
84
+ >,
85
+ ) => TSelected,
86
+ ) => { current: TSelected }
87
+ // This giant type allows the type
88
+ // - to be used as a function (which they are now in Svelte 5)
89
+ // - to be used as a class (which they were in Svelte 4, and which Svelte intellisense still uses for backwards compat)
90
+ // - to preserve the generics correctly
91
+ // Once Svelte intellisense no longer has/needs backwards compat, we can remove the class constructor part
92
+ Subscribe: (<
93
+ TSelected = NoInfer<
94
+ FormState<
95
+ TParentData,
96
+ TFormOnMount,
97
+ TFormOnChange,
98
+ TFormOnChangeAsync,
99
+ TFormOnBlur,
100
+ TFormOnBlurAsync,
101
+ TFormOnSubmit,
102
+ TFormOnSubmitAsync,
103
+ TFormOnServer
104
+ >
105
+ >,
106
+ >(
107
+ internal: any,
108
+ props: {
109
+ selector?: (
110
+ state: NoInfer<
111
+ FormState<
112
+ TParentData,
113
+ TFormOnMount,
114
+ TFormOnChange,
115
+ TFormOnChangeAsync,
116
+ TFormOnBlur,
117
+ TFormOnBlurAsync,
118
+ TFormOnSubmit,
119
+ TFormOnSubmitAsync,
120
+ TFormOnServer
121
+ >
122
+ >,
123
+ ) => TSelected
124
+ children: Snippet<[NoInfer<TSelected>]>
125
+ },
126
+ ) => {}) &
127
+ (new <
128
+ TSelected = NoInfer<
129
+ FormState<
130
+ TParentData,
131
+ TFormOnMount,
132
+ TFormOnChange,
133
+ TFormOnChangeAsync,
134
+ TFormOnBlur,
135
+ TFormOnBlurAsync,
136
+ TFormOnSubmit,
137
+ TFormOnSubmitAsync,
138
+ TFormOnServer
139
+ >
140
+ >,
141
+ >(
142
+ opts: ComponentConstructorOptions<{
143
+ selector?: (
144
+ state: NoInfer<
145
+ FormState<
146
+ TParentData,
147
+ TFormOnMount,
148
+ TFormOnChange,
149
+ TFormOnChangeAsync,
150
+ TFormOnBlur,
151
+ TFormOnBlurAsync,
152
+ TFormOnSubmit,
153
+ TFormOnSubmitAsync,
154
+ TFormOnServer
155
+ >
156
+ >,
157
+ ) => TSelected
158
+ children: Snippet<[NoInfer<TSelected>]>
159
+ }>,
160
+ ) => SvelteComponent) &
161
+ WithoutFunction<Component>
162
+ }
163
+
164
+ export function createForm<
165
+ TParentData,
166
+ TFormOnMount extends undefined | FormValidateOrFn<TParentData>,
167
+ TFormOnChange extends undefined | FormValidateOrFn<TParentData>,
168
+ TFormOnChangeAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
169
+ TFormOnBlur extends undefined | FormValidateOrFn<TParentData>,
170
+ TFormOnBlurAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
171
+ TFormOnSubmit extends undefined | FormValidateOrFn<TParentData>,
172
+ TFormOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TParentData>,
173
+ TFormOnServer extends undefined | FormAsyncValidateOrFn<TParentData>,
174
+ TSubmitMeta,
175
+ >(
176
+ opts?: () => FormOptions<
177
+ TParentData,
178
+ TFormOnMount,
179
+ TFormOnChange,
180
+ TFormOnChangeAsync,
181
+ TFormOnBlur,
182
+ TFormOnBlurAsync,
183
+ TFormOnSubmit,
184
+ TFormOnSubmitAsync,
185
+ TFormOnServer,
186
+ TSubmitMeta
187
+ >,
188
+ ) {
189
+ const options = opts?.()
190
+ const api = new FormApi<
191
+ TParentData,
192
+ TFormOnMount,
193
+ TFormOnChange,
194
+ TFormOnChangeAsync,
195
+ TFormOnBlur,
196
+ TFormOnBlurAsync,
197
+ TFormOnSubmit,
198
+ TFormOnSubmitAsync,
199
+ TFormOnServer,
200
+ TSubmitMeta
201
+ >(options)
202
+ const extendedApi: typeof api &
203
+ SvelteFormApi<
204
+ TParentData,
205
+ TFormOnMount,
206
+ TFormOnChange,
207
+ TFormOnChangeAsync,
208
+ TFormOnBlur,
209
+ TFormOnBlurAsync,
210
+ TFormOnSubmit,
211
+ TFormOnSubmitAsync,
212
+ TFormOnServer,
213
+ TSubmitMeta
214
+ > = api as never
215
+
216
+ // @ts-expect-error constructor definition exists only on a type level
217
+ extendedApi.Field = (internal, props) =>
218
+ Field(internal, { ...props, form: api })
219
+ extendedApi.createField = (props) =>
220
+ createField(() => {
221
+ return { ...props(), form: api }
222
+ }) as never // Type cast because else "Error: Type instantiation is excessively deep and possibly infinite."
223
+ extendedApi.useStore = (selector) => useStore(api.store, selector)
224
+ // @ts-expect-error constructor definition exists only on a type level
225
+ extendedApi.Subscribe = (internal, props) =>
226
+ Subscribe(internal, { ...props, store: api.store })
227
+
228
+ onMount(api.mount)
229
+
230
+ // formApi.update should not have any side effects. Think of it like a `useRef`
231
+ // that we need to keep updated every render with the most up-to-date information.
232
+ $effect.pre(() => api.update(opts?.()))
233
+
234
+ return extendedApi
235
+ }
package/src/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ export * from '@tanstack/form-core'
2
+
3
+ export { useStore } from '@tanstack/svelte-store'
4
+
5
+ export { createForm, type SvelteFormApi } from './createForm.svelte.js'
6
+
7
+ export { default as Field, createField } from './Field.svelte'
8
+
9
+ export type { CreateField, FieldComponent } from './types.js'