UNPKG

4.05 kBJavaScriptView Raw
1import { h, Component } from 'preact'
2const noOp = val => val
3
4class Input extends Component {
5 constructor (props) {
6 super(props)
7 if (props.getSetter) {
8 this.setter = props.getSetter(props.name)
9 }
10 this.state = {
11 hasChanged: false,
12 valid: this.isValid(props.value)
13 }
14 }
15
16 isValid (val) {
17 if (!this.props.test) {
18 return true
19 }
20 return this.props.test(val)
21 }
22
23 componentDidMount () {
24 const { value } = this.props
25 if (value) {
26 this.updateValue(value)
27 } else {
28 const result = this.isValid(value)
29 this.setState({valid: result})
30 this.setter && this.setter({validity: result})
31 }
32 }
33
34 updateValue (val) {
35 const { type, clean, test } = this.props
36 if (type === 'number' && val && typeof val === 'string') {
37 val = Number(val)
38 }
39 if (clean) {
40 val = clean(val)
41 }
42 const update = {
43 value: val
44 }
45 if (test) {
46 const result = this.isValid(val)
47 this.setState({valid: result})
48 update.validity = result
49 }
50 if (this.setter) {
51 this.setter(update)
52 }
53 }
54
55 render ({
56 name,
57 autoFocus = false,
58 label,
59 subLabel,
60 helpText,
61 value,
62 containerClasses = 'mv2',
63 onFocus = noOp,
64 placeholder,
65 disabled = false,
66 className = 'pa2 input-reset br2 bg-transparent hover-bg w-100 ba',
67 getSetter = null,
68 clean = noOp,
69 test = null,
70 min,
71 max,
72 inputmode,
73 pattern,
74 type = 'text'},
75 {
76 valid,
77 hasChanged
78 }) {
79 const isCheckbox = type === 'checkbox'
80 const isTextarea = type === 'textarea'
81
82 if (isCheckbox) {
83 className = 'mr2'
84 }
85
86 if (type === 'number' && !inputmode) {
87 inputmode = 'numeric'
88 }
89
90 const onInput = e => {
91 if (!this.state.hasChanged) {
92 this.setState({hasChanged: true})
93 }
94 this.updateValue(e.target.value)
95 }
96
97 const colorClasses = (hasChanged && !valid) ? 'b--red' : 'b--black-40'
98 const inputClasses = className + ' ' + colorClasses
99
100 return (
101 h('div', {
102 key: name,
103 className: containerClasses
104 }, [
105 (label || subLabel) && !isCheckbox && (
106 h('label', {
107 className: 'db fw9 lh-copy f6',
108 htmlFor: name
109 }, [
110 label,
111 ' ',
112 subLabel && h('span', { className: 'f6 fw5' }, [subLabel])
113 ])
114 ),
115 !isTextarea && !isCheckbox && (
116 h('input', {
117 className: inputClasses,
118 autoFocus,
119 name,
120 type,
121 placeholder,
122 onFocus,
123 onInput,
124 value,
125 disabled,
126 id: name,
127 min,
128 max,
129 inputmode,
130 pattern,
131 'data-e2e': `${name}Input`
132 })
133 ),
134 isTextarea && (
135 h('textarea', {
136 className: inputClasses,
137 autoFocus,
138 name,
139 placeholder,
140 onFocus,
141 onInput,
142 value,
143 disabled,
144 id: name,
145 'data-e2e': `${name}Input`
146 }, [placeholder])
147 ),
148 type === 'checkbox' && (
149 h('div', {className: 'flex items-center'}, [
150 h('input', {
151 className: inputClasses,
152 autoFocus,
153 name,
154 type: 'checkbox',
155 onFocus,
156 onChange: e => {
157 this.updateValue(e.target.checked)
158 },
159 value,
160 disabled,
161 id: name,
162 'data-e2e': `${name}Input`
163 }),
164 h('label', {
165 className: 'fw6 lh-copy f6',
166 htmlFor: name
167 }, [
168 label,
169 ' ',
170 subLabel && h('span', {className: 'f6 fw5'}, [subLabel])
171 ])
172 ])
173 ),
174 helpText && h('span', {className: 'f6 fw5 lh-copy'}, [helpText])
175 ])
176 )
177 }
178}
179
180export default Input