Skip to content
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
8 changes: 8 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# 1.2.0

- add onValidated - fired once after validation occurs.

- now using useEffect for event firing.

^-- this change should result in less calls to `onError` `onValidated`, `onInvalid` and `onValid`

# 1.1.0

- why are badges so difficult to get right? fixing it for real this time
Expand Down
4 changes: 2 additions & 2 deletions examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
href="https://unpkg.com/bootstrap@4.3.1/dist/css/bootstrap.min.css"
/>
<script src="https://unpkg.com/@babel/standalone/babel.js"></script>
<script src="babel-preset.js"></script>
<script src="/babel-preset.js"></script>
<script src="https://unpkg.com/react@16.11.0/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16.11.0/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/prop-types@15.7.2/prop-types.min.js"></script>
<script src="/dist/index.umd.js"></script>
<script src="/index.umd.js"></script>

<style>
.loading .form-control,
Expand Down
2,042 changes: 1,562 additions & 480 deletions package-lock.json

Large diffs are not rendered by default.

34 changes: 17 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tswaters/react-form-validation",
"version": "1.1.0",
"version": "1.2.0",
"description": "React form validation components",
"browser": "dist/index.umd.js",
"main": "./dist/index.cjs.js",
Expand Down Expand Up @@ -28,31 +28,31 @@
},
"dependencies": {},
"devDependencies": {
"@babel/cli": "^7.6.4",
"@babel/core": "^7.6.4",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.4.4",
"@babel/plugin-proposal-optional-chaining": "^7.6.0",
"@babel/preset-env": "^7.6.3",
"@babel/preset-react": "^7.6.3",
"@babel/register": "^7.6.2",
"@babel/cli": "^7.7.5",
"@babel/core": "^7.7.5",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.7.4",
"@babel/plugin-proposal-optional-chaining": "^7.7.5",
"@babel/preset-env": "^7.7.6",
"@babel/preset-react": "^7.7.4",
"@babel/register": "^7.7.4",
"babel-eslint": "^10.0.3",
"bootstrap": "^4.3.1",
"coveralls": "^3.0.7",
"bootstrap": "^4.4.1",
"coveralls": "^3.0.9",
"cross-env": "^6.0.3",
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.15.1",
"eslint": "^6.6.0",
"eslint-plugin-react": "^7.16.0",
"eslint-plugin-react-hooks": "^2.2.0",
"eslint": "^6.7.2",
"eslint-plugin-react": "^7.17.0",
"eslint-plugin-react-hooks": "^2.3.0",
"jsdom": "^15.2.1",
"mocha": "^6.2.2",
"nyc": "^14.1.1",
"prettier": "^1.18.2",
"prettier": "^1.19.1",
"prop-types": "^15.7.2",
"react": "^16.11.0",
"react-dom": "^16.11.0",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"rimraf": "^3.0.0",
"rollup": "^1.26.2",
"rollup": "^1.27.9",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-serve": "^1.0.1",
"rollup-plugin-terser": "^5.1.2",
Expand Down
25 changes: 12 additions & 13 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
# React Form Validation

<a href="https://www.npmjs.org/package/@tswaters/react-form-validation">
<img src="https://img.shields.io/npm/v/@tswaters/react-form-validation" alt="npm version">
</a>
<a href="https://travis-ci.org/tswaters/react-form-validation/">
<img src="https://img.shields.io/travis/tswaters/react-form-validation" alt="build status">
</a>
<a href="https://coveralls.io/github/tswaters/react-form-validation">
<img src="https://img.shields.io/coveralls/github/tswaters/react-form-validation" alt="coverage">
</a>
<a href="https://github.com/tswaters/react-form-validation/blob/master/LICENSE">
<img src="https://img.shields.io/npm/l/@tswaters/react-form-validation" alt="license (MIT)">
</a>
<a href="https://www.npmjs.org/package/@tswaters/react-form-validation"><img
src="https://img.shields.io/npm/v/@tswaters/react-form-validation" alt="npm version"></a>
<a href="https://travis-ci.org/tswaters/react-form-validation/"><img
src="https://img.shields.io/travis/tswaters/react-form-validation" alt="build status"></a>
<a href="https://coveralls.io/github/tswaters/react-form-validation"><img
src="https://img.shields.io/coveralls/github/tswaters/react-form-validation" alt="coverage"></a>
<a href="https://github.com/tswaters/react-form-validation/blob/master/LICENSE"><img
src="https://img.shields.io/npm/l/@tswaters/react-form-validation" alt="license (MIT)"></a>

The goal of this library is to implement the [Constraint Validation API](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#the-constraint-validation-api) in React while not getting in your way to do it.

Expand Down Expand Up @@ -71,7 +67,7 @@ Input/Select/TextArea take all the same props.
import { Input, Select, TextArea } from '@tswaters/react-form-validation'
const example = () => (
<>
<Input
<Input // Select | TextArea
validation={oneOfType([arrayOf(func), func])}
other={oneOfType([arrayOf(string), string])}
recheck={bool}
Expand All @@ -80,6 +76,7 @@ const example = () => (
onError={func}
onInvalid={func}
onValid={func}
onValidated={func}
/>
</>
)
Expand Down Expand Up @@ -108,6 +105,8 @@ const example = () => (

- **onValid** _(bool) => void_ will be called after validation with a bool indicating the form field is valid

- **onValidated** _(bool) => void_ will be called after an input is validated.

Any additional props will be passed down to the underlying `input/select/textarea` element

### Validator
Expand Down
4 changes: 2 additions & 2 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ const config = (format, file, minify, server = false) => ({
serve({
port: 8001,
host: '0.0.0.0',
path: 'index.html',
contentBase: ['dist', 'node_modules'],
path: 'examples/index.html',
contentBase: ['examples', 'dist', 'node_modules'],
open: false,
wait: 500
})
Expand Down
1 change: 1 addition & 0 deletions src/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const Form = forwardRef(({ onSubmit, ...rest }, ref) => {
* Form submit handler
* Verify each of our inputs passes validation before calling onSubmit
* But if validation fails, it won't ever be called - make sure to not submit the form.
* Calling `.persist()` because when async comes back, the `e.target` is null.
*/
const handleSubmit = useCallback(
async e => {
Expand Down
5 changes: 4 additions & 1 deletion src/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const propTypes = {
onError: func,
onValid: func,
onInvalid: func,
onValidated: func,
name: string.isRequired // form elements must have name!
}

Expand All @@ -39,6 +40,7 @@ const createInput = inputType => {
onError,
onValid,
onInvalid,
onValidated,
...rest
},
ref
Expand All @@ -64,7 +66,8 @@ const createInput = inputType => {
click,
onError,
onValid,
onInvalid
onInvalid,
onValidated
})

return React.createElement(inputType, {
Expand Down
30 changes: 25 additions & 5 deletions src/use-validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ const useValidation = (
click,
onError,
onInvalid,
onValid
onValid,
onValidated
}
) => {
const ctx = useContext(FormContext)
Expand All @@ -48,6 +49,9 @@ const useValidation = (
const timeoutRef = useRef(null)
const argsRef = useRef(null)
const [validated, setValidated] = useState(false)
const [valid, setValid] = useState(null)
const [error, setError] = useState(null)
const [invalid, setInvalid] = useState(null)

const waitForValidation = useCallback(
e => {
Expand All @@ -64,14 +68,30 @@ const useValidation = (
(error, validity) => {
const is_valid = error == null || error === false || error === ''
const is_invalid = !is_valid
onValid?.(is_valid)
onError?.(is_valid ? null : getError(error, validity))
onInvalid?.(is_invalid)
setValid(is_valid)
setInvalid(is_invalid)
setError(is_valid ? null : getError(error, validity))
setValidated(true)
},
[onError, onValid, onInvalid]
[setValid, setInvalid, setError, setValidated]
)

useEffect(() => {
onValid?.(valid)
}, [onValid, valid])

useEffect(() => {
onError?.(error)
}, [onError, error])

useEffect(() => {
onInvalid?.(invalid)
}, [onInvalid, invalid])

useEffect(() => {
onValidated?.(validated)
}, [onValidated, validated])

const handleOnInvalid = useCallback(
({ target: element }) =>
updateState(new Error(element.validationMessage), element.validity),
Expand Down
14 changes: 4 additions & 10 deletions src/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
isValidElement,
memo,
useCallback,
useMemo,
useState
} from 'react'
import { oneOfType, arrayOf, func } from 'prop-types'
Expand All @@ -14,10 +13,7 @@ import { Input, Select, TextArea } from './input'
const mapDeep = (children, fn) =>
Children.map(children, (child, index) =>
isValidElement(child) &&
Children.toArray(child.props.children).reduce(
(response, child) => response || isValidElement(child),
false
)
Children.toArray(child.props.children).some(child => isValidElement(child))
? fn(
cloneElement(child, {
...child.props,
Expand All @@ -40,14 +36,11 @@ const Validator = ({ children, ...rest }) => {
const [error, setError] = useState(null)
const [valid, setValid] = useState(null)
const [invalid, setInvalid] = useState(null)
const [validated, setValidated] = useState(null)
const handleError = useCallback(e => setError(e), [])
const handleValid = useCallback(e => setValid(e), [])
const handleInvalid = useCallback(e => setInvalid(e), [])
const validated = useMemo(() => error || valid || invalid, [
error,
invalid,
valid
])
const handleValidated = useCallback(e => setValidated(e), [])
return mapDeep(children({ error, valid, invalid, validated }), item => {
const myCtor = getCtorFromItem(item)
if (myCtor == null) return item
Expand All @@ -56,6 +49,7 @@ const Validator = ({ children, ...rest }) => {
onError: handleError,
onValid: handleValid,
onInvalid: handleInvalid,
onValidated: handleValidated,
...item.props
})
})
Expand Down
2 changes: 1 addition & 1 deletion test/utils.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const wait = () => new Promise(resolve => setImmediate(resolve))
export const wait = () => new Promise(resolve => setTimeout(resolve, 0))