Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make runtime agnostic/Support React Native #439

Merged
merged 3 commits into from
Sep 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion docs/framework/react/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ export default function App() {
<form.Field
name="fullName"
children={(field) => (
<input name={field.name} {...field.getInputProps()} />
<input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
)}
/>
</div>
Expand Down
4 changes: 0 additions & 4 deletions docs/framework/react/reference/formApi.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ title: Form API

When using `@tanstack/react-form`, the [core form API](../../reference/formApi) is extended with additional methods for React-specific functionality:

- ```tsx
getFormProps: () => FormProps
```
- A function that returns props for the form element.
- ```tsx
Field: FieldComponent<TFormData>
```
Expand Down
41 changes: 34 additions & 7 deletions docs/guides/basic-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ Example:
name="firstName"
children={(field) => (
<>
<input {...field.getInputProps()} />
<input
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
)}
Expand All @@ -68,12 +72,16 @@ const { value, error, touched, isValidating } = field.state

## Field API

The Field API is an object passed to the render prop function when creating a field. It provides methods for working with the field's state, such as getInputProps, which returns an object with props needed to bind the field to a form input element.
The Field API is an object passed to the render prop function when creating a field. It provides methods for working with the field's state.

Example:

```tsx
<input {...field.getInputProps()} />
<input
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
```

## Validation
Expand All @@ -92,7 +100,11 @@ Example:
}}
children={(field) => (
<>
<input {...field.getInputProps()} />
<input
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
)}
Expand Down Expand Up @@ -143,7 +155,12 @@ Example:
return (
<div>
<label htmlFor={field.name}>Name:</label>
<input name={field.name} {...field.getInputProps()} />
<input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<button
type="button"
onClick={() => hobbiesField.removeValue(i)}
Expand All @@ -162,7 +179,12 @@ Example:
return (
<div>
<label htmlFor={field.name}>Description:</label>
<input name={field.name} {...field.getInputProps()} />
<input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</div>
)
Expand Down Expand Up @@ -202,7 +224,12 @@ Example:
return (
<div>
<label htmlFor={field.name}>Name:</label>
<input name={field.name} {...field.getInputProps()} />
<input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<button type="button" onClick={() => hobbiesField.removeValue(i)}>
X
</button>
Expand Down
64 changes: 40 additions & 24 deletions docs/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,71 +26,82 @@ In the example below, you can see TanStack Form in action with the React framewo
[Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-form/tree/main/examples/react/simple)

```tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { useForm } from "@tanstack/react-form";
import type { FieldApi } from "@tanstack/react-form";
import React from 'react'
import ReactDOM from 'react-dom/client'
import { useForm } from '@tanstack/react-form'
import type { FieldApi } from '@tanstack/react-form'

function FieldInfo({ field }: { field: FieldApi<any, any> }) {
return (
<>
{field.state.meta.touchedError ? (
<em>{field.state.meta.touchedError}</em>
) : null}{" "}
{field.state.meta.isValidating ? "Validating..." : null}
) : null}
{field.state.meta.isValidating ? 'Validating...' : null}
</>
);
)
}

export default function App() {
const form = useForm({
// Memoize your default values to prevent re-renders
defaultValues: React.useMemo(
() => ({
firstName: "",
lastName: "",
firstName: '',
lastName: '',
}),
[],
),
onSubmit: async (values) => {
// Do something with form data
console.log(values);
console.log(values)
},
});
})

return (
<div>
<h1>Simple Form Example</h1>
{/* A pre-bound form component */}
<form.Provider>
<form {...form.getFormProps()}>
<form
onSubmit={(e) => {
e.preventDefault()
e.stopPropagation()
void form.handleSubmit()
}}
>
<div>
{/* A type-safe and pre-bound field component*/}
<form.Field
name="firstName"
onChange={(value) =>
!value
? "A first name is required"
? 'A first name is required'
: value.length < 3
? "First name must be at least 3 characters"
? 'First name must be at least 3 characters'
: undefined
}
onChangeAsyncDebounceMs={500}
onChangeAsync={async (value) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
await new Promise((resolve) => setTimeout(resolve, 1000))
return (
value.includes("error") && 'No "error" allowed in first name'
);
value.includes('error') && 'No "error" allowed in first name'
)
}}
children={(field) => {
// Avoid hasty abstractions. Render props are great!
return (
<>
<label htmlFor={field.name}>First Name:</label>
<input name={field.name} {...field.getInputProps()} />
<input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
);
)
}}
/>
</div>
Expand All @@ -100,7 +111,12 @@ export default function App() {
children={(field) => (
<>
<label htmlFor={field.name}>Last Name:</label>
<input name={field.name} {...field.getInputProps()} />
<input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
)}
Expand All @@ -110,19 +126,19 @@ export default function App() {
selector={(state) => [state.canSubmit, state.isSubmitting]}
children={([canSubmit, isSubmitting]) => (
<button type="submit" disabled={!canSubmit}>
{isSubmitting ? "..." : "Submit"}
{isSubmitting ? '...' : 'Submit'}
</button>
)}
/>
</form>
</form.Provider>
</div>
);
)
}

const rootElement = document.getElementById("root")!;
const rootElement = document.getElementById('root')!

ReactDOM.createRoot(rootElement).render(<App />);
ReactDOM.createRoot(rootElement).render(<App />)
```

## You talked me into it, so what now?
Expand Down
31 changes: 16 additions & 15 deletions docs/reference/fieldApi.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ title: Field API

### Creating a new FieldApi Instance



Normally, you will not need to create a new `FieldApi` instance directly. Instead, you will use a framework hook/function like `useField` or `createField` to create a new instance for you that utilizes your frameworks reactivity model. However, if you need to create a new instance manually, you can do so by calling the `new FieldApi` constructor.

```tsx
Expand All @@ -28,55 +26,58 @@ An object type representing the options for a field in a form.
- ```tsx
defaultMeta?: Partial<FieldMeta>
```

- An optional object with default metadata for the field.

- ```tsx
onMount?: (formApi: FieldApi<TData, TFormData>) => void
```

- An optional function that takes a param of `formApi` which is a generic type of `TData` and `TFormData`

- ```tsx
onChange?: ValidateFn<TData, TFormData>
```

- An optional property that takes a `ValidateFn` which is a generic of `TData` and `TFormData`

- ```tsx
onChangeAsync?: ValidateAsyncFn<TData, TFormData>
```
- An optional property similar to `onChange` but async validation

- An optional property similar to `onChange` but async validation

- ```tsx
onChangeAsyncDebounceMs?: number
```
- An optional number to represent how long the `onChangeAsync` should wait before running

- An optional number to represent how long the `onChangeAsync` should wait before running
- If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds

- ```tsx
onBlur?: ValidateFn<TData, TFormData>
```

- An optional function, when that run when subscribing to blur event of input

- ```tsx
onBlurAsync?: ValidateAsyncFn<TData, TFormData>
```

- An optional function that takes a `ValidateFn` which is a generic of `TData` and `TFormData` happens async

```tsx
onBlurAsyncDebounceMs?: number
```
- An optional number to represent how long the `onBlurAsyncDebounceMs` should wait before running
- If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds

- An optional number to represent how long the `onBlurAsyncDebounceMs` should wait before running
- If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds

```tsx
onSubmitAsync?: number
```
- If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds





- If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds

### `ValidationCause`

Expand Down Expand Up @@ -205,13 +206,13 @@ A class representing the API for managing a form field.
```
- Validates the field value.
- ```tsx
getChangeProps<T extends UserChangeProps<any>>(props: T = {} as T): ChangeProps<TData> & Omit<T, keyof ChangeProps<TData>>
handleBlur(): void;
```
- Gets the change and blur event handlers.
- Handles the blur event.
- ```tsx
getInputProps<T extends UserInputProps>(props: T = {} as T): InputProps & Omit<T, keyof InputProps>
handleChange(value: TData): void
```
- Gets the input event handlers.
- Handles the change event.

### `FieldState<TData>`

Expand Down
24 changes: 20 additions & 4 deletions examples/react/simple/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function FieldInfo({ field }: { field: FieldApi<any, any> }) {
<>
{field.state.meta.touchedError ? (
<em>{field.state.meta.touchedError}</em>
) : null}{" "}
) : null}
{field.state.meta.isValidating ? "Validating..." : null}
</>
);
Expand All @@ -35,7 +35,13 @@ export default function App() {
<h1>Simple Form Example</h1>
{/* A pre-bound form component */}
<form.Provider>
<form {...form.getFormProps()}>
<form
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
void form.handleSubmit();
}}
>
<div>
{/* A type-safe and pre-bound field component*/}
<form.Field
Expand All @@ -59,7 +65,12 @@ export default function App() {
return (
<>
<label htmlFor={field.name}>First Name:</label>
<input name={field.name} {...field.getInputProps()} />
<input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
);
Expand All @@ -72,7 +83,12 @@ export default function App() {
children={(field) => (
<>
<label htmlFor={field.name}>Last Name:</label>
<input name={field.name} {...field.getInputProps()} />
<input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
)}
Expand Down
Loading