Skip to content

Commit 3fbb25d

Browse files
committed
Initial setup
0 parents  commit 3fbb25d

13 files changed

+4371
-0
lines changed

.eslintrc.json

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"extends": [
3+
"eslint:recommended",
4+
"plugin:@typescript-eslint/recommended",
5+
"plugin:react/recommended",
6+
7+
"plugin:prettier/recommended",
8+
"prettier/@typescript-eslint"
9+
],
10+
"plugins": [
11+
"react",
12+
"@typescript-eslint",
13+
"prettier",
14+
"react-hooks",
15+
"simple-import-sort"
16+
],
17+
"parser": "@typescript-eslint/parser",
18+
"env": { "browser": true, "node": true, "es6": true, "jest": true },
19+
"parserOptions": {
20+
"sourceType": "module"
21+
},
22+
"settings": {
23+
"react": {
24+
"pragma": "React",
25+
"version": "detect"
26+
}
27+
},
28+
"rules": {
29+
"react-hooks/rules-of-hooks": "error",
30+
"simple-import-sort/sort": "error",
31+
"prettier/prettier": ["error"],
32+
"linebreak-style": 0,
33+
"camelcase": "off",
34+
"endOfLine": 0,
35+
"@typescript-eslint/camelcase": [
36+
"error",
37+
{
38+
"ignoreDestructuring": true
39+
}
40+
],
41+
"@typescript-eslint/explicit-function-return-type": 0
42+
}
43+
}

.gitignore

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
lerna-debug.log*
8+
9+
# Directory for instrumented libs generated by jscoverage/JSCover
10+
lib-cov
11+
12+
# Coverage directory used by tools like istanbul
13+
coverage
14+
*.lcov
15+
16+
# nyc test coverage
17+
.nyc_output
18+
19+
# node-waf configuration
20+
.lock-wscript
21+
22+
# Compiled binary addons (https://nodejs.org/api/addons.html)
23+
build/Release
24+
25+
# Dependency directories
26+
node_modules/
27+
jspm_packages/
28+
29+
# TypeScript v1 declaration files
30+
typings/
31+
32+
# TypeScript cache
33+
*.tsbuildinfo
34+
35+
# Optional npm cache directory
36+
.npm
37+
38+
# Optional eslint cache
39+
.eslintcache
40+
41+
# Output of 'npm pack'
42+
*.tgz
43+
44+
# Yarn Integrity file
45+
.yarn-integrity
46+
47+
# generate output
48+
dist
49+
50+
# local todo list for development
51+
.todo

.npmignore

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
dist
2+
.babelrc
3+
.storybook
4+
.gitignore
5+
.prettierrc
6+
rollup.config.js
7+
tsconfig.json

.nvmrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
17.8.0

.prettierrc

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"semi": true,
3+
"trailingComma": "all",
4+
"singleQuote": true,
5+
"printWidth": 85,
6+
"tabWidth": 2,
7+
"endOfLine": "auto"
8+
}

