on dee2cd5 help sign in
bridge/src/components/old/advancedInput.js
147 lines 4.4 kB history raw
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
4import { compose, defaultTo } from '../../lib/lib';
6// =============================================================================
7// Utils
9const initMessage = data => ({
10 data: data,
11 pass: true,
12 error: '',
13});
15// Validation display triggers
16const displayTriggers = {
17 eagerSuccess: r => r.pass,
18 eagerFailure: r => !r.pass,
19 tactfulSuccess: r => r.pass && r.beenFocussed,
20 tactfulFailure: r => !r.pass && r.beenFocussed && !r.focussed,
21};
23// =============================================================================
24// AdvancedInput
26const advancedInput = ({ WrappedComponent, validators, transformers }) => {
27 // set argument defaults
28 validators = defaultTo(validators, []);
29 transformers = defaultTo(transformers, []);
31 class AdvancedInputHOC extends Component {
32 constructor(props) {
33 super(props);
34 this.state = {
35 focussed: false,
36 beenFocussed: false,
37 };
38 this.onFocus = this.onFocus.bind(this);
39 this.onBlur = this.onBlur.bind(this);
40 this.onChange = this.onChange.bind(this);
41 }
43 onFocus = () => this.setState({ focussed: true });
45 onBlur = () => this.setState({ focussed: false, beenFocussed: true });
47 onChange = value => {
48 const { props } = this;
50 // =======================================================================
51 // 0. RUN VALUE TRANSFORMERS
53 // This applies functions to the input value and updates state with the
54 // new value. This is useful for ship/point names which technically
55 // should always have a sig prepending them, but users might not know/care
56 // about such a technicality. ValueTransformers are executed from right to
57 // left.
58 const newValue = compose(...transformers)(value);
60 props.onChange(newValue);
61 };
63 render() {
64 const { state, props } = this;
66 // =======================================================================
67 // RUN VALIDATORS AND DETERMINE STYLES
69 // Run validation chain on the transformed value. Validators are executed
70 // from right to left and exit on the first validation failure.
72 const report = compose(
73 ...validators,
74 initMessage
75 )(props.value);
77 // Makes a uniform data structure to pass to display triggers. This
78 // removes the need to rely on argument order for these functions.
79 const stateReport = {
80 pass: report.pass,
81 beenFocussed: state.beenFocussed,
82 focussed: state.focussed,
83 submitted: props.submitted,
84 };
86 // Determine if the passing validation style or message should be shown
87 const displayPass = displayTriggers.eagerSuccess(stateReport);
89 // Determine if the failing validation style or message should be shown
90 const displayFailure = displayTriggers.tactfulFailure(stateReport);
92 // Generate class strings for validation state. VCN stands for validation
93 // class names
94 const valClassname = styleSelector(displayPass, displayFailure);
96 return (
97 <WrappedComponent
98 {...props}
99 // Events
100 onFocus={this.onFocus}
101 onBlur={this.onBlur}
102 onChange={this.onChange}
103 // stateReport
104 focussed={state.focussed}
105 beenFocussed={state.beenFocussed}
106 displayPass={displayPass}
107 displayFailure={displayFailure}
108 // 'error' prop refers to an error message string, not the presence
109 // of an error.
110 error={report.error}
111 didPass={report.pass}
112 value={props.value}
113 className={props.className}
114 disabled={props.disabled}
115 valClassname={valClassname}
116 advanced={true}
117 />
118 );
119 }
120 }
122 AdvancedInputHOC.propTypes = {
123 className: PropTypes.string,
124 style: PropTypes.object,
125 value: PropTypes.string,
126 submitted: PropTypes.bool,
127 };
129 AdvancedInputHOC.defaultProps = {
130 className: '',
131 style: {},
132 value: '',
133 submitted: false,
134 };
136 return AdvancedInputHOC;
137 // END advancedInput()
138};
140const styleSelector = (pass, fail) => {
141 if (fail === true)
142 return 'br-yellow outline-yellow f-br-yellow bg-yellow-light';
143 if (pass === true) return 'br-green outline-green f-br-green';
144 return 'br-gray-50 f-br-blue outline-blue';
145};
147export default advancedInput;