forked from godaddy/react-validation-context
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvalidates.js
109 lines (95 loc) · 3.43 KB
/
validates.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import React from 'react';
import { string, func, element, oneOf } from 'prop-types';
const undef = void 0;
function noop() {}
/**
* This library revolves around the idea of "validity". A component can have one of the following validities:
*
* - `undefined` - No validation state defined. This is the default.
* - `null` - Validation is disabled.
* - `true` - Validation passed.
* - `false` - Validation failed.
*
* @typedef {(undefined|null|Boolean)} Validity
*/
/**
* It is useful to know when a component's validity changes. As such, this library attempts to provide a uniform API for
* validation change handlers. In general, a validity change handler has the following API:
*
* @callback onValidChange
* @param {String} name - The unique identifier for the component whose validity changed.
* @param {Validity} isValid - The current validity of the component.
* @param {Validity} wasValid - The previous validity of the component.
*/
/**
* The `Validates` component is used to wrap a component that can be validated, providing the logic for validation change
* handlers.
*/
export default class Validates extends React.Component {
/**
* If `isValid !== wasValid` or `prevName !== this.props.name`, calls the onValidChange handlers in props and context with the
* specified arguments.
*
* @protected
* @param {Validity} isValid The current validity.
* @param {Validity} wasValid The previous validity.
* @param {Object} [prevName] The previous name that the component was using. If it is different than the current name, the
* props and context handlers will be called first with `undefined` to indicate the previous name no longer has validation.
*/
onValidChange(isValid, wasValid, prevName) {
const { onValidChange: propsHandler = noop } = this.props;
const { onValidChange: ctxHandler = noop } = this.context;
const { name } = this.props;
const nameChanged = prevName && prevName !== name;
const validChanged = isValid !== wasValid;
if (nameChanged && (undef !== wasValid)) {
propsHandler(prevName, undef, wasValid);
ctxHandler(prevName, undef, wasValid);
}
if (nameChanged || validChanged) {
propsHandler(name, isValid, wasValid);
ctxHandler(name, isValid, wasValid);
}
}
/**
* React lifecycle handler called immediately before the component's initial render
*/
componentWillMount() {
// Update the handlers with the initial state
this.onValidChange(this.props.validates);
}
/**
* React lifecycle handler called when a component finished updating.
*
* @param {Object} prevProps Component's previous props.
*/
componentDidUpdate(prevProps) {
const { validates: wasValid, name: prevName } = prevProps;
const { validates: isValid } = this.props;
this.onValidChange(isValid, wasValid, prevName);
}
/**
* React lifecycle handler called when component is about to be unmounted.
*/
componentWillUnmount() {
// Update the handlers with `isValid=undefined` to notify them that the component no longer is being validated
this.onValidChange(undef, this.props.validates);
}
/**
* Renders the component.
*
* @returns {React.DOM} Rendered component.
*/
render() {
return this.props.children || null;
}
}
Validates.propTypes = {
validates: oneOf([true, false, null]),
onValidChange: func,
name: string.isRequired,
children: element
};
Validates.contextTypes = {
onValidChange: func
};