@kitr/forms 0.0.0-stage → 0.3.0
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/LICENSE +21 -0
- package/README.md +14 -2
- package/dist/index.d.ts +96 -0
- package/dist/index.js +183 -0
- package/dist/kitr.d.ts +28 -0
- package/dist/kitr.js +49 -0
- package/docs/api.md +77 -0
- package/docs/index.md +841 -0
- package/docs/overview.md +95 -0
- package/package.json +68 -3
package/docs/overview.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Overview
|
|
3
|
+
description: Build forms with validation, and show server errors next to the right field.
|
|
4
|
+
order: 0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Forms
|
|
8
|
+
|
|
9
|
+
## What it is
|
|
10
|
+
|
|
11
|
+
`@kitr/forms` is React Hook Form plus the kitr pieces. `useSchemaForm` builds a form from a schema, so the type and the rules are one thing. `<Form>` submits to an action or API route, shows a pending state and puts server errors on the right fields.
|
|
12
|
+
|
|
13
|
+
Runs in the browser. The server half is [actions](/packages/actions) or [API routes](/packages/api).
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
kitr add forms
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Adds `@kitr/forms` with react-hook-form, its resolvers and zod. No provider, no config file. [Every change](/packages/forms/guide#install).
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
Start with a schema, then build the form from it. Each field is a `<FormField>` with an input inside:
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
// app/features/invoices/new-invoice-form.tsx
|
|
29
|
+
import { FieldInput, Form, FormField, SubmitButton, useRootError, useSchemaForm } from '@kitr/forms'
|
|
30
|
+
import { z } from 'zod'
|
|
31
|
+
|
|
32
|
+
const newInvoiceSchema = z.object({
|
|
33
|
+
customerEmail: z.email('Enter the customer’s email'),
|
|
34
|
+
amount: z.coerce.number().positive('Amount must be more than zero'),
|
|
35
|
+
})
|
|
36
|
+
type NewInvoice = z.output<typeof newInvoiceSchema>
|
|
37
|
+
|
|
38
|
+
export function NewInvoiceForm({ onCreate }: { onCreate: (invoice: NewInvoice) => Promise<unknown> }) {
|
|
39
|
+
const form = useSchemaForm(newInvoiceSchema, { defaultValues: { customerEmail: '', amount: '' } })
|
|
40
|
+
return (
|
|
41
|
+
<Form form={form} onSubmit={onCreate} resetOnSuccess aria-label="New invoice">
|
|
42
|
+
<FormField name="customerEmail" label="Customer email">
|
|
43
|
+
<FieldInput type="email" />
|
|
44
|
+
</FormField>
|
|
45
|
+
<FormField name="amount" label="Amount (USD)">
|
|
46
|
+
<FieldInput inputMode="decimal" />
|
|
47
|
+
</FormField>
|
|
48
|
+
<RootError />
|
|
49
|
+
<SubmitButton pendingText="Creating…">Create invoice</SubmitButton>
|
|
50
|
+
</Form>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function RootError() {
|
|
55
|
+
const error = useRootError()
|
|
56
|
+
return error ? <p role="alert">{error}</p> : null
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Render `<NewInvoiceForm onCreate={async (invoice) => console.log('created', invoice)} />` on a page. Tab out of the empty email field and "Enter the customer’s email" appears under it. Fill in `grace@acme.com` and `120`, press the button, and the console prints:
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
created { customerEmail: 'grace@acme.com', amount: 120 }
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`amount` arrives as the number `120`, because `onSubmit` receives the schema's output. While `onCreate` runs the button reads "Creating…". Next in the guide: [Build your first form](/packages/forms/guide#build-your-first-form).
|
|
67
|
+
|
|
68
|
+
## Built on
|
|
69
|
+
|
|
70
|
+
| What kitr adds | Why |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| `useSchemaForm` | React Hook Form with a [Standard Schema](https://standardschema.dev) resolver, so zod, valibot or arktype schemas type the form. |
|
|
73
|
+
| `<Form>` | Submits a mutation, shows a pending state, and maps `KitrError.fieldErrors` onto fields. |
|
|
74
|
+
| `FormField`, `useFieldProps`, `SubmitButton` | Headless field wiring with `aria-*` attributes and `data-kitr` attributes for styling, and a button that follows the pending state. |
|
|
75
|
+
| `kitr make:form` | A generator for a form file with its schema. |
|
|
76
|
+
|
|
77
|
+
kitr adds `useSchemaForm`, `<Form>`, the field components with accessibility attributes and the server error mapping.
|
|
78
|
+
|
|
79
|
+
## Problems it solves
|
|
80
|
+
|
|
81
|
+
- **Validation rules and types written twice.** [Build your first form](/packages/forms/guide#build-your-first-form).
|
|
82
|
+
- **Server errors in a generic alert.** [Show server errors on fields](/packages/forms/guide#show-server-errors-on-fields).
|
|
83
|
+
- **Double submits.** [Show a pending state](/packages/forms/guide#show-a-pending-state).
|
|
84
|
+
- **Editing an existing record.** [Edit an existing record](/packages/forms/guide#edit-an-existing-record).
|
|
85
|
+
- **Inputs the library does not know about.** [Wrap a controlled component](/packages/forms/guide#wrap-a-controlled-component).
|
|
86
|
+
- **Inaccessible forms.** [Make forms accessible](/packages/forms/guide#make-forms-accessible).
|
|
87
|
+
|
|
88
|
+
## Further reading
|
|
89
|
+
|
|
90
|
+
- [Guide](/packages/forms/guide).
|
|
91
|
+
- [API reference](/packages/forms/api).
|
|
92
|
+
- [React Hook Form docs](https://react-hook-form.com/docs).
|
|
93
|
+
- [Standard Schema](https://standardschema.dev).
|
|
94
|
+
- [Actions](/packages/actions) and [Query](/packages/query).
|
|
95
|
+
- [Tailwind](/packages/tailwind).
|
package/package.json
CHANGED
|
@@ -1,6 +1,71 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kitr/forms",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "@kitr/forms: React Hook Form re-exported, plus useSchemaForm, <Form>, <FormField> and server-error mapping.",
|
|
5
|
+
"kitr": {
|
|
6
|
+
"name": "forms",
|
|
7
|
+
"title": "Forms",
|
|
8
|
+
"summary": "Build forms with validation, and show server errors next to the right field.",
|
|
9
|
+
"category": "forms",
|
|
10
|
+
"runsOn": "client",
|
|
11
|
+
"builtOn": [
|
|
12
|
+
"react-hook-form"
|
|
13
|
+
],
|
|
14
|
+
"client": true,
|
|
15
|
+
"docs": "docs",
|
|
16
|
+
"setup": "./kitr"
|
|
17
|
+
},
|
|
18
|
+
"type": "module",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/kitrjs/kitr.git",
|
|
23
|
+
"directory": "packages/forms"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://kitr.dev/packages/forms",
|
|
26
|
+
"bugs": "https://github.com/kitrjs/kitr/issues",
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"sideEffects": false,
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"default": "./dist/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./kitr": {
|
|
37
|
+
"types": "./dist/kitr.d.ts",
|
|
38
|
+
"default": "./dist/kitr.js"
|
|
39
|
+
},
|
|
40
|
+
"./package.json": "./package.json"
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"dist",
|
|
44
|
+
"docs"
|
|
45
|
+
],
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@kitr/core": "0.3.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"react": ">=18.0.0",
|
|
51
|
+
"react-hook-form": ">=7.50.0",
|
|
52
|
+
"@hookform/resolvers": ">=5.0.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@hookform/resolvers": "^7.0.3",
|
|
56
|
+
"@types/react": "^19.3.0",
|
|
57
|
+
"react": "^19.3.1",
|
|
58
|
+
"react-hook-form": "^7.91.0",
|
|
59
|
+
"tsdown": "^0.23.7",
|
|
60
|
+
"typescript": "^5.9.3",
|
|
61
|
+
"zod": "^4.6.7"
|
|
62
|
+
},
|
|
63
|
+
"keywords": [
|
|
64
|
+
"kitr",
|
|
65
|
+
"kitr-package"
|
|
66
|
+
],
|
|
67
|
+
"scripts": {
|
|
68
|
+
"build": "tsdown",
|
|
69
|
+
"typecheck": "tsc -p tsconfig.json"
|
|
70
|
+
}
|
|
6
71
|
}
|