Skip to content

Commit 03eb9af

Browse files
committed
feat: stimulus-zod-form
0 parents  commit 03eb9af

16 files changed

+8173
-0
lines changed

.eslintignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
dist
3+
docs/lib

.eslintrc.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/** @type {import('eslint').Linter.Config} */
2+
module.exports = {
3+
parser: "@typescript-eslint/parser",
4+
plugins: ["@typescript-eslint", "prettier"],
5+
extends: [
6+
"eslint:recommended",
7+
"plugin:@typescript-eslint/eslint-recommended",
8+
"plugin:@typescript-eslint/recommended",
9+
"plugin:prettier/recommended",
10+
],
11+
rules: {
12+
"@typescript-eslint/no-non-null-assertion": "off",
13+
"@typescript-eslint/no-explicit-any": "off",
14+
"@typescript-eslint/ban-ts-comment": "off",
15+
"@typescript-eslint/ban-types": "off",
16+
"@typescript-eslint/no-unused-vars": "off",
17+
},
18+
env: {
19+
browser: true,
20+
node: true,
21+
},
22+
};

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
dist
3+
coverage

.prettierrc.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module.exports = {
2+
plugins: [
3+
"prettier-plugin-organize-imports"
4+
],
5+
printWidth: 120,
6+
pluginSearchDirs: false,
7+
organizeImportsSkipDestructiveCodeActions: true,
8+
trailingComma: "es5",
9+
};

.vscode/settings.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"editor.formatOnSave": false,
3+
"editor.codeActionsOnSave": {
4+
"source.fixAll.eslint": true
5+
},
6+
"html.format.maxPreserveNewLines": 0,
7+
"html.format.wrapAttributes": "preserve-aligned",
8+
"typescript.tsdk": "node_modules/typescript/lib"
9+
}

README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Stimulus Zod Form
2+
3+
### Stimulus Zod Validated Form
4+
5+
For the ten people on earth who want to use [Zod](https://zod.dev/) with [Stimulus](https://stimulus.hotwired.dev/) for client side validation.
6+
7+
This package was inspired by [Remix Validated Form](https://www.remix-validated-form.io/) but a whole lot simpler thanks to Stimulus!
8+
9+
### Usage
10+
11+
Define your schema and register the controllers
12+
13+
```ts
14+
import { Application } from "@hotwired/stimulus"
15+
import { FormController, FieldController } from "stimulus-zod-form";
16+
import { z } from "zod";
17+
18+
const PersonSchema = z.object({
19+
name: z.string().min(3),
20+
email: z.string().email("invalid_email"),
21+
addresses: z.array(z.object({ city: z.string() }))
22+
})
23+
24+
const PersonFormController = FormController(PersonSchema);
25+
26+
window.Stimulus = Application.start();
27+
Stimulus.register("form", PersonFormController);
28+
Stimulus.register("field", FieldController);
29+
```
30+
31+
Let the controllers spring to life!
32+
33+
```html
34+
<form data-controller="form"
35+
data-form-field-outlet=".form-field"
36+
data-action="form#submit"
37+
data-form-error-map-value='{ "invalid_email": "correo inválido", ... }'>
38+
39+
<div data-form-target="error"></div>
40+
41+
<div data-controller="field" class="form-field">
42+
<input name="addresses[0].city"
43+
data-field-target="input"
44+
data-action="blur->field#setTouched blur->form#validate" />
45+
<div data-field-target="error"></div>
46+
</div>
47+
</form>
48+
```
49+
50+
### Summary
51+
52+
In the sample code above note the following
53+
54+
* Form field outlets `data-form-field-outlet`
55+
* Form validate on submit `data-action="form#submit"`
56+
* Field validate on blur `data-action="blur->field#setTouched blur->form#validate"`
57+
* Field input target `data-field-target="input"`
58+
* Field error target `data-field-target="error"`
59+
* Form error target ` data-form-target="error"`
60+
* Error localization `data-form-error-map-value`

jest.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/** @type {import('ts-jest').JestConfigWithTsJest} */
2+
module.exports = {
3+
preset: "ts-jest",
4+
testEnvironment: "jsdom",
5+
};

license.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
MIT License
3+
4+
Copyright (c) 2023 Ajai Shankar
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.

0 commit comments

Comments
 (0)