README.md

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# React AJV Schema Hook
2+
3+
![Drag Racing](./assets/ajv-react.png)
4+
5+
[use-ajv-form](https://github.com/agjs/use-ajv-form) is a custom React Hook that enables you to generate your form logic and validation based on [Ajv JSON Schema Validator](https://ajv.js.org/).
6+
7+
It integrates seamlessly with any form and is completely agnostic from your form markup. It simply provides the state and validation. You choose how you want to present the errors and organise your forms. In simple words, it's completely decoupled from how your forms work, look and feel.
8+
9+
# Why
10+
11+
Validating forms manually is a painful process. Ajv solves that by not only providing validation based on valid JSON Schema Specification, but also, provides custom plugins and keywords that allow you to create your own custom validators. That means that you can extend your schema with infinite amount of validators, and keep your forms still purely depend on the schema, without introducing manual if statements all over the place.
12+
13+
This library is used by all forms on [Programmer Network](https://programmer.network/) and is Open Sourced due to our amazing community on an official [Programmer Network Twitch Channel](https://twitch.tv/programmer_network).
14+
15+
# Install
16+
17+
`yarn add @programmer_network/use-ajv-form`
18+
19+
or
20+
21+
`npm install @programmer_network/use-ajv-form`
22+
23+
# Usage
24+
25+
[Codesandbox Live Demo](https://google.com)
26+
27+
Let's start with a simple example.
28+
29+
Let's create our form object. This object contains methods and state that our form will depend on.
30+
31+
```javascript
32+
import { useAjvForm } from '@programmer_network/useAjvForm';
33+
34+
const initialState = {
35+
title: '',
36+
description: '',
37+
};
38+
39+
const schema = {
40+
type: 'object',
41+
required: ['title'],
42+
properties: {
43+
title: {
44+
type: 'string',
45+
},
46+
description: {
47+
type: 'string',
48+
minLength: 20,
49+
errorMessages: {
50+
minLength: 'Description is too short. At least 20 characters expected.',
51+
},
52+
},
53+
},
54+
};
55+
56+
const form = useAjvForm(initialState, schema);
57+
```
58+
59+
Then we create a onSubmit form handler that will call our validators.
60+
61+
```js
62+
const handleSubmit = (event) => {
63+
event.preventDefault();
64+
65+
if (!form.isValid()) {
66+
// form is invalid, exit early
67+
// when this happens, our hook will update the fields that failed validation
68+
return;
69+
}
70+
71+
// validation successful, call some API
72+
axios.post('someUrl', form.data);
73+
};
74+
```
75+
76+
Generally, your own Input component takes a value and an error. If you are using component composition, this might look a bit different, but you get the point.
77+
78+
```jsx
79+
// your custom input component
80+
const CustomInput = ({ value, error, name }) => {
81+
<input type="text" name={name} value={value} />;
82+
{
83+
error && <span>{error}</span>;
84+
}
85+
};
86+
```
87+
88+
As you may notice, for every given property in your schema, our hook will create a value and error properties. Error property is initially set to null, and the value to whatever values are set in your initial state.
89+
90+
```jsx
91+
<form onSubmit={handleSubmit}>
92+
<CustomInput name="title" value={form.state.title.value} />
93+
<CustomInput name="description" value={form.state.description.value} />
94+
<button type="submit">Submit</button>
95+
</form>
96+
```

assets/ajv-react.png

28.2 KB
Loading

package.json

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
{
2+
"name": "use-ajv-form",
3+
"version": "1.0.0",
4+
"description": "Custom React Hook that integrates with Ajv JSON Schema Validator",
5+
"main": "dist/index.js",
6+
"scripts": {
7+
"build": "rollup -c",
8+
"start": "rollup -c -w",
9+
"test": "jest"
10+
},
11+
"engines": {
12+
"node": ">=8",
13+
"npm": ">=5"
14+
},
15+
"jest": {
16+
"transform": {
17+
".(ts|tsx)": "ts-jest"
18+
},
19+
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
20+
"moduleFileExtensions": [
21+
"ts",
22+
"tsx",
23+
"js"
24+
],
25+
"modulePathIgnorePatterns": [
26+
"<rootDir>/dist/"
27+
]
28+
},
29+
"repository": {
30+
"type": "git",
31+
"url": "git+https://github.com/agjs/use-ajv-form.git"
32+
},
33+
"author": "Aleksandar Grbic",
34+
"license": "ISC",
35+
"bugs": {
36+
"url": "https://github.com/agjs/use-ajv-form/issues"
37+
},
38+
"homepage": "https://github.com/agjs/use-ajv-form#readme",
39+
"peerDependencies": {
40+
"react": ">= 16.8.0",
41+
"react-dom": ">= 16.8.0"
42+
},
43+
"dependencies": {
44+
"prop-types": "^15.7.2"
45+
},
46+
"devDependencies": {
47+
"@testing-library/react-hooks": "^3.4.1",
48+
"@types/jest": "^26.0.7",
49+
"@types/react": "^16.3.13",
50+
"@types/react-dom": "^16.0.5",
51+
"babel-core": "^6.26.3",
52+
"babel-runtime": "^6.26.0",
53+
"eslint-plugin-react-hooks": "^4.0.8",
54+
"jest": "^26.1.0",
55+
"react": "^16.12.0",
56+
"react-dom": "^16.12.0",
57+
"react-test-renderer": "^16.13.1",
58+
"rollup": "^1.29.0",
59+
"rollup-plugin-typescript2": "^0.25.3",
60+
"rollup-plugin-uglify": "^6.0.4",
61+
"ts-jest": "^26.1.3",
62+
"typescript": "^3.8.3"
63+
},
64+
"files": [
65+
"dist"
66+
],
67+
"keywords": [
68+
"react",
69+
"react hooks",
70+
"typescript",
71+
"npm"
72+
]
73+
}

rollup.config.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import typescript from "rollup-plugin-typescript2";
2+
import { uglify } from "rollup-plugin-uglify";
3+
4+
import pkg from "./package.json";
5+
6+
export default {
7+
input: "src/index.ts",
8+
output: [
9+
{
10+
file: pkg.main,
11+
format: "cjs",
12+
exports: "named",
13+
sourcemap: true,
14+
strict: false,
15+
},
16+
],
17+
plugins: [typescript(), uglify()],
18+
external: ["react", "react-dom"],
19+
};

src/hooks/useAjvForm/index.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const useAjvForm = (initialState, schema): number => {
2+
return 5;
3+
};
4+
5+
useCounter.defaultProps = {
6+
initialValue: 0,
7+
};

src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { useAjvForm } from './hooks/use-ajv-form';

tsconfig.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"compilerOptions": {
3+
"outDir": "dist",
4+
"module": "esnext",
5+
"target": "es5",
6+
"lib": ["es6", "dom", "es2016", "es2017"],
7+
"sourceMap": true,
8+
"allowJs": false,
9+
"jsx": "react",
10+
"declaration": true,
11+
"moduleResolution": "node",
12+
"forceConsistentCasingInFileNames": true,
13+
"noImplicitReturns": true,
14+
"noImplicitThis": true,
15+
"noImplicitAny": true,
16+
"strictNullChecks": true,
17+
"suppressImplicitAnyIndexErrors": true,
18+
"noUnusedLocals": true,
19+
"noUnusedParameters": true,
20+
"esModuleInterop": true,
21+
"strict": true
22+
},
23+
"include": ["src"],
24+
"exclude": ["node_modules", "dist", "example", "rollup.config.js"]
25+
}

0 commit comments

Comments
 (0)