@tanstack/vue-form 2.0.0-alpha.1 → 2.0.0-alpha.3

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.
@@ -1,6 +1,9 @@
1
- import { AnyVueFormComponentMap } from "./componentMap.public.js";
2
- import { AppFormHookResult } from "./createFormHookTypes.public.js";
1
+ import { AppFormHookResult, CreateFormHookOptions } from "./createFormHookTypes.public.js";
2
+ import { Component } from "vue";
3
3
  //#region src/AppForm/createFormHook.public.d.ts
4
- declare function createFormHook<const TComponents extends AnyVueFormComponentMap>(createOptions: TComponents): AppFormHookResult<TComponents>;
4
+ declare function createFormHook<const TFormComponents extends Record<string, Component>, const TFieldComponents extends Record<string, Component>>(createOptions: CreateFormHookOptions<TFormComponents, TFieldComponents>): AppFormHookResult<{
5
+ formComponents: TFormComponents;
6
+ fieldComponents: TFieldComponents;
7
+ }>;
5
8
  //#endregion
6
9
  export { createFormHook };
@@ -2,11 +2,9 @@ import { useInternalForm } from "../VueForm/VueFormApi.lib.js";
2
2
  import { defineFieldGroup } from "../FieldGroup/withFields.public.js";
3
3
  import { useFormContext } from "./contexts.lib.js";
4
4
  import { createAppFormInitializer } from "./initializeAppForm.lib.js";
5
+ import { formOptions } from "@tanstack/form-core";
5
6
 
6
7
  //#region src/AppForm/createFormHook.public.ts
7
- const appFormOptions = ((opts) => opts);
8
- appFormOptions.strictSchema = (opts) => opts;
9
- appFormOptions.looseSchema = (opts) => opts;
10
8
  function createFormHook(createOptions) {
11
9
  const initializeAppForm = createAppFormInitializer(createOptions);
12
10
  function useExtendedForm(options) {
@@ -14,7 +12,7 @@ function createFormHook(createOptions) {
14
12
  }
15
13
  return {
16
14
  useFormContext,
17
- appFormOptions,
15
+ appFormOptions: formOptions,
18
16
  defineAppFieldGroup: defineFieldGroup,
19
17
  useAppForm: useExtendedForm
20
18
  };
@@ -1,15 +1,91 @@
1
- import { AnyVueFormComponentMap } from "./componentMap.public.js";
2
- import { AppFormOptionsApi } from "./appFormOptions.public.js";
1
+ import { AnyVueFormComponentMap, VueFormComponentMap } from "./componentMap.public.js";
3
2
  import { DefineFieldGroupFn } from "../FieldGroup/withFields.public.js";
4
3
  import { VueAppFormApi } from "./VueAppFormApi.public.js";
5
- import { FormOptions, FormValidators, ToFormErrorTypes } from "@tanstack/form-core";
4
+ import { DefaultFieldOptions, DefaultFormGroupOptions, DefaultFormOptions, FormOptions, FormOptionsApi, FormValidators, ToFormErrorTypes } from "@tanstack/form-core";
5
+ import { Component } from "vue";
6
6
  //#region src/AppForm/createFormHookTypes.public.d.ts
7
- type UseAppFormHook<TComponents extends AnyVueFormComponentMap> = <TFormData, const TFormValidators extends FormValidators<TFormData>, TSubmitReturn>(options: FormOptions<TFormData, TFormValidators, TSubmitReturn>) => VueAppFormApi<TFormData, ToFormErrorTypes<TFormValidators, TSubmitReturn>, TComponents>;
7
+ /**
8
+ * Configures the components and reusable defaults returned by
9
+ * `createFormHook`.
10
+ *
11
+ * Form core resolves each default object before the corresponding usage-site
12
+ * options. Non-listener properties passed at the usage site take precedence,
13
+ * including when explicitly set to `undefined`. Listener arrays follow the
14
+ * configured `listenersMerge` strategy.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const { useAppForm } = createFormHook({
19
+ * formComponents: {},
20
+ * fieldComponents: {
21
+ * TextField,
22
+ * },
23
+ * defaultFormOptions: {
24
+ * errorVisibility: ({ fieldState }) => fieldState.meta.isBlurred,
25
+ * },
26
+ * defaultFieldOptions: {
27
+ * errorBoundary: true,
28
+ * },
29
+ * })
30
+ * ```
31
+ *
32
+ * @typeParam TFormComponents - Library-managed. Do not specify explicitly.
33
+ * @typeParam TFieldComponents - Library-managed. Do not specify explicitly.
34
+ */
35
+ interface CreateFormHookOptions<TFormComponents extends Record<string, Component>, TFieldComponents extends Record<string, Component>> extends VueFormComponentMap<TFormComponents, TFieldComponents> {
36
+ /**
37
+ * Defaults for every form created by `useAppForm`.
38
+ *
39
+ * Non-listener options passed to `useAppForm` override these defaults,
40
+ * including when explicitly set to `undefined`. Listener arrays follow
41
+ * `listenersMerge`.
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * defaultFormOptions: {
46
+ * errorVisibility: ({ state }) => state.submissionAttempts > 0,
47
+ * },
48
+ * ```
49
+ */
50
+ defaultFormOptions?: DefaultFormOptions;
51
+ /**
52
+ * Defaults for every field and array-field component owned by the form.
53
+ *
54
+ * Non-listener options passed to the component override these defaults,
55
+ * including when explicitly set to `undefined`. Listener arrays follow
56
+ * `listenersMerge`. This includes `group.Field` and `group.ArrayField`.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * defaultFieldOptions: {
61
+ * errorVisibility: ({ fieldState }) => fieldState.meta.isBlurred,
62
+ * },
63
+ * ```
64
+ */
65
+ defaultFieldOptions?: DefaultFieldOptions;
66
+ /**
67
+ * Defaults for every `form.FormGroup` component.
68
+ *
69
+ * Options passed to the component override these defaults, including when
70
+ * an option is explicitly `undefined`.
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * defaultFormGroupOptions: {
75
+ * onSubmitInvalid: ({ groupApi }) => {
76
+ * console.error('Invalid group', groupApi.name)
77
+ * },
78
+ * },
79
+ * ```
80
+ */
81
+ defaultFormGroupOptions?: DefaultFormGroupOptions;
82
+ }
83
+ type UseAppFormHook<TComponents extends AnyVueFormComponentMap> = <TFormData, const TFormValidators extends FormValidators<TFormData>, TSubmitReturn>(options: FormOptions<TFormData, TFormValidators, TSubmitReturn, unknown>) => VueAppFormApi<TFormData, ToFormErrorTypes<TFormValidators, TSubmitReturn>, TComponents>;
8
84
  interface AppFormHookResult<TComponents extends AnyVueFormComponentMap> {
9
- appFormOptions: AppFormOptionsApi<TComponents>;
85
+ appFormOptions: FormOptionsApi<TComponents>;
10
86
  defineAppFieldGroup: DefineFieldGroupFn<TComponents['fieldComponents']>;
11
87
  useAppForm: UseAppFormHook<TComponents>;
12
88
  useFormContext: () => VueAppFormApi<any, any, TComponents>;
13
89
  }
14
90
  //#endregion
15
- export { AppFormHookResult, UseAppFormHook };
91
+ export { AppFormHookResult, CreateFormHookOptions, UseAppFormHook };
@@ -3,7 +3,12 @@ import { InternalFormApi } from "@tanstack/form-core/internals";
3
3
 
4
4
  //#region src/AppForm/initializeAppForm.lib.ts
5
5
  function createAppFormInitializer(createOptions) {
6
- return (options) => attachVueAppFormComponents(new InternalFormApi(options), createOptions.formComponents, createOptions.fieldComponents);
6
+ const defaultOptions = createOptions.defaultFormOptions || createOptions.defaultFieldOptions || createOptions.defaultFormGroupOptions ? {
7
+ form: createOptions.defaultFormOptions,
8
+ field: createOptions.defaultFieldOptions,
9
+ formGroup: createOptions.defaultFormGroupOptions
10
+ } : void 0;
11
+ return (options) => attachVueAppFormComponents(new InternalFormApi(options, defaultOptions), createOptions.formComponents, createOptions.fieldComponents);
7
12
  }
8
13
 
9
14
  //#endregion
@@ -15,7 +15,7 @@ type FieldGroupArrayFieldComponent<in out TFieldData, in out TFieldComponents ex
15
15
  };
16
16
  }>;
