@tanstack/vue-form 0.3.4 → 0.3.5
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/build/legacy/createFormFactory.cjs.map +1 -1
- package/build/legacy/createFormFactory.d.cts +1 -1
- package/build/legacy/createFormFactory.d.ts +1 -1
- package/build/legacy/createFormFactory.js.map +1 -1
- package/build/legacy/types.cjs.map +1 -1
- package/build/legacy/types.d.cts +1 -1
- package/build/legacy/types.d.ts +1 -1
- package/build/legacy/useField.cjs.map +1 -1
- package/build/legacy/useField.d.cts +16 -20
- package/build/legacy/useField.d.ts +16 -20
- package/build/legacy/useField.js +1 -3
- package/build/legacy/useField.js.map +1 -1
- package/build/legacy/useForm.cjs.map +1 -1
- package/build/legacy/useForm.d.cts +1 -1
- package/build/legacy/useForm.d.ts +1 -1
- package/build/legacy/useForm.js.map +1 -1
- package/build/modern/createFormFactory.cjs.map +1 -1
- package/build/modern/createFormFactory.d.cts +1 -1
- package/build/modern/createFormFactory.d.ts +1 -1
- package/build/modern/createFormFactory.js.map +1 -1
- package/build/modern/types.cjs.map +1 -1
- package/build/modern/types.d.cts +1 -1
- package/build/modern/types.d.ts +1 -1
- package/build/modern/useField.cjs.map +1 -1
- package/build/modern/useField.d.cts +16 -20
- package/build/modern/useField.d.ts +16 -20
- package/build/modern/useField.js +1 -3
- package/build/modern/useField.js.map +1 -1
- package/build/modern/useForm.cjs.map +1 -1
- package/build/modern/useForm.d.cts +1 -1
- package/build/modern/useForm.d.ts +1 -1
- package/build/modern/useForm.js.map +1 -1
- package/package.json +2 -2
- package/src/createFormFactory.ts +1 -1
- package/src/types.ts +3 -3
- package/src/useField.tsx +58 -55
- package/src/useForm.tsx +1 -1
- package/build/lib/createFormFactory.d.ts +0 -8
- package/build/lib/createFormFactory.js +0 -12
- package/build/lib/formContext.d.ts +0 -11
- package/build/lib/formContext.js +0 -12
- package/build/lib/index.d.ts +0 -5
- package/build/lib/index.js +0 -5
- package/build/lib/tests/useField.test.d.ts +0 -2
- package/build/lib/tests/useField.test.jsx +0 -109
- package/build/lib/tests/useForm.test.d.ts +0 -2
- package/build/lib/tests/useForm.test.jsx +0 -71
- package/build/lib/tests/utils.d.ts +0 -1
- package/build/lib/tests/utils.js +0 -5
- package/build/lib/types.d.ts +0 -4
- package/build/lib/types.js +0 -1
- package/build/lib/useField.d.ts +0 -42
- package/build/lib/useField.jsx +0 -41
- package/build/lib/useForm.d.ts +0 -19
- package/build/lib/useForm.jsx +0 -35
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, type FormState, type FormOptions } from '@tanstack/form-core'\nimport { type NoInfer, useStore } from '@tanstack/vue-store'\nimport { type UseField, type FieldComponent, Field, useField } from './useField'\nimport { provideFormContext } from './formContext'\nimport {\n type EmitsOptions,\n type SlotsType,\n type SetupContext,\n defineComponent,\n} from 'vue-demi'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData> {\n Provider: (props: Record<string, any> & {}) => any\n provideFormContext: () => void\n Field: FieldComponent<TFormData
|
1
|
+
{"version":3,"sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, type FormState, type FormOptions } from '@tanstack/form-core'\nimport { type NoInfer, useStore } from '@tanstack/vue-store'\nimport { type UseField, type FieldComponent, Field, useField } from './useField'\nimport { provideFormContext } from './formContext'\nimport {\n type EmitsOptions,\n type SlotsType,\n type SetupContext,\n defineComponent,\n} from 'vue-demi'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData> {\n Provider: (props: Record<string, any> & {}) => any\n provideFormContext: () => void\n Field: FieldComponent<TFormData>\n useField: UseField<TFormData>\n useStore: <TSelected = NoInfer<FormState<TFormData>>>(\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,\n ) => TSelected\n Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(\n props: {\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected\n },\n context: SetupContext<\n EmitsOptions,\n SlotsType<{ default: NoInfer<FormState<TFormData>> }>\n >,\n ) => any\n }\n}\n\nexport function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {\n const formApi = (() => {\n const api = new FormApi<TData>(opts)\n\n api.Provider = defineComponent(\n (_, context) => {\n provideFormContext({ formApi })\n return () => context.slots.default!()\n },\n { name: 'Provider' },\n )\n api.provideFormContext = () => {\n provideFormContext({ formApi })\n }\n api.Field = Field as never\n api.useField = useField as never\n api.useStore = (selector) => {\n return useStore(api.store as never, selector as never) as never\n }\n api.Subscribe = defineComponent(\n (props, context) => {\n const allProps = { ...props, ...context.attrs }\n const selector = allProps.selector ?? ((state) => state)\n const data = useStore(api.store as never, selector as never)\n return () => context.slots.default!(data.value)\n },\n {\n name: 'Subscribe',\n inheritAttrs: false,\n },\n )\n\n return api\n })()\n\n // formApi.useStore((state) => state.isSubmitting)\n formApi.update(opts)\n\n return formApi as never\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAA0D;AAC1D,uBAAuC;AACvC,sBAAoE;AACpE,yBAAmC;AACnC,sBAKO;AAwBA,SAAS,QAAe,MAA2C;AACxE,QAAM,WAAW,MAAM;AACrB,UAAM,MAAM,IAAI,yBAAe,IAAI;AAEnC,QAAI,eAAW;AAAA,MACb,CAAC,GAAG,YAAY;AACd,mDAAmB,EAAE,QAAQ,CAAC;AAC9B,eAAO,MAAM,QAAQ,MAAM,QAAS;AAAA,MACtC;AAAA,MACA,EAAE,MAAM,WAAW;AAAA,IACrB;AACA,QAAI,qBAAqB,MAAM;AAC7B,iDAAmB,EAAE,QAAQ,CAAC;AAAA,IAChC;AACA,QAAI,QAAQ;AACZ,QAAI,WAAW;AACf,QAAI,WAAW,CAAC,aAAa;AAC3B,iBAAO,2BAAS,IAAI,OAAgB,QAAiB;AAAA,IACvD;AACA,QAAI,gBAAY;AAAA,MACd,CAAC,OAAO,YAAY;AAClB,cAAM,WAAW,EAAE,GAAG,OAAO,GAAG,QAAQ,MAAM;AAC9C,cAAM,WAAW,SAAS,aAAa,CAAC,UAAU;AAClD,cAAM,WAAO,2BAAS,IAAI,OAAgB,QAAiB;AAC3D,eAAO,MAAM,QAAQ,MAAM,QAAS,KAAK,KAAK;AAAA,MAChD;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,cAAc;AAAA,MAChB;AAAA,IACF;AAEA,WAAO;AAAA,EACT,GAAG;AAGH,UAAQ,OAAO,IAAI;AAEnB,SAAO;AACT;","names":[]}
|
@@ -8,7 +8,7 @@ declare module '@tanstack/form-core' {
|
|
8
8
|
interface FormApi<TFormData> {
|
9
9
|
Provider: (props: Record<string, any> & {}) => any;
|
10
10
|
provideFormContext: () => void;
|
11
|
-
Field: FieldComponent<TFormData
|
11
|
+
Field: FieldComponent<TFormData>;
|
12
12
|
useField: UseField<TFormData>;
|
13
13
|
useStore: <TSelected = NoInfer<FormState<TFormData>>>(selector?: (state: NoInfer<FormState<TFormData>>) => TSelected) => TSelected;
|
14
14
|
Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {
|
@@ -8,7 +8,7 @@ declare module '@tanstack/form-core' {
|
|
8
8
|
interface FormApi<TFormData> {
|
9
9
|
Provider: (props: Record<string, any> & {}) => any;
|
10
10
|
provideFormContext: () => void;
|
11
|
-
Field: FieldComponent<TFormData
|
11
|
+
Field: FieldComponent<TFormData>;
|
12
12
|
useField: UseField<TFormData>;
|
13
13
|
useStore: <TSelected = NoInfer<FormState<TFormData>>>(selector?: (state: NoInfer<FormState<TFormData>>) => TSelected) => TSelected;
|
14
14
|
Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, type FormState, type FormOptions } from '@tanstack/form-core'\nimport { type NoInfer, useStore } from '@tanstack/vue-store'\nimport { type UseField, type FieldComponent, Field, useField } from './useField'\nimport { provideFormContext } from './formContext'\nimport {\n type EmitsOptions,\n type SlotsType,\n type SetupContext,\n defineComponent,\n} from 'vue-demi'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData> {\n Provider: (props: Record<string, any> & {}) => any\n provideFormContext: () => void\n Field: FieldComponent<TFormData
|
1
|
+
{"version":3,"sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, type FormState, type FormOptions } from '@tanstack/form-core'\nimport { type NoInfer, useStore } from '@tanstack/vue-store'\nimport { type UseField, type FieldComponent, Field, useField } from './useField'\nimport { provideFormContext } from './formContext'\nimport {\n type EmitsOptions,\n type SlotsType,\n type SetupContext,\n defineComponent,\n} from 'vue-demi'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData> {\n Provider: (props: Record<string, any> & {}) => any\n provideFormContext: () => void\n Field: FieldComponent<TFormData>\n useField: UseField<TFormData>\n useStore: <TSelected = NoInfer<FormState<TFormData>>>(\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,\n ) => TSelected\n Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(\n props: {\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected\n },\n context: SetupContext<\n EmitsOptions,\n SlotsType<{ default: NoInfer<FormState<TFormData>> }>\n >,\n ) => any\n }\n}\n\nexport function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {\n const formApi = (() => {\n const api = new FormApi<TData>(opts)\n\n api.Provider = defineComponent(\n (_, context) => {\n provideFormContext({ formApi })\n return () => context.slots.default!()\n },\n { name: 'Provider' },\n )\n api.provideFormContext = () => {\n provideFormContext({ formApi })\n }\n api.Field = Field as never\n api.useField = useField as never\n api.useStore = (selector) => {\n return useStore(api.store as never, selector as never) as never\n }\n api.Subscribe = defineComponent(\n (props, context) => {\n const allProps = { ...props, ...context.attrs }\n const selector = allProps.selector ?? ((state) => state)\n const data = useStore(api.store as never, selector as never)\n return () => context.slots.default!(data.value)\n },\n {\n name: 'Subscribe',\n inheritAttrs: false,\n },\n )\n\n return api\n })()\n\n // formApi.useStore((state) => state.isSubmitting)\n formApi.update(opts)\n\n return formApi as never\n}\n"],"mappings":";AAAA,SAAS,eAAiD;AAC1D,SAAuB,gBAAgB;AACvC,SAA6C,OAAO,gBAAgB;AACpE,SAAS,0BAA0B;AACnC;AAAA,EAIE;AAAA,OACK;AAwBA,SAAS,QAAe,MAA2C;AACxE,QAAM,WAAW,MAAM;AACrB,UAAM,MAAM,IAAI,QAAe,IAAI;AAEnC,QAAI,WAAW;AAAA,MACb,CAAC,GAAG,YAAY;AACd,2BAAmB,EAAE,QAAQ,CAAC;AAC9B,eAAO,MAAM,QAAQ,MAAM,QAAS;AAAA,MACtC;AAAA,MACA,EAAE,MAAM,WAAW;AAAA,IACrB;AACA,QAAI,qBAAqB,MAAM;AAC7B,yBAAmB,EAAE,QAAQ,CAAC;AAAA,IAChC;AACA,QAAI,QAAQ;AACZ,QAAI,WAAW;AACf,QAAI,WAAW,CAAC,aAAa;AAC3B,aAAO,SAAS,IAAI,OAAgB,QAAiB;AAAA,IACvD;AACA,QAAI,YAAY;AAAA,MACd,CAAC,OAAO,YAAY;AAClB,cAAM,WAAW,EAAE,GAAG,OAAO,GAAG,QAAQ,MAAM;AAC9C,cAAM,WAAW,SAAS,aAAa,CAAC,UAAU;AAClD,cAAM,OAAO,SAAS,IAAI,OAAgB,QAAiB;AAC3D,eAAO,MAAM,QAAQ,MAAM,QAAS,KAAK,KAAK;AAAA,MAChD;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,cAAc;AAAA,MAChB;AAAA,IACF;AAEA,WAAO;AAAA,EACT,GAAG;AAGH,UAAQ,OAAO,IAAI;AAEnB,SAAO;AACT;","names":[]}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@tanstack/vue-form",
|
3
|
-
"version": "0.3.
|
3
|
+
"version": "0.3.5",
|
4
4
|
"description": "Powerful, type-safe forms for Vue.",
|
5
5
|
"author": "tannerlinsley",
|
6
6
|
"license": "MIT",
|
@@ -45,7 +45,7 @@
|
|
45
45
|
"@tanstack/store": "0.1.3",
|
46
46
|
"@tanstack/vue-store": "0.1.3",
|
47
47
|
"vue-demi": "^0.14.6",
|
48
|
-
"@tanstack/form-core": "0.3.
|
48
|
+
"@tanstack/form-core": "0.3.5"
|
49
49
|
},
|
50
50
|
"devDependencies": {
|
51
51
|
"@vue/composition-api": "1.7.2",
|
package/src/createFormFactory.ts
CHANGED
@@ -6,7 +6,7 @@ import { useForm } from './useForm'
|
|
6
6
|
export type FormFactory<TFormData> = {
|
7
7
|
useForm: (opts?: FormOptions<TFormData>) => FormApi<TFormData>
|
8
8
|
useField: UseField<TFormData>
|
9
|
-
Field: FieldComponent<TFormData
|
9
|
+
Field: FieldComponent<TFormData>
|
10
10
|
}
|
11
11
|
|
12
12
|
export function createFormFactory<TFormData>(
|
package/src/types.ts
CHANGED
@@ -2,8 +2,8 @@ import type { FieldOptions, DeepKeys } from '@tanstack/form-core'
|
|
2
2
|
|
3
3
|
export type UseFieldOptions<
|
4
4
|
TData,
|
5
|
-
|
6
|
-
TName
|
7
|
-
> = FieldOptions<TData,
|
5
|
+
TParentData,
|
6
|
+
TName extends DeepKeys<TParentData>,
|
7
|
+
> = FieldOptions<TData, TParentData, TName> & {
|
8
8
|
mode?: 'value' | 'array'
|
9
9
|
}
|
package/src/useField.tsx
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
import {
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
import { FieldApi } from '@tanstack/form-core'
|
2
|
+
import type {
|
3
|
+
DeepKeys,
|
4
|
+
DeepValue,
|
5
|
+
Narrow,
|
6
|
+
ResolveData,
|
5
7
|
} from '@tanstack/form-core'
|
6
|
-
import type { DeepKeys, DeepValue, Narrow } from '@tanstack/form-core'
|
7
8
|
import { useStore } from '@tanstack/vue-store'
|
8
9
|
import { defineComponent, onMounted, onUnmounted, watch } from 'vue-demi'
|
9
10
|
import type { SlotsType, SetupContext, Ref } from 'vue-demi'
|
@@ -12,44 +13,52 @@ import type { UseFieldOptions } from './types'
|
|
12
13
|
|
13
14
|
declare module '@tanstack/form-core' {
|
14
15
|
// eslint-disable-next-line no-shadow
|
15
|
-
interface FieldApi<
|
16
|
-
|
16
|
+
interface FieldApi<
|
17
|
+
TData,
|
18
|
+
TParentData,
|
19
|
+
TName extends DeepKeys<TParentData>,
|
20
|
+
TResolvedData extends ResolveData<TData, TParentData, TName> = ResolveData<
|
21
|
+
TData,
|
22
|
+
TParentData,
|
23
|
+
TName
|
24
|
+
>,
|
25
|
+
> {
|
26
|
+
Field: FieldComponent<TResolvedData>
|
17
27
|
}
|
18
28
|
}
|
19
29
|
|
20
|
-
export type UseField<
|
21
|
-
opts?: { name: Narrow<
|
22
|
-
DeepValue<
|
23
|
-
|
30
|
+
export type UseField<TParentData> = <TName extends DeepKeys<TParentData>>(
|
31
|
+
opts?: { name: Narrow<TName> } & UseFieldOptions<
|
32
|
+
DeepValue<TParentData, TName>,
|
33
|
+
TParentData,
|
34
|
+
TName
|
24
35
|
>,
|
25
|
-
) => FieldApi<DeepValue<
|
36
|
+
) => FieldApi<DeepValue<TParentData, TName>, TParentData, TName>
|
26
37
|
|
27
38
|
export function useField<
|
28
39
|
TData,
|
29
|
-
|
30
|
-
TName extends
|
31
|
-
? string
|
32
|
-
: DeepKeys<TFormData> = unknown extends TFormData
|
33
|
-
? string
|
34
|
-
: DeepKeys<TFormData>,
|
40
|
+
TParentData,
|
41
|
+
TName extends DeepKeys<TParentData>,
|
35
42
|
>(
|
36
|
-
opts: UseFieldOptions<TData,
|
43
|
+
opts: UseFieldOptions<TData, TParentData, TName>,
|
37
44
|
): {
|
38
45
|
api: FieldApi<
|
39
46
|
TData,
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
47
|
+
TParentData,
|
48
|
+
TName
|
49
|
+
// Omit<typeof opts, 'onMount'> & {
|
50
|
+
// form: FormApi<TParentData>
|
51
|
+
// }
|
44
52
|
>
|
45
53
|
state: Readonly<
|
46
54
|
Ref<
|
47
55
|
FieldApi<
|
48
56
|
TData,
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
57
|
+
TParentData,
|
58
|
+
TName
|
59
|
+
// Omit<typeof opts, 'onMount'> & {
|
60
|
+
// form: FormApi<TParentData>
|
61
|
+
// }
|
53
62
|
>['state']
|
54
63
|
>
|
55
64
|
>
|
@@ -91,17 +100,16 @@ export function useField<
|
|
91
100
|
return { api: fieldApi, state: fieldState } as never
|
92
101
|
}
|
93
102
|
|
94
|
-
export type FieldValue<
|
95
|
-
? unknown extends
|
96
|
-
?
|
97
|
-
: DeepValue<
|
98
|
-
: DeepValue<
|
103
|
+
export type FieldValue<TParentData, TName> = TParentData extends any[]
|
104
|
+
? unknown extends TName
|
105
|
+
? TParentData[number]
|
106
|
+
: DeepValue<TParentData[number], TName>
|
107
|
+
: DeepValue<TParentData, TName>
|
99
108
|
|
100
109
|
type FieldComponentProps<
|
110
|
+
TData,
|
101
111
|
TParentData,
|
102
|
-
|
103
|
-
TField,
|
104
|
-
TName extends unknown extends TFormData ? string : DeepKeys<TFormData>,
|
112
|
+
TName extends DeepKeys<TParentData>,
|
105
113
|
> = (TParentData extends any[]
|
106
114
|
? {
|
107
115
|
name?: TName
|
@@ -111,40 +119,35 @@ type FieldComponentProps<
|
|
111
119
|
name: TName
|
112
120
|
index?: never
|
113
121
|
}) &
|
114
|
-
Omit<UseFieldOptions<
|
122
|
+
Omit<UseFieldOptions<TData, TParentData, TName>, 'name' | 'index'>
|
115
123
|
|
116
|
-
export type FieldComponent<TParentData
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
124
|
+
export type FieldComponent<TParentData> = <
|
125
|
+
TData,
|
126
|
+
TName extends DeepKeys<TParentData>,
|
127
|
+
TResolvedData extends ResolveData<TData, TParentData, TName> = ResolveData<
|
128
|
+
TData,
|
129
|
+
TParentData,
|
130
|
+
TName
|
131
|
+
>,
|
121
132
|
>(
|
122
|
-
fieldOptions: FieldComponentProps<
|
133
|
+
fieldOptions: FieldComponentProps<TData, TParentData, TName>,
|
123
134
|
context: SetupContext<
|
124
135
|
{},
|
125
136
|
SlotsType<{
|
126
137
|
default: {
|
127
|
-
field: FieldApi<
|
128
|
-
|
129
|
-
TFormData,
|
130
|
-
FieldApiOptions<TField, TFormData, TName>
|
131
|
-
>
|
132
|
-
state: FieldApi<
|
133
|
-
TField,
|
134
|
-
TFormData,
|
135
|
-
FieldApiOptions<TField, TFormData, TName>
|
136
|
-
>['state']
|
138
|
+
field: FieldApi<TData, TParentData, TName, TResolvedData>
|
139
|
+
state: FieldApi<TData, TParentData, TName, TResolvedData>['state']
|
137
140
|
}
|
138
141
|
}>
|
139
142
|
>,
|
140
143
|
) => any
|
141
144
|
|
142
145
|
export const Field = defineComponent(
|
143
|
-
<TData,
|
144
|
-
fieldOptions: UseFieldOptions<TData,
|
146
|
+
<TData, TParentData, TName extends DeepKeys<TParentData>>(
|
147
|
+
fieldOptions: UseFieldOptions<TData, TParentData, TName>,
|
145
148
|
context: SetupContext,
|
146
149
|
) => {
|
147
|
-
const fieldApi = useField({ ...fieldOptions, ...context.attrs })
|
150
|
+
const fieldApi = useField({ ...fieldOptions, ...context.attrs } as any)
|
148
151
|
|
149
152
|
provideFormContext({
|
150
153
|
formApi: fieldApi.api.form,
|
package/src/useForm.tsx
CHANGED
@@ -14,7 +14,7 @@ declare module '@tanstack/form-core' {
|
|
14
14
|
interface FormApi<TFormData> {
|
15
15
|
Provider: (props: Record<string, any> & {}) => any
|
16
16
|
provideFormContext: () => void
|
17
|
-
Field: FieldComponent<TFormData
|
17
|
+
Field: FieldComponent<TFormData>
|
18
18
|
useField: UseField<TFormData>
|
19
19
|
useStore: <TSelected = NoInfer<FormState<TFormData>>>(
|
20
20
|
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,
|
@@ -1,8 +0,0 @@
|
|
1
|
-
import type { FormApi, FormOptions } from '@tanstack/form-core';
|
2
|
-
import { type UseField, type FieldComponent } from './useField';
|
3
|
-
export type FormFactory<TFormData> = {
|
4
|
-
useForm: (opts?: FormOptions<TFormData>) => FormApi<TFormData>;
|
5
|
-
useField: UseField<TFormData>;
|
6
|
-
Field: FieldComponent<TFormData, TFormData>;
|
7
|
-
};
|
8
|
-
export declare function createFormFactory<TFormData>(defaultOpts?: FormOptions<TFormData>): FormFactory<TFormData>;
|
@@ -1,12 +0,0 @@
|
|
1
|
-
import { Field, useField } from './useField';
|
2
|
-
import { useForm } from './useForm';
|
3
|
-
export function createFormFactory(defaultOpts) {
|
4
|
-
return {
|
5
|
-
useForm: (opts) => {
|
6
|
-
const formOptions = Object.assign({}, defaultOpts, opts);
|
7
|
-
return useForm(formOptions);
|
8
|
-
},
|
9
|
-
useField: useField,
|
10
|
-
Field: Field,
|
11
|
-
};
|
12
|
-
}
|
@@ -1,11 +0,0 @@
|
|
1
|
-
import type { FormApi } from '@tanstack/form-core';
|
2
|
-
export type FormContext = {
|
3
|
-
formApi: FormApi<any>;
|
4
|
-
parentFieldName?: string;
|
5
|
-
} | null;
|
6
|
-
export declare const formContext: unique symbol;
|
7
|
-
export declare function provideFormContext(val: FormContext): void;
|
8
|
-
export declare function useFormContext(): {
|
9
|
-
formApi: FormApi<any>;
|
10
|
-
parentFieldName?: string | undefined;
|
11
|
-
};
|
package/build/lib/formContext.js
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
import { inject, provide } from 'vue-demi';
|
2
|
-
export const formContext = Symbol('FormContext');
|
3
|
-
export function provideFormContext(val) {
|
4
|
-
provide(formContext, val);
|
5
|
-
}
|
6
|
-
export function useFormContext() {
|
7
|
-
const formApi = inject(formContext);
|
8
|
-
if (!formApi) {
|
9
|
-
throw new Error(`You are trying to use the form API outside of a form!`);
|
10
|
-
}
|
11
|
-
return formApi;
|
12
|
-
}
|
package/build/lib/index.d.ts
DELETED
package/build/lib/index.js
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
/// <reference lib="dom" />
|
2
|
-
import { defineComponent } from 'vue-demi';
|
3
|
-
import { render, waitFor } from '@testing-library/vue';
|
4
|
-
import '@testing-library/jest-dom';
|
5
|
-
import { createFormFactory, provideFormContext, } from '../index';
|
6
|
-
import userEvent from '@testing-library/user-event';
|
7
|
-
import { sleep } from './utils';
|
8
|
-
const user = userEvent.setup();
|
9
|
-
describe('useField', () => {
|
10
|
-
it('should allow to set default value', async () => {
|
11
|
-
const formFactory = createFormFactory();
|
12
|
-
const Comp = defineComponent(() => {
|
13
|
-
const form = formFactory.useForm();
|
14
|
-
provideFormContext({ formApi: form });
|
15
|
-
return () => (<form.Field name="firstName" defaultValue="FirstName">
|
16
|
-
{({ field }) => (<input data-testid={'fieldinput'} value={field.state.value} onBlur={field.handleBlur} onInput={(e) => field.handleChange(e.target.value)}/>)}
|
17
|
-
</form.Field>);
|
18
|
-
});
|
19
|
-
const { getByTestId } = render(Comp);
|
20
|
-
const input = getByTestId('fieldinput');
|
21
|
-
await waitFor(() => expect(input).toHaveValue('FirstName'));
|
22
|
-
});
|
23
|
-
it('should not validate on change if isTouched is false', async () => {
|
24
|
-
const error = 'Please enter a different value';
|
25
|
-
const formFactory = createFormFactory();
|
26
|
-
const Comp = defineComponent(() => {
|
27
|
-
const form = formFactory.useForm();
|
28
|
-
provideFormContext({ formApi: form });
|
29
|
-
return () => (<form.Field name="firstName" onChange={(value) => (value === 'other' ? error : undefined)}>
|
30
|
-
{({ field }) => (<div>
|
31
|
-
<input data-testid="fieldinput" name={field.name} value={field.state.value} onBlur={field.handleBlur} onInput={(e) => field.setValue(e.target.value)}/>
|
32
|
-
<p>{field.getMeta().errors}</p>
|
33
|
-
</div>)}
|
34
|
-
</form.Field>);
|
35
|
-
});
|
36
|
-
const { getByTestId, queryByText } = render(Comp);
|
37
|
-
const input = getByTestId('fieldinput');
|
38
|
-
await user.type(input, 'other');
|
39
|
-
expect(queryByText(error)).not.toBeInTheDocument();
|
40
|
-
});
|
41
|
-
it('should validate on change if isTouched is true', async () => {
|
42
|
-
const error = 'Please enter a different value';
|
43
|
-
const formFactory = createFormFactory();
|
44
|
-
const Comp = defineComponent(() => {
|
45
|
-
const form = formFactory.useForm();
|
46
|
-
provideFormContext({ formApi: form });
|
47
|
-
return () => (<form.Field name="firstName" onChange={(value) => (value === 'other' ? error : undefined)}>
|
48
|
-
{({ field }) => (<div>
|
49
|
-
<input data-testid="fieldinput" name={field.name} value={field.state.value} onBlur={field.handleBlur} onInput={(e) => field.handleChange(e.target.value)}/>
|
50
|
-
<p>{field.getMeta().errors}</p>
|
51
|
-
</div>)}
|
52
|
-
</form.Field>);
|
53
|
-
});
|
54
|
-
const { getByTestId, getByText, queryByText } = render(Comp);
|
55
|
-
const input = getByTestId('fieldinput');
|
56
|
-
expect(queryByText(error)).not.toBeInTheDocument();
|
57
|
-
await user.type(input, 'other');
|
58
|
-
expect(getByText(error)).toBeInTheDocument();
|
59
|
-
});
|
60
|
-
it('should validate async on change', async () => {
|
61
|
-
const error = 'Please enter a different value';
|
62
|
-
const formFactory = createFormFactory();
|
63
|
-
const Comp = defineComponent(() => {
|
64
|
-
const form = formFactory.useForm();
|
65
|
-
provideFormContext({ formApi: form });
|
66
|
-
return () => (<form.Field name="firstName" defaultMeta={{ isTouched: true }} onChangeAsync={async () => {
|
67
|
-
await sleep(10);
|
68
|
-
return error;
|
69
|
-
}}>
|
70
|
-
{({ field }) => (<div>
|
71
|
-
<input data-testid="fieldinput" name={field.name} value={field.state.value} onBlur={field.handleBlur} onInput={(e) => field.handleChange(e.target.value)}/>
|
72
|
-
<p>{field.getMeta().errors}</p>
|
73
|
-
</div>)}
|
74
|
-
</form.Field>);
|
75
|
-
});
|
76
|
-
const { getByTestId, getByText, queryByText } = render(Comp);
|
77
|
-
const input = getByTestId('fieldinput');
|
78
|
-
expect(queryByText(error)).not.toBeInTheDocument();
|
79
|
-
await user.type(input, 'other');
|
80
|
-
await waitFor(() => getByText(error));
|
81
|
-
expect(getByText(error)).toBeInTheDocument();
|
82
|
-
});
|
83
|
-
it('should validate async on change with debounce', async () => {
|
84
|
-
const mockFn = vi.fn();
|
85
|
-
const error = 'Please enter a different value';
|
86
|
-
const formFactory = createFormFactory();
|
87
|
-
const Comp = defineComponent(() => {
|
88
|
-
const form = formFactory.useForm();
|
89
|
-
provideFormContext({ formApi: form });
|
90
|
-
return () => (<form.Field name="firstName" defaultMeta={{ isTouched: true }} onChangeAsyncDebounceMs={100} onChangeAsync={async () => {
|
91
|
-
mockFn();
|
92
|
-
await sleep(10);
|
93
|
-
return error;
|
94
|
-
}}>
|
95
|
-
{({ field }) => (<div>
|
96
|
-
<input data-testid="fieldinput" name={field.name} value={field.state.value} onBlur={field.handleBlur} onInput={(e) => field.handleChange(e.target.value)}/>
|
97
|
-
<p>{field.getMeta().errors}</p>
|
98
|
-
</div>)}
|
99
|
-
</form.Field>);
|
100
|
-
});
|
101
|
-
const { getByTestId, getByText } = render(<Comp />);
|
102
|
-
const input = getByTestId('fieldinput');
|
103
|
-
await user.type(input, 'other');
|
104
|
-
// mockFn will have been called 5 times without onChangeAsyncDebounceMs
|
105
|
-
expect(mockFn).toHaveBeenCalledTimes(0);
|
106
|
-
await waitFor(() => getByText(error));
|
107
|
-
expect(getByText(error)).toBeInTheDocument();
|
108
|
-
});
|
109
|
-
});
|
@@ -1,71 +0,0 @@
|
|
1
|
-
/// <reference lib="dom" />
|
2
|
-
import { defineComponent, ref } from 'vue-demi';
|
3
|
-
import { render, waitFor } from '@testing-library/vue';
|
4
|
-
import '@testing-library/jest-dom';
|
5
|
-
import { createFormFactory, provideFormContext, useForm, } from '../index';
|
6
|
-
import userEvent from '@testing-library/user-event';
|
7
|
-
const user = userEvent.setup();
|
8
|
-
describe('useForm', () => {
|
9
|
-
it('preserved field state', async () => {
|
10
|
-
const formFactory = createFormFactory();
|
11
|
-
const Comp = defineComponent(() => {
|
12
|
-
const form = formFactory.useForm();
|
13
|
-
provideFormContext({ formApi: form });
|
14
|
-
return () => (<form.Field name="firstName" defaultValue="">
|
15
|
-
{({ field }) => (<input data-testid={'fieldinput'} value={field.state.value} onBlur={field.handleBlur} onInput={(e) => field.handleChange(e.target.value)}/>)}
|
16
|
-
</form.Field>);
|
17
|
-
});
|
18
|
-
const { getByTestId, queryByText } = render(Comp);
|
19
|
-
const input = getByTestId('fieldinput');
|
20
|
-
expect(queryByText('FirstName')).not.toBeInTheDocument();
|
21
|
-
await user.type(input, 'FirstName');
|
22
|
-
expect(input).toHaveValue('FirstName');
|
23
|
-
});
|
24
|
-
it('should allow default values to be set', async () => {
|
25
|
-
const formFactory = createFormFactory();
|
26
|
-
const Comp = defineComponent(() => {
|
27
|
-
const form = formFactory.useForm({
|
28
|
-
defaultValues: {
|
29
|
-
firstName: 'FirstName',
|
30
|
-
lastName: 'LastName',
|
31
|
-
},
|
32
|
-
});
|
33
|
-
form.provideFormContext();
|
34
|
-
return () => (<form.Field name="firstName" defaultValue="">
|
35
|
-
{({ field }) => (<p>{field.state.value}</p>)}
|
36
|
-
</form.Field>);
|
37
|
-
});
|
38
|
-
const { findByText, queryByText } = render(Comp);
|
39
|
-
expect(await findByText('FirstName')).toBeInTheDocument();
|
40
|
-
expect(queryByText('LastName')).not.toBeInTheDocument();
|
41
|
-
});
|
42
|
-
it('should handle submitting properly', async () => {
|
43
|
-
const Comp = defineComponent(() => {
|
44
|
-
const submittedData = ref();
|
45
|
-
const form = useForm({
|
46
|
-
defaultValues: {
|
47
|
-
firstName: 'FirstName',
|
48
|
-
},
|
49
|
-
onSubmit: (data) => {
|
50
|
-
submittedData.value = data;
|
51
|
-
},
|
52
|
-
});
|
53
|
-
form.provideFormContext();
|
54
|
-
return () => (<form.Provider>
|
55
|
-
<form.Field name="firstName">
|
56
|
-
{({ field, }) => {
|
57
|
-
return (<input value={field.state.value} onBlur={field.handleBlur} onChange={(e) => field.handleChange(e.target.value)} placeholder={'First name'}/>);
|
58
|
-
}}
|
59
|
-
</form.Field>
|
60
|
-
<button onClick={form.handleSubmit}>Submit</button>
|
61
|
-
{submittedData.value && (<p>Submitted data: {submittedData.value.firstName}</p>)}
|
62
|
-
</form.Provider>);
|
63
|
-
});
|
64
|
-
const { findByPlaceholderText, getByText } = render(Comp);
|
65
|
-
const input = await findByPlaceholderText('First name');
|
66
|
-
await user.clear(input);
|
67
|
-
await user.type(input, 'OtherName');
|
68
|
-
await user.click(getByText('Submit'));
|
69
|
-
await waitFor(() => expect(getByText('Submitted data: OtherName')).toBeInTheDocument());
|
70
|
-
});
|
71
|
-
});
|
@@ -1 +0,0 @@
|
|
1
|
-
export declare function sleep(timeout: number): Promise<void>;
|
package/build/lib/tests/utils.js
DELETED
package/build/lib/types.d.ts
DELETED
package/build/lib/types.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export {};
|
package/build/lib/useField.d.ts
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
import { FieldApi, type FieldApiOptions, type FormApi } from '@tanstack/form-core';
|
2
|
-
import type { DeepKeys, DeepValue, Narrow } from '@tanstack/form-core';
|
3
|
-
import type { SlotsType, SetupContext, Ref } from 'vue-demi';
|
4
|
-
import type { UseFieldOptions } from './types';
|
5
|
-
declare module '@tanstack/form-core' {
|
6
|
-
interface FieldApi<_TData, TFormData, Opts, TData> {
|
7
|
-
Field: FieldComponent<TFormData, TData>;
|
8
|
-
}
|
9
|
-
}
|
10
|
-
export type UseField<TFormData> = <TField extends DeepKeys<TFormData>>(opts?: {
|
11
|
-
name: Narrow<TField>;
|
12
|
-
} & UseFieldOptions<DeepValue<TFormData, TField>, TFormData>) => FieldApi<DeepValue<TFormData, TField>, TFormData>;
|
13
|
-
export declare function useField<TData, TFormData, TName extends unknown extends TFormData ? string : DeepKeys<TFormData> = unknown extends TFormData ? string : DeepKeys<TFormData>>(opts: UseFieldOptions<TData, TFormData, TName>): {
|
14
|
-
api: FieldApi<TData, TFormData, Omit<typeof opts, 'onMount'> & {
|
15
|
-
form: FormApi<TFormData>;
|
16
|
-
}>;
|
17
|
-
state: Readonly<Ref<FieldApi<TData, TFormData, Omit<typeof opts, 'onMount'> & {
|
18
|
-
form: FormApi<TFormData>;
|
19
|
-
}>['state']>>;
|
20
|
-
};
|
21
|
-
export type FieldValue<TFormData, TField> = TFormData extends any[] ? unknown extends TField ? TFormData[number] : DeepValue<TFormData[number], TField> : DeepValue<TFormData, TField>;
|
22
|
-
type FieldComponentProps<TParentData, TFormData, TField, TName extends unknown extends TFormData ? string : DeepKeys<TFormData>> = (TParentData extends any[] ? {
|
23
|
-
name?: TName;
|
24
|
-
index: number;
|
25
|
-
} : {
|
26
|
-
name: TName;
|
27
|
-
index?: never;
|
28
|
-
}) & Omit<UseFieldOptions<TField, TFormData, TName>, 'name' | 'index'>;
|
29
|
-
export type FieldComponent<TParentData, TFormData> = <TField, TName extends unknown extends TFormData ? string : DeepKeys<TFormData>>(fieldOptions: FieldComponentProps<TParentData, TFormData, TField, TName>, context: SetupContext<{}, SlotsType<{
|
30
|
-
default: {
|
31
|
-
field: FieldApi<TField, TFormData, FieldApiOptions<TField, TFormData, TName>>;
|
32
|
-
state: FieldApi<TField, TFormData, FieldApiOptions<TField, TFormData, TName>>['state'];
|
33
|
-
};
|
34
|
-
}>>) => any;
|
35
|
-
export declare const Field: <TData, TFormData>(props: import("@tanstack/form-core").FieldOptions<TData, TFormData, unknown extends TFormData ? string : DeepKeys<TFormData>, unknown extends TData ? DeepValue<TFormData, unknown extends TFormData ? string : DeepKeys<TFormData>> : TData> & {
|
36
|
-
mode?: "value" | "array" | undefined;
|
37
|
-
} & ({
|
38
|
-
[x: `on${Capitalize<string>}`]: ((...args: never) => any) | undefined;
|
39
|
-
} | {
|
40
|
-
[x: `on${Capitalize<string>}`]: ((...args: any[]) => any) | undefined;
|
41
|
-
})) => any;
|
42
|
-
export {};
|
package/build/lib/useField.jsx
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
import { FieldApi, } from '@tanstack/form-core';
|
2
|
-
import { useStore } from '@tanstack/vue-store';
|
3
|
-
import { defineComponent, onMounted, onUnmounted, watch } from 'vue-demi';
|
4
|
-
import { provideFormContext, useFormContext } from './formContext';
|
5
|
-
export function useField(opts) {
|
6
|
-
// Get the form API either manually or from context
|
7
|
-
const { formApi, parentFieldName } = useFormContext();
|
8
|
-
const fieldApi = (() => {
|
9
|
-
const api = new FieldApi({
|
10
|
-
...opts,
|
11
|
-
form: formApi,
|
12
|
-
name: opts.name,
|
13
|
-
});
|
14
|
-
api.Field = Field;
|
15
|
-
return api;
|
16
|
-
})();
|
17
|
-
const fieldState = useStore(fieldApi.store, (state) => state);
|
18
|
-
let cleanup;
|
19
|
-
onMounted(() => {
|
20
|
-
cleanup = fieldApi.mount();
|
21
|
-
});
|
22
|
-
onUnmounted(() => {
|
23
|
-
cleanup();
|
24
|
-
});
|
25
|
-
watch(() => opts, () => {
|
26
|
-
// Keep options up to date as they are rendered
|
27
|
-
fieldApi.update({ ...opts, form: formApi });
|
28
|
-
});
|
29
|
-
return { api: fieldApi, state: fieldState };
|
30
|
-
}
|
31
|
-
export const Field = defineComponent((fieldOptions, context) => {
|
32
|
-
const fieldApi = useField({ ...fieldOptions, ...context.attrs });
|
33
|
-
provideFormContext({
|
34
|
-
formApi: fieldApi.api.form,
|
35
|
-
parentFieldName: fieldApi.api.name,
|
36
|
-
});
|
37
|
-
return () => context.slots.default({
|
38
|
-
field: fieldApi.api,
|
39
|
-
state: fieldApi.state.value,
|
40
|
-
});
|
41
|
-
}, { name: 'Field', inheritAttrs: false });
|