Skip to content

Commit

Permalink
feat: valibot form adapter (#499)
Browse files Browse the repository at this point in the history
* feat: mount method on FormApi

* fix solid-form test case

* fix: added form.mount() to tests

* feat: valibot-form-adapter

* chore: add missing config items

* docs: add Valibot React example

* docs: add Solid Valibot example

* docs: add valibot Vue example

* fix: valibot async adapter now works

* docs: add docs for valibot adapter

---------

Co-authored-by: Corbin Crutchley <[email protected]>
  • Loading branch information
aadito123 and crutchcorn authored Nov 5, 2023
1 parent 1a37fab commit 31f6261
Show file tree
Hide file tree
Showing 57 changed files with 2,150 additions and 1,495 deletions.
12 changes: 12 additions & 0 deletions docs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@
{
"label": "Zod",
"to": "framework/react/examples/zod"
},
{
"label": "Valibot",
"to": "framework/react/examples/valibot"
}
]
}
Expand Down Expand Up @@ -153,6 +157,10 @@
{
"label": "Zod",
"to": "framework/vue/examples/zod"
},
{
"label": "Valibot",
"to": "framework/vue/examples/valibot"
}
]
}
Expand Down Expand Up @@ -205,6 +213,10 @@
{
"label": "Zod",
"to": "framework/solid/examples/zod"
},
{
"label": "Valibot",
"to": "framework/solid/examples/valibot"
}
]
}
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/basic-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ Example:

## Validation Adapters