17
17
  type FieldGroupSubscribeProps<TSelected> = VueFormSubscribeProps<unknown, FormErrorTypes, TSelected>;
18
- type FieldGroupSubscribeComponent = new <TSelected>(props: FieldGroupSubscribeProps<TSelected> & PublicProps) => VueComponentInstance<FieldGroupSubscribeProps<TSelected>, {
18
+ type FieldGroupSubscribeComponent = new <const TSelected>(props: FieldGroupSubscribeProps<TSelected> & PublicProps) => VueComponentInstance<FieldGroupSubscribeProps<TSelected>, {
19
19
  default: NoInfer<TSelected>;
20
20
  }>;
21
21
  interface FieldGroupApi<in out TFieldData, in out TFieldComponents extends Record<string, Component> = Record<never, never>> extends FormApiFieldMethods<TFieldData>, FormApiArrayMethods<TFieldData> {
@@ -1,48 +1,26 @@
1
1
  import { VueComponentInstance } from "../vueTypes.lib.js";
2
2
  import { VueTanStackFormComponents } from "../VueForm/Components.public.js";
3
3
  import { FieldGroupApi } from "./FieldGroupApi.public.js";
4
- import { DeepKeys, DeepKeysWhereValueIncludes, DeepValue, FormApi } from "@tanstack/form-core";
4
+ import { FieldGroupFieldBindings, FieldGroupFieldBindingsProps, FieldGroupFieldData, FieldGroupFields, FieldGroupFieldsPropName, FieldGroupHelper, FormApi } from "@tanstack/form-core";
5
5
  import { Component, PublicProps } from "vue";
6
6
  //#region src/FieldGroup/withFields.public.d.ts
7
- declare const fieldGroupFieldSlotValueSymbol: unique symbol;
8
7
  declare const fieldGroupFieldsSymbol: unique symbol;
9
- type FieldGroupFieldSlotMode = 'strict' | 'loose';
10
- interface FieldGroupFieldSlot<out TValue, out TMode extends FieldGroupFieldSlotMode = FieldGroupFieldSlotMode> {
11
- readonly mode: TMode;
12
- readonly [fieldGroupFieldSlotValueSymbol]: TValue;
13
- }
14
- type AnyFieldGroupFieldSlot = FieldGroupFieldSlot<any>;
15
- type StrictFieldGroupFieldSlot<TValue> = FieldGroupFieldSlot<TValue, 'strict'>;
16
- type LooseFieldGroupFieldSlot<TValue> = FieldGroupFieldSlot<TValue, 'loose'>;
17
- type FieldGroupFieldSlotValue<TSlot> = TSlot extends FieldGroupFieldSlot<infer TValue> ? TValue : never;
18
- type FieldGroupFieldSlotModeOf<TSlot> = TSlot extends FieldGroupFieldSlot<any, infer TMode> ? TMode : never;
19
- type IsSame<TTypeA, TTypeB> = [TTypeA] extends [TTypeB] ? [TTypeB] extends [TTypeA] ? true : false : false;
20
- type FieldGroupFieldSlotAllows<TSlot, TValue> = TSlot extends FieldGroupFieldSlot<infer TAcceptedValue, infer TMode> ? TMode extends 'strict' ? IsSame<TValue, TAcceptedValue> : [TValue] extends [TAcceptedValue] ? true : false : false;
21
- type FieldGroupFieldNameForSlot<TFieldData, TSlot extends AnyFieldGroupFieldSlot> = { [TFieldName in DeepKeys<TFieldData>]: FieldGroupFieldSlotAllows<TSlot, DeepValue<TFieldData, TFieldName>> extends true ? TFieldName : never; }[DeepKeys<TFieldData>];
22
- type FieldGroupFields = Record<string, AnyFieldGroupFieldSlot>;
23
- type FieldGroupFieldNames<TFieldData, TFields extends FieldGroupFields> = { [TFieldName in keyof TFields]: FieldGroupFieldNameForSlot<TFieldData, TFields[TFieldName]>; };
24
- type FieldGroupFieldData<TFields extends FieldGroupFields> = { [TFieldName in keyof TFields]: TFields[TFieldName] extends FieldGroupFieldSlot<infer TValue, any> ? TValue : never; };
25
8
  type FieldGroupFieldsOf<TFieldGroup> = TFieldGroup extends {
26
- readonly [fieldGroupFieldsSymbol]: infer TFields;
9
+ readonly [fieldGroupFieldsSymbol]: infer TFields extends FieldGroupFields;
27
10
  } ? TFields : never;
28
11
  type VueFieldGroup<TFields extends FieldGroupFields, TFieldComponents extends Record<string, Component> = Record<never, never>> = FieldGroupApi<FieldGroupFieldData<TFields>, TFieldComponents> & {
29
12
  readonly [fieldGroupFieldsSymbol]: TFields;
30
13
  };
31
14
  type FieldGroupFieldComponentsOf<TFieldGroup> = TFieldGroup extends VueFieldGroup<any, infer TFieldComponents> ? TFieldComponents : never;
32
15
  type FieldGroupForm<TFieldComponents extends Record<string, Component> = Record<never, never>, TFormData = any> = FormApi<TFormData, any> & VueTanStackFormComponents<TFormData, any, TFieldComponents>;
33
- type FieldGroupFieldBindingForSlot<TFormData, TSlot extends AnyFieldGroupFieldSlot> = TSlot extends FieldGroupFieldSlot<infer TValue, infer TMode> ? TMode extends 'strict' ? FieldGroupFieldNameForSlot<TFormData, TSlot> : DeepKeysWhereValueIncludes<TFormData, TValue> : never;
34
- type FieldGroupFieldBindings<TFields extends FieldGroupFields, TFormData = any> = { [TFieldName in keyof TFields]: FieldGroupFieldBindingForSlot<TFormData, TFields[TFieldName]>; };
35
16
  type FieldGroupFieldBindingsOf<TFieldGroup, TFormData> = FieldGroupFieldsOf<TFieldGroup> extends FieldGroupFields ? FieldGroupFieldBindings<FieldGroupFieldsOf<TFieldGroup>, TFormData> : never;
36
- type FieldGroupFieldsPropName<TProps, TFieldGroup extends VueFieldGroup<any, any>> = { [TPropName in keyof TProps]-?: IsSame<TProps[TPropName], TFieldGroup> extends true ? TPropName : never; }[keyof TProps];
17
+ type FieldsPropsDefinition<TFieldGroup extends VueFieldGroup<any, any>, TFormData, TFieldsPropName extends PropertyKey> = { [TPropName in TFieldsPropName]: FieldGroupFieldBindingsOf<TFieldGroup, TFormData>; };
18
+ type FieldGroupFieldBindingsInstanceProp<TFieldGroup extends VueFieldGroup<any, any>, TFormData, TFieldsPropName extends PropertyKey> = FieldsPropsDefinition<TFieldGroup, TFormData, TFieldsPropName> | FieldGroupFieldBindingsProps<FieldGroupFieldsOf<TFieldGroup>, TFormData, TFieldsPropName>;
37
19
  type FieldGroupWithFieldsFn<TFieldGroup extends VueFieldGroup<any, any>> = <TProps extends object, const TFieldsPropName extends PropertyKey>(component: Component & (new (props: TProps & PublicProps) => any), fieldsPropName: TFieldsPropName & FieldGroupFieldsPropName<TProps, TFieldGroup>) => new <TFormData>(props: Omit<TProps, TFieldsPropName | 'form'> & {
38
20
  form: FieldGroupForm<FieldGroupFieldComponentsOf<TFieldGroup>, TFormData>;
39
- } & { [TPropName in TFieldsPropName]: FieldGroupFieldBindingsOf<TFieldGroup, TFormData>; } & PublicProps) => VueComponentInstance<Omit<TProps, TFieldsPropName | 'form'> & {
21
+ } & FieldGroupFieldBindingsProps<FieldGroupFieldsOf<TFieldGroup>, TFormData, TFieldsPropName> & PublicProps) => VueComponentInstance<Omit<TProps, TFieldsPropName | 'form'> & {
40
22
  form: FieldGroupForm<FieldGroupFieldComponentsOf<TFieldGroup>, TFormData>;
41
- } & { [TPropName in TFieldsPropName]: FieldGroupFieldBindingsOf<TFieldGroup, TFormData>; } & Record<string, any>, {}>;
42
- interface FieldGroupHelper {
43
- strict: <TValue>() => StrictFieldGroupFieldSlot<TValue>;
44
- loose: <TValue>() => LooseFieldGroupFieldSlot<TValue>;
45
- }
23
+ } & FieldGroupFieldBindingsInstanceProp<TFieldGroup, TFormData, TFieldsPropName> & Record<string, any>, {}>;
46
24
  interface FieldGroupDefinition<TFields extends FieldGroupFields, TFieldComponents extends Record<string, Component>> {
47
25
  /** The virtual field-group API injected into the bound component. */
48
26
  fields: VueFieldGroup<TFields, TFieldComponents>;
@@ -54,4 +32,4 @@ type DefineFieldGroupFn<TFieldComponents extends Record<string, Component>> = <c
54
32
  /** Defines a reusable group of virtual fields. */
55
33
  declare const defineFieldGroup: DefineFieldGroupFn<Record<never, never>>;
56
34
  //#endregion
57
- export { AnyFieldGroupFieldSlot, DefineFieldGroupFn, FieldGroupDefinition, FieldGroupFieldBindingForSlot, FieldGroupFieldBindings, FieldGroupFieldBindingsOf, FieldGroupFieldComponentsOf, FieldGroupFieldData, FieldGroupFieldNameForSlot, FieldGroupFieldNames, FieldGroupFieldSlot, FieldGroupFieldSlotAllows, FieldGroupFieldSlotMode, FieldGroupFieldSlotModeOf, FieldGroupFieldSlotValue, FieldGroupFields, FieldGroupFieldsOf, FieldGroupFieldsPropName, FieldGroupForm, FieldGroupHelper, FieldGroupWithFieldsFn, LooseFieldGroupFieldSlot, StrictFieldGroupFieldSlot, VueFieldGroup, defineFieldGroup };
35
+ export { DefineFieldGroupFn, FieldGroupDefinition, FieldGroupFieldBindingsOf, FieldGroupFieldComponentsOf, FieldGroupFieldsOf, FieldGroupForm, FieldGroupWithFieldsFn, VueFieldGroup, defineFieldGroup };
@@ -1,5 +1,6 @@
1
1
  import { Subscribe } from "../Subscribe.public.js";
2
2
  import { createArrayFieldSubscription, createValueFieldSubscription } from "./fieldSubscriptions.lib.js";
3
+ import { createFieldView } from "./fieldView.lib.js";
3
4
  import { useField } from "./useField.lib.js";
4
5
  import { shallow, useSelector } from "@tanstack/vue-store";
5
6
  import { InternalFormGroupApi } from "@tanstack/form-core/internals";
@@ -20,12 +21,14 @@ function createFieldComponent(form, fieldComponents, array, fieldContext) {
20
21
  ...context.attrs,
21
22
  form
22
23
  });
