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