Skip to content

Commit

Permalink
fix: complete form factory functionality, docs
Browse files Browse the repository at this point in the history
  • Loading branch information
tannerlinsley committed May 1, 2023
1 parent b274bcc commit c444704
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 51 deletions.
36 changes: 36 additions & 0 deletions docs/framework/react/reference/createFormFactory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
id: createFormFactory
title: createFormFactory
---

### `createFormFactory`

```tsx
export function createFormFactory<TFormData>(
opts?: FormOptions<TFormData>,
): FormFactory<TFormData>
```

A function that creates a new `FormFactory<TFormData>` instance.

- `opts`
- Optional form options and a `listen` function to be called with the form state.

### `FormFactory<TFormData>`

A type representing a form factory. Form factories provide a type-safe way to interact with the form API as opposed to using the globally exported form utilities.

```tsx
export type FormFactory<TFormData> = {
useForm: (opts?: FormOptions<TFormData>) => FormApi<TFormData>
useField: UseField<TFormData>
Field: FieldComponent<TFormData>
}
```

- `useForm`
- A custom hook that creates and returns a new instance of the `FormApi<TFormData>` class.
- `useField`
- A custom hook that returns an instance of the `FieldApi<TFormData>` class.
- `Field`
- A form field component.
4 changes: 0 additions & 4 deletions docs/reference/formApi.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ An object representing the options for a form.
validate?: (values: TData, formApi: FormApi<TData>) => Promise<any>
```
- A function for custom validation logic for the form.
- ```tsx
debugForm?: boolean
```
- A boolean flag to enable or disable form debugging.
- ```tsx
defaultValidatePristine?: boolean
```
Expand Down
26 changes: 25 additions & 1 deletion examples/react/simple/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,22 @@ import React from "react";
import ReactDOM from "react-dom/client";
import { FieldApi, createFormFactory } from "@tanstack/react-form";

const formFactory = createFormFactory({
type Person = {
firstName: string;
lastName: string;
hobbies: Hobby[];
};

type Hobby = {
name: string;
description: string;
};

const formFactory = createFormFactory<Person>({
defaultValues: {
firstName: "",
lastName: "",
hobbies: [],
},
});

Expand Down Expand Up @@ -68,6 +80,18 @@ export default function App() {
)}
/>
</div>
<div>
<form.Field
name="hobbies"
children={(field) => (
<>
<label htmlFor={field.name}>Last Name:</label>
<input name={field.name} {...field.getInputProps()} />
<FieldInfo field={field} />
</>
)}
/>
</div>
<form.Subscribe
selector={(state) => [state.canSubmit, state.isSubmitting]}
children={([canSubmit, isSubmitting]) => (
Expand Down
6 changes: 2 additions & 4 deletions packages/form-core/src/FormApi.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { FormEvent } from 'react'
import { Store } from '@tanstack/store'
//
import type { DeepKeys, DeepValue, Updater } from './utils'
Expand All @@ -11,7 +10,6 @@ export type FormOptions<TData> = {
onSubmit?: (values: TData, formApi: FormApi<TData>) => void
onInvalidSubmit?: (values: TData, formApi: FormApi<TData>) => void
validate?: (values: TData, formApi: FormApi<TData>) => Promise<any>
debugForm?: boolean
defaultValidatePristine?: boolean
defaultValidateOn?: ValidationCause
defaultValidateAsyncOn?: ValidationCause
Expand Down Expand Up @@ -53,7 +51,7 @@ export type FormState<TData> = {
submissionAttempts: number
}

export function getDefaultFormState<TData>(
function getDefaultFormState<TData>(
defaultState: Partial<FormState<TData>>,
): FormState<TData> {
return {
Expand Down Expand Up @@ -247,7 +245,7 @@ export class FormApi<TFormData> {
return this.validationMeta.validationPromise
}

handleSubmit = async (e: FormEvent & { __handled?: boolean }) => {
handleSubmit = async (e: Event) => {
e.preventDefault()
e.stopPropagation()

Expand Down
5 changes: 4 additions & 1 deletion packages/react-form/src/createFormFactory.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import type { FormApi, FormOptions } from '@tanstack/form-core'
import { createUseField, type UseField } from './useField'
import { useForm } from './useForm'
import { createFieldComponent, type FieldComponent } from './Field'

export type FormFactory<TFormData> = {
useForm: (opts?: FormOptions<TFormData>) => FormApi<TFormData>
useField: UseField<TFormData>
Field: FieldComponent<TFormData>
}

export function createFormFactory<TFormData>(
Expand All @@ -14,6 +16,7 @@ export function createFormFactory<TFormData>(
useForm: (opts) => {
return useForm<TFormData>({ ...defaultOpts, ...opts } as any) as any
},
useField: createUseField(),
useField: createUseField<TFormData>(),
Field: createFieldComponent<TFormData>(),
}
}
40 changes: 35 additions & 5 deletions packages/react-form/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
export * from '@tanstack/form-core'
export * from './useForm'
export * from './Field'
export * from './useField'
export * from './createFormFactory'
export type {
ChangeProps,
DeepKeys,
DeepValue,
FieldApiOptions,
FieldInfo,
FieldMeta,
FieldOptions,
FieldState,
FormOptions,
FormState,
InputProps,
RequiredByKey,
Updater,
UpdaterFn,
UserChangeProps,
UserInputProps,
ValidationCause,
ValidationError,
ValidationMeta,
} from '@tanstack/form-core'

export { FormApi, FieldApi, functionalUpdate } from '@tanstack/form-core'

export type { FormComponent, FormProps } from './useForm'
export { useForm } from './useForm'

export type { FieldComponent } from './Field'
export { Field } from './Field'

export type { UseField } from './useField'
export { useField } from './useField'

export type { FormFactory } from './createFormFactory'
export { createFormFactory } from './createFormFactory'
37 changes: 1 addition & 36 deletions packages/react-form/src/useForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ export function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {
return api
})

// React.useEffect(() => formApi.mount(), [])

return formApi as any
}

Expand All @@ -66,7 +64,7 @@ export type FormProps = React.HTMLProps<HTMLFormElement> & {

export type FormComponent = (props: FormProps) => any

export function createFormComponent(formApi: FormApi<any>) {
function createFormComponent(formApi: FormApi<any>) {
const Form: FormComponent = ({ children, noFormElement, ...rest }) => {
const isSubmitting = formApi.useStore((state) => state.isSubmitting)

Expand All @@ -80,26 +78,6 @@ export function createFormComponent(formApi: FormApi<any>) {
disabled={isSubmitting}
{...rest}
>
{formApi.options.debugForm ? (
<div
style={{
margin: '2rem 0',
}}
>
<div
style={{
fontWeight: 'bolder',
}}
>
Form State
</div>
<pre>
<code>
{JSON.stringify(formApi, safeStringifyReplace(), 2)}
</code>
</pre>
</div>
) : null}
{children}
</form>
)}
Expand All @@ -109,16 +87,3 @@ export function createFormComponent(formApi: FormApi<any>) {

return Form
}

function safeStringifyReplace() {
const set = new Set()
return (_key: string, value: any) => {
if (typeof value === 'object' || Array.isArray(value)) {
if (set.has(value)) {
return '(circular value)'
}
set.add(value)
}
return typeof value === 'function' ? undefined : value
}
}

0 comments on commit c444704

Please sign in to comment.