23
- const fieldApi = useField(options, fieldComponents);
24
- const selection = array ? createArrayFieldSubscription(fieldApi) : createValueFieldSubscription(fieldApi);
25
- if (fieldContext) provide(fieldContext, fieldApi.value);
24
+ const fieldApi = useField(options);
25
+ const { selection, meta } = array ? createArrayFieldSubscription(fieldApi) : createValueFieldSubscription(fieldApi);
26
+ const field = createFieldView(fieldApi, selection, meta);
27
+ if (fieldComponents !== null) Object.assign(field, fieldComponents);
28
+ if (fieldContext) provide(fieldContext, field);
26
29
  return () => {
27
30
  selection.value;
28
- return context.slots.default?.({ field: fieldApi.value });
31
+ return context.slots.default?.({ field });
29
32
  };
30
33
  }, {
31
34
  name: array ? "TanStackForm.ArrayField" : "TanStackForm.Field",
@@ -18,7 +18,7 @@ interface VueSubscribeProps<in out TSourceData, in out TSelected> {
18
18
  when?: (selected: NoInfer<TSelected>) => boolean;
19
19
  }
20
20
  type VueFormSubscribeProps<TFormData, TFormErrorTypes extends FormErrorTypes, TSelected> = VueSubscribeProps<FormState<TFormData, TFormErrorTypes>, TSelected>;
21
- type VueFormSubscribeComponent<in out TFormData, in out TFormErrorTypes extends FormErrorTypes> = new <TSelected>(props: VueFormSubscribeProps<TFormData, TFormErrorTypes, TSelected> & PublicProps) => VueComponentInstance<VueFormSubscribeProps<TFormData, TFormErrorTypes, TSelected>, {
21
+ type VueFormSubscribeComponent<in out TFormData, in out TFormErrorTypes extends FormErrorTypes> = new <const TSelected>(props: VueFormSubscribeProps<TFormData, TFormErrorTypes, TSelected> & PublicProps) => VueComponentInstance<VueFormSubscribeProps<TFormData, TFormErrorTypes, TSelected>, {
22
22
  default: NoInfer<TSelected>;
23
23
  }>;
24
24
  interface VueFormFieldProps<in out TFieldData, in out TFieldName, in out TFieldValue, in out TFieldValidators extends FieldValidators<TFieldData, TFieldName, TFieldValue>, in out TGroupFieldError, in out TFormData, in out TFormErrorTypes extends FormErrorTypes, in out TFieldComponents extends Record<string, Component>> extends FieldApiOptions<TFieldData, TFieldName, TFieldValue, TFieldValidators, TGroupFieldError, TFormData, TFormErrorTypes> {
@@ -35,7 +35,7 @@ type VueFormArrayFieldComponent<in out TFormData, in out TFormErrorTypes extends
35
35
  };
36
36
  }>;
37
37
  type VueFormGroupSubscribeProps<TGroupValue, TGroupErrorTypes extends FormErrorTypes, TSelected> = VueSubscribeProps<FormGroupState<TGroupValue, TGroupErrorTypes>, TSelected>;
38
- type VueFormGroupSubscribeComponent<in out TGroupValue, in out TGroupErrorTypes extends FormErrorTypes> = new <TSelected>(props: VueFormGroupSubscribeProps<TGroupValue, TGroupErrorTypes, TSelected> & PublicProps) => VueComponentInstance<VueFormGroupSubscribeProps<TGroupValue, TGroupErrorTypes, TSelected>, {
38
+ type VueFormGroupSubscribeComponent<in out TGroupValue, in out TGroupErrorTypes extends FormErrorTypes> = new <const TSelected>(props: VueFormGroupSubscribeProps<TGroupValue, TGroupErrorTypes, TSelected> & PublicProps) => VueComponentInstance<VueFormGroupSubscribeProps<TGroupValue, TGroupErrorTypes, TSelected>, {
39
39
  default: NoInfer<TSelected>;
40
40
  }>;
41
41
  type VueFormGroupFieldComponent<in out TFormData, in out TGroupValue, in out TGroupErrorTypes extends FormErrorTypes, in out TFormErrorTypes extends FormErrorTypes, in out TFieldComponents extends Record<string, Component>> = new <TFieldName extends DeepKeys<TGroupValue>, const TFieldValidators extends FieldValidators<TGroupValue, TFieldName, DeepValue<TGroupValue, TFieldName>>>(props: VueFormFieldProps<TGroupValue, TFieldName, DeepValue<TGroupValue, TFieldName>, TFieldValidators, TGroupErrorTypes['fieldError'], TFormData, TFormErrorTypes, TFieldComponents> & PublicProps) => VueComponentInstance<VueFormFieldProps<TGroupValue, TFieldName, DeepValue<TGroupValue, TFieldName>, TFieldValidators, TGroupErrorTypes['fieldError'], TFormData, TFormErrorTypes, TFieldComponents>, {
@@ -4,9 +4,12 @@ import { shallowRef, toRaw, watch } from "vue";
4
4
  //#region src/VueForm/fieldSubscriptions.lib.ts
5
5
  function createFieldSelection(fieldApi, selector) {
6
6
  const selected = shallowRef(selector(fieldApi.value));
7
+ const meta = shallowRef(fieldApi.value.meta);
7
8
  watch(fieldApi, (field, _previous, onCleanup) => {
9
+ meta.value = field.meta;
8
10
  selected.value = selector(field);
9
11
  const subscription = field.atom.subscribe(() => {
12
+ meta.value = field.meta;
10
13
  const next = selector(field);
11
14
  if (!shallow(toRaw(selected.value), next)) selected.value = next;
12
15
  });
@@ -15,7 +18,10 @@ function createFieldSelection(fieldApi, selector) {
15
18
  immediate: true,
16
19
  flush: "sync"
17
20
  });
18
- return selected;
21
+ return {
22
+ selection: selected,
23
+ meta
24
+ };
19
25
  }
20
26
  function createValueFieldSubscription(fieldApi) {
21
27
  return createFieldSelection(fieldApi, (field) => ({
@@ -0,0 +1,43 @@
1
+ //#region src/VueForm/fieldView.lib.ts
2
+ /**
3
+ * The public field shared by slots and injected components. State getters
4
+ * track the existing subscription in the component that reads them, while
5
+ * handlers follow the current core field after a reset or name change.
6
+ */
7
+ function createFieldView(fieldApi, selection, meta) {
8
+ return {
9
+ get form() {
10
+ return fieldApi.value.form;
11
+ },
12
+ get name() {
13
+ return fieldApi.value.name;
14
+ },
15
+ get atom() {
16
+ return fieldApi.value.atom;
17
+ },
18
+ get value() {
19
+ selection.value;
20
+ return fieldApi.value.value;
21
+ },
22
+ get meta() {
23
+ return meta.value;
24
+ },
25
+ get errors() {
26
+ return meta.value.errors;
27
+ },
28
+ handleChange: (value, options) => fieldApi.value.handleChange(value, options),
29
+ handleBlur: () => fieldApi.value.handleBlur(),
30
+ reset: () => fieldApi.value.reset(),
31
+ swapValues: (indexA, indexB) => fieldApi.value.swapValues(indexA, indexB),
32
+ moveValue: (fromIndex, toIndex, options) => fieldApi.value.moveValue(fromIndex, toIndex, options),
33
+ pushValue: (value, options) => fieldApi.value.pushValue(value, options),
34
+ insertValue: (index, value, options) => fieldApi.value.insertValue(index, value, options),
35
+ clearValues: (options) => fieldApi.value.clearValues(options),
36
+ replaceValue: (index, value, options) => fieldApi.value.replaceValue(index, value, options),
37
+ removeValue: (index, options) => fieldApi.value.removeValue(index, options),
38
+ filterValues: (predicate, options) => fieldApi.value.filterValues(predicate, options)
39
+ };
40
+ }
41
+
42
+ //#endregion
43
+ export { createFieldView };
@@ -1,6 +1,5 @@
1
1
  import { AnyVueFormComponentMap, DefaultVueFormComponentMap } from "../AppForm/componentMap.public.js";
2
2
  import { VueFormApi } from "./formApiTypes.public.js";
3
- import { AppFormOptions } from "../AppForm/appFormOptions.public.js";
4
3
  import { AnyFormOptions, FormOptions, FormValidators, ToFormErrorTypes } from "@tanstack/form-core";
5
4
  //#region src/VueForm/formType.public.d.ts
6
5
  type VueFormTypeErrorTypes<TFormValidators extends FormValidators<any>, TSubmitReturn> = unknown extends TSubmitReturn ? any : ToFormErrorTypes<TFormValidators, TSubmitReturn>;
@@ -27,6 +26,6 @@ type VueFormTypeErrorTypes<TFormValidators extends FormValidators<any>, TSubmitR
27
26
  *
28
27
  * @typeParam TOptions - The reusable form or app-form options from which the API derives its form data, error, and registered-component types.
29
28
  */
30
- type VueFormType<TOptions extends AnyFormOptions | AppFormOptions<any, any, any, AnyVueFormComponentMap>> = TOptions extends AppFormOptions<infer TFormData, infer TFormValidators, infer TSubmitReturn, infer TComponents> ? VueFormApi<TFormData, VueFormTypeErrorTypes<TFormValidators, TSubmitReturn>, TComponents> : TOptions extends FormOptions<infer TFormData, infer TFormValidators, infer TSubmitReturn> ? VueFormApi<TFormData, VueFormTypeErrorTypes<TFormValidators, TSubmitReturn>, DefaultVueFormComponentMap> : never;
29
+ type VueFormType<TOptions extends AnyFormOptions> = TOptions extends FormOptions<infer TFormData, infer TFormValidators, infer TSubmitReturn, infer TComponents> ? VueFormApi<TFormData, VueFormTypeErrorTypes<TFormValidators, TSubmitReturn>, TComponents extends AnyVueFormComponentMap ? TComponents : DefaultVueFormComponentMap> : never;
31
30
  //#endregion
32
31
  export { VueFormType };
@@ -2,17 +2,15 @@ import { useSelector } from "@tanstack/vue-store";
2
2
  import { onMounted, onUnmounted, shallowRef, watch, watchEffect } from "vue";
3
3
 
4
4
  //#region src/VueForm/useField.lib.ts
5
- function useField(options, fieldComponents) {
5
+ function useField(options) {
6
6
  const initialOptions = options();
7
7
  const resetVersion = useSelector(initialOptions.form._atoms.resetVersion);
8
8
  const createField = () => {
9
9
  const current = options();
10
- const field = current.form._getOrCreateFieldApi({
10
+ return current.form._getOrCreateFieldApi({
11
11
  ...current,
12
12
  name: current.name
13
- });
14
- if (fieldComponents !== null) Object.assign(field, fieldComponents);
15
- return field;
13
+ }, "field");
16
14
  };
17
15
  const fieldApi = shallowRef(createField());
18
16
  watch([
@@ -23,7 +21,7 @@ function useField(options, fieldComponents) {
23
21
  fieldApi.value = createField();
24
22
  }, { flush: "sync" });
25
23
  watchEffect(() => {
26
- fieldApi.value._update(options());
24
+ fieldApi.value._update(options(), "field");
27
25
  });
28
26
  let mounted = false;
29
27
  let unregister;
@@ -2,7 +2,29 @@ import { AnyVueFormComponentMap, DefaultVueFormComponentMap } from "../AppForm/c
2
2
  import { VueFormApi } from "./formApiTypes.public.js";
3
3
  import { FormOptions, FormValidators, ToFormErrorTypes } from "@tanstack/form-core";
4
4
  //#region src/VueForm/useForm.public.d.ts
5
- type UseFormHook<in out TComponents extends AnyVueFormComponentMap> = <TFormData, const TFormValidators extends FormValidators<TFormData>, TSubmitReturn>(options: FormOptions<TFormData, TFormValidators, TSubmitReturn>) => VueFormApi<TFormData, ToFormErrorTypes<TFormValidators, TSubmitReturn>, TComponents>;
5
+ type UseFormHook<in out TComponents extends AnyVueFormComponentMap> = <TFormData, const TFormValidators extends FormValidators<TFormData>, TSubmitReturn>(options: FormOptions<TFormData, TFormValidators, TSubmitReturn, unknown>) => VueFormApi<TFormData, ToFormErrorTypes<TFormValidators, TSubmitReturn>, TComponents>;
6
+ /**
7
+ * Creates a Vue form whose instance and lifecycle are owned by the current
8
+ * component.
9
+ *
10
+ * `defaultValues` establish the initial state and inferred form value type. To
11
+ * update the existing form after creation, pass a reactive options object;
12
+ * tracked changes are applied without replacing the form instance.
13
+ *
14
+ * Call this during the component's setup phase. The form mounts with the
15
+ * component and is cleaned up when the component unmounts.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * const form = useForm({
20
+ * defaultValues: { name: '' },
21
+ * onSubmit: ({ value }) => saveProfile(value),
22
+ * })
23
+ * ```
24
+ *
25
+ * @returns The Vue form API with typed field, subscription, and form-group
26
+ * components attached.
27
+ */
6
28
  declare const useForm: UseFormHook<DefaultVueFormComponentMap>;
7
29
  //#endregion
8
30
  export { UseFormHook, useForm };
@@ -4,6 +4,28 @@ import { initializeForm, useInternalForm } from "./VueFormApi.lib.js";
4
4
  function useFormHook(options) {
5
5
  return useInternalForm(options, initializeForm);
6
6
  }
7
+ /**
8
+ * Creates a Vue form whose instance and lifecycle are owned by the current
9
+ * component.
10
+ *
11
+ * `defaultValues` establish the initial state and inferred form value type. To
12
+ * update the existing form after creation, pass a reactive options object;
13
+ * tracked changes are applied without replacing the form instance.
14
+ *
15
+ * Call this during the component's setup phase. The form mounts with the
16
+ * component and is cleaned up when the component unmounts.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const form = useForm({
21
+ * defaultValues: { name: '' },
22
+ * onSubmit: ({ value }) => saveProfile(value),
23
+ * })
24
+ * ```
25
+ *
26
+ * @returns The Vue form API with typed field, subscription, and form-group
27
+ * components attached.
28
+ */
7
29
  const useForm = useFormHook;
8
30
 
9
31
  //#endregion
package/dist/index.d.ts CHANGED
@@ -2,15 +2,14 @@ import { AnyVueFormComponentMap, DefaultVueFormComponentMap, VueFormComponentMap
2
2
  import { VueFieldApi, VueFormArrayFieldComponent, VueFormFieldComponent, VueFormFieldProps, VueFormGroupApi, VueFormGroupArrayFieldComponent, VueFormGroupComponent, VueFormGroupFieldComponent, VueFormGroupProps, VueFormGroupSubscribeComponent, VueFormGroupSubscribeProps, VueFormSubscribeComponent, VueFormSubscribeProps, VueTanStackFormComponents } from "./VueForm/Components.public.js";
3
3
  import { AnyVueFormApi, VueFormApi } from "./VueForm/formApiTypes.public.js";
4
4
  import { UseFormHook, useForm } from "./VueForm/useForm.public.js";
5
- import { AppFormOptions, AppFormOptionsApi } from "./AppForm/appFormOptions.public.js";
6
5
  import { VueFormType } from "./VueForm/formType.public.js";
7
6
  import { Subscribe, SubscribeComponent, SubscribeProps, SubscribeSource } from "./Subscribe.public.js";
8
7
  import { AnyFieldGroupApi, FieldGroupApi, FieldGroupArrayFieldComponent, FieldGroupFieldComponent, FieldGroupFormState, FieldGroupSubscribeComponent, FieldGroupSubscribeProps } from "./FieldGroup/FieldGroupApi.public.js";
9
- import { AnyFieldGroupFieldSlot, DefineFieldGroupFn, FieldGroupDefinition, FieldGroupFieldBindingForSlot, FieldGroupFieldBindings, FieldGroupFieldBindingsOf, FieldGroupFieldComponentsOf, FieldGroupFieldData, FieldGroupFieldNameForSlot, FieldGroupFieldNames, FieldGroupFieldSlot, FieldGroupFieldSlotAllows, FieldGroupFieldSlotMode, FieldGroupFieldSlotModeOf, FieldGroupFieldSlotValue, FieldGroupFields, FieldGroupFieldsOf, FieldGroupFieldsPropName, FieldGroupForm, FieldGroupHelper, FieldGroupWithFieldsFn, LooseFieldGroupFieldSlot, StrictFieldGroupFieldSlot, VueFieldGroup, defineFieldGroup } from "./FieldGroup/withFields.public.js";
8
+ import { DefineFieldGroupFn, FieldGroupDefinition, FieldGroupFieldBindingsOf, FieldGroupFieldComponentsOf, FieldGroupFieldsOf, FieldGroupForm, FieldGroupWithFieldsFn, VueFieldGroup, defineFieldGroup } from "./FieldGroup/withFields.public.js";
10
9
  import { AppFormComponent, VueAppFormApi } from "./AppForm/VueAppFormApi.public.js";
11
- import { AppFormHookResult, UseAppFormHook } from "./AppForm/createFormHookTypes.public.js";
10
+ import { AppFormHookResult, CreateFormHookOptions, UseAppFormHook } from "./AppForm/createFormHookTypes.public.js";
12
11
  import { createFormHook } from "./AppForm/createFormHook.public.js";
13
12
  import { FormHookHelpers, getFormHookHelpers } from "./AppForm/getFormHookHelpers.public.js";
14
13
  export * from "@tanstack/form-core";
15
14
  export * from "@tanstack/vue-store";
16
- export { AnyFieldGroupApi, AnyFieldGroupFieldSlot, AnyVueFormApi, AnyVueFormComponentMap, AppFormComponent, AppFormHookResult, AppFormOptions, AppFormOptionsApi, DefaultVueFormComponentMap, DefineFieldGroupFn, FieldGroupApi, FieldGroupArrayFieldComponent, FieldGroupDefinition, FieldGroupFieldBindingForSlot, FieldGroupFieldBindings, FieldGroupFieldBindingsOf, FieldGroupFieldComponent, FieldGroupFieldComponentsOf, FieldGroupFieldData, FieldGroupFieldNameForSlot, FieldGroupFieldNames, FieldGroupFieldSlot, FieldGroupFieldSlotAllows, FieldGroupFieldSlotMode, FieldGroupFieldSlotModeOf, FieldGroupFieldSlotValue, FieldGroupFields, FieldGroupFieldsOf, FieldGroupFieldsPropName, FieldGroupForm, FieldGroupFormState, FieldGroupHelper, FieldGroupSubscribeComponent, FieldGroupSubscribeProps, FieldGroupWithFieldsFn, FormHookHelpers, LooseFieldGroupFieldSlot, StrictFieldGroupFieldSlot, Subscribe, SubscribeComponent, SubscribeProps, SubscribeSource, UseAppFormHook, UseFormHook, VueAppFormApi, VueFieldApi, VueFieldGroup, VueFormApi, VueFormArrayFieldComponent, VueFormComponentMap, VueFormFieldComponent, VueFormFieldProps, VueFormGroupApi, VueFormGroupArrayFieldComponent, VueFormGroupComponent, VueFormGroupFieldComponent, VueFormGroupProps, VueFormGroupSubscribeComponent, VueFormGroupSubscribeProps, VueFormSubscribeComponent, VueFormSubscribeProps, VueFormType, VueTanStackFormComponents, createFormHook, defineFieldGroup, getFormHookHelpers, useForm };
15
+ export { AnyFieldGroupApi, AnyVueFormApi, AnyVueFormComponentMap, AppFormComponent, AppFormHookResult, CreateFormHookOptions, DefaultVueFormComponentMap, DefineFieldGroupFn, FieldGroupApi, FieldGroupArrayFieldComponent, FieldGroupDefinition, FieldGroupFieldBindingsOf, FieldGroupFieldComponent, FieldGroupFieldComponentsOf, FieldGroupFieldsOf, FieldGroupForm, FieldGroupFormState, FieldGroupSubscribeComponent, FieldGroupSubscribeProps, FieldGroupWithFieldsFn, FormHookHelpers, Subscribe, SubscribeComponent, SubscribeProps, SubscribeSource, UseAppFormHook, UseFormHook, VueAppFormApi, VueFieldApi, VueFieldGroup, VueFormApi, VueFormArrayFieldComponent, VueFormComponentMap, VueFormFieldComponent, VueFormFieldProps, VueFormGroupApi, VueFormGroupArrayFieldComponent, VueFormGroupComponent, VueFormGroupFieldComponent, VueFormGroupProps, VueFormGroupSubscribeComponent, VueFormGroupSubscribeProps, VueFormSubscribeComponent, VueFormSubscribeProps, VueFormType, VueTanStackFormComponents, createFormHook, defineFieldGroup, getFormHookHelpers, useForm };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/vue-form",
3
- "version": "2.0.0-alpha.1",
3
+ "version": "2.0.0-alpha.3",
4
4
  "description": "Powerful, type-safe forms for Vue.",
5
5
  "author": "tannerlinsley",
6
6
  "license": "MIT",
@@ -25,15 +25,15 @@
25
25
  "dist"
26
26
  ],
27
27
  "dependencies": {
28
- "@tanstack/vue-store": "^0.11.1",
29
- "@tanstack/form-core": "2.0.0-alpha.1"
28
+ "@tanstack/form-core": "2.0.0-alpha.3",
29
+ "@tanstack/vue-store": "^0.11.1"
30
30
  },
31
31
  "devDependencies": {
32
- "@testing-library/vue": "^8.1.0",
33
- "@vitejs/plugin-vue": "^6.0.8",
32
+ "@vitejs/plugin-vue": "^6.0.9",
34
33
  "unplugin-vue": "^7.2.0",
35
- "vue": "^3.6.0-rc.2",
36
- "vue-tsc": "^3.3.9"
34
+ "vitest-browser-vue": "^3.1.0",
35
+ "vue": "^3.6.0-rc.9",
36
+ "vue-tsc": "^3.3.11"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "vue": "^3.6.0-rc.2"
@@ -1,14 +0,0 @@
1
- import { AnyVueFormComponentMap } from "./componentMap.public.js";
2
- import { FormOptions, FormValidatorData, FormValidators, InferUnion, NullableSchemaData } from "@tanstack/form-core";
3
- //#region src/AppForm/appFormOptions.public.d.ts
4
- declare const componentsSymbol: unique symbol;
5
- interface AppFormOptions<TFormData, TFormValidators extends FormValidators<TFormData>, TSubmitReturn, TComponents extends AnyVueFormComponentMap> extends FormOptions<TFormData, TFormValidators, TSubmitReturn> {
6
- [componentsSymbol]: TComponents;
7
- }
8
- interface AppFormOptionsApi<TComponents extends AnyVueFormComponentMap> {
9
- <TFormData, const TFormValidators extends FormValidators<TFormData>, TSubmitReturn>(options: FormOptions<TFormData, TFormValidators, TSubmitReturn>): AppFormOptions<TFormData, TFormValidators, TSubmitReturn, TComponents>;
10
- strictSchema: <const TFormValidators extends FormValidators<any>, TFormData extends FormValidatorData<TFormValidators>, TSubmitReturn>(options: FormOptions<TFormData, TFormValidators, TSubmitReturn>) => AppFormOptions<FormValidatorData<TFormValidators>, TFormValidators, TSubmitReturn, TComponents>;
11
- looseSchema: <const TFormValidators extends FormValidators<any>, const TFormData extends NullableSchemaData<TFormValidators>, TSubmitReturn>(options: FormOptions<TFormData, TFormValidators, TSubmitReturn>) => AppFormOptions<InferUnion<TFormData, FormValidatorData<TFormValidators>>, TFormValidators, TSubmitReturn, TComponents>;
12
- }
13
- //#endregion
14
- export { AppFormOptions, AppFormOptionsApi };