In addition to hand-rolled validation options, we also provide adapters like `@tanstack/zod-form-adapter` and `@tanstack/yup-form-adapter` to enable usage with common schema validation tools like [Yup](https://github.com/jquense/yup) and [Zod](https://zod.dev/).
In addition to hand-rolled validation options, we also provide adapters like `@tanstack/zod-form-adapter`, `@tanstack/yup-form-adapter`, and `@tanstack/valibot-form-adapter` to enable usage with common schema validation tools like [Zod](https://zod.dev/), [Yup](https://github.com/jquense/yup), and [Valibot](https://valibot.dev/).

Example:

Expand Down
6 changes: 4 additions & 2 deletions docs/guides/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,16 +246,18 @@ This will debounce every async call with a 500ms delay. You can even override th
> This will run `onChangeAsync` every 1500ms while `onBlurAsync` will run every 500ms.

## Adapter-Based Validation (Zod, Yup)
## Adapter-Based Validation (Zod, Yup, Valibot)

While functions provide more flexibility and customization over your validation, they can be a bit verbose. To help solve this, there are libraries like [Yup](https://github.com/jquense/yup) and [Zod](https://zod.dev/) that provide schema-based validation to make shorthand and type-strict validation substantially easier.
While functions provide more flexibility and customization over your validation, they can be a bit verbose. To help solve this, there are libraries like [Valibot](https://valibot.dev/), [Yup](https://github.com/jquense/yup), and [Zod](https://zod.dev/) that provide schema-based validation to make shorthand and type-strict validation substantially easier.

Luckily, we support both of these libraries through official adapters:

```bash
$ npm install @tanstack/zod-form-adapter zod
# or
$ npm install @tanstack/yup-form-adapter yup
# or
$ npm install @tanstack/valibot-form-adapter valibot
```

Once done, we can add the adapter to the `validator` property on the form or field:
Expand Down
2 changes: 2 additions & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ In addition, we support both Zod and Yup as validators through official validato
$ npm i @tanstack/zod-form-adapter zod
# or
$ npm i @tanstack/yup-form-adapter yup
# or
$ npm i @tanstack/valibot-form-adapter valibot
```
1 change: 0 additions & 1 deletion examples/react/simple/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
},
"dependencies": {
"@tanstack/react-form": "0.8.1",
"axios": "^0.26.1",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"@tanstack/form-core": "0.8.1",
Expand Down
15 changes: 15 additions & 0 deletions examples/react/valibot/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// @ts-check

/** @type {import('eslint').Linter.Config} */
const config = {
extends: ["plugin:react/recommended", "plugin:react-hooks/recommended"],
parserOptions: {
tsconfigRootDir: __dirname,
project: "./tsconfig.json",
},
rules: {
"react/no-children-prop": "off",
},
};

module.exports = config;
27 changes: 27 additions & 0 deletions examples/react/valibot/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

pnpm-lock.yaml
yarn.lock
package-lock.json

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
1 change: 1 addition & 0 deletions examples/react/valibot/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
6 changes: 6 additions & 0 deletions examples/react/valibot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Example

To run this example:

- `npm install`
- `npm run dev`
16 changes: 16 additions & 0 deletions examples/react/valibot/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/emblem-light.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />

<title>TanStack Form React Valibot Example App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
52 changes: 52 additions & 0 deletions examples/react/valibot/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "@tanstack/form-example-react-valibot",
"version": "0.0.1",
"main": "src/index.jsx",
"scripts": {
"dev": "vite --port=3001",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@tanstack/react-form": "0.7.2",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"valibot": "^0.20.1",
"@tanstack/valibot-form-adapter": "0.7.2",
"@tanstack/form-core": "0.7.2",
"@tanstack/zod-form-adapter": "0.7.2",
"@tanstack/vue-form": "0.7.2",
"@tanstack/yup-form-adapter": "0.7.2",
"@tanstack/solid-form": "0.7.2"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.0.4",
"vite": "^4.4.9"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"nx": {
"implicitDependencies": [
"@tanstack/form-core",
"@tanstack/react-form",
"@tanstack/zod-form-adapter"
],
"targets": {
"test:types": {
"dependsOn": [
"build"
]
}
}
}
}
13 changes: 13 additions & 0 deletions examples/react/valibot/public/emblem-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
120 changes: 120 additions & 0 deletions examples/react/valibot/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import * as React from "react";
import { createRoot } from "react-dom/client";
import { useForm } from "@tanstack/react-form";
import { valibotValidator } from "@tanstack/valibot-form-adapter";
import { string, minLength, stringAsync, PipeResult } from "valibot";
import type { FieldApi } from "@tanstack/react-form";

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

export default function App() {
const form = useForm({
defaultValues: {
firstName: "",
lastName: "",
},
onSubmit: async (values) => {
// Do something with form data
console.log(values);
},
// Add a validator to support Valibot usage in Form and Field
validator: valibotValidator,
});

return (
<div>
<h1>Valibot Form Example</h1>
<form.Provider>
<form
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
void form.handleSubmit();
}}
>
<div>
{/* A type-safe field component*/}
<form.Field
name="firstName"
onChange={string([
minLength(3, "First name must be at least 3 characters"),
])}
onChangeAsyncDebounceMs={500}
onChangeAsync={stringAsync([
async (value) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
return (
value.includes("error")
? {
issues: [
{
input: value,
validation: "firstName",
message: "No 'error' allowed in first name",
},
],
}
: { output: value }
) as PipeResult<string>;
},
])}
children={(field) => {
// Avoid hasty abstractions. Render props are great!
return (
<>
<label htmlFor={field.name}>First Name:</label>
<input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
);
}}
/>
</div>
<div>
<form.Field
name="lastName"
children={(field) => (
<>
<label htmlFor={field.name}>Last Name:</label>
<input
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
)}
/>
</div>
<form.Subscribe
selector={(state) => [state.canSubmit, state.isSubmitting]}
children={([canSubmit, isSubmitting]) => (
<button type="submit" disabled={!canSubmit}>
{isSubmitting ? "..." : "Submit"}
</button>
)}
/>
</form>
</form.Provider>
</div>
);
}

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

createRoot(rootElement).render(<App />);
7 changes: 7 additions & 0 deletions examples/react/valibot/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"compilerOptions": {
"jsx": "react",
"noEmit": true,
"lib": ["DOM", "DOM.Iterable", "ES2020"]
}
}
1 change: 0 additions & 1 deletion examples/react/yup/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
},
"dependencies": {
"@tanstack/react-form": "0.8.1",
"axios": "^0.26.1",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"yup": "^1.3.2",
Expand Down
1 change: 0 additions & 1 deletion examples/react/zod/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
},
"dependencies": {
"@tanstack/react-form": "0.8.1",
"axios": "^0.26.1",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"zod": "^3.21.4",
Expand Down
24 changes: 24 additions & 0 deletions examples/solid/valibot/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
Loading

0 comments on commit 31f6261

Please sign in to comment.