Skip to content

Commit 5e781bc

Browse files
authored
feat: Add TextField component (#143)
feat: Add TextField component
2 parents d21f347 + 64761d1 commit 5e781bc

File tree

7 files changed

+1083
-1
lines changed

7 files changed

+1083
-1
lines changed
Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
import {
4+
TextField as MuiTextField,
5+
makeStyles
6+
} from "@material-ui/core";
7+
import { refType } from "@material-ui/utils";
8+
9+
// Styles for the base input component
10+
const useInputStyles = makeStyles((theme) => ({
11+
root: {
12+
"position": "relative",
13+
"borderRadius": theme.shape.borderRadius,
14+
"&:hover $notchedOutline": {
15+
borderColor: theme.palette.colors.black40
16+
},
17+
// Reset on touch devices, it doesn't add specificity
18+
"@media (hover: none)": {
19+
"&:hover $notchedOutline": {
20+
borderColor: theme.palette.colors.black20
21+
}
22+
},
23+
"&$focused $notchedOutline": {
24+
borderColor: theme.palette.colors.reactionBlue400,
25+
borderWidth: 2
26+
},
27+
"&$error $notchedOutline": {
28+
borderColor: theme.palette.error.main
29+
},
30+
"&$disabled $notchedOutline": {
31+
borderColor: theme.palette.action.disabled
32+
},
33+
"&$disabled $input": {
34+
backgroundColor: theme.palette.colors.black10
35+
}
36+
},
37+
/* Styles applied to the root element if the component is focused. */
38+
focused: {},
39+
/* Styles applied to the root element if `error={true}`. */
40+
error: {},
41+
/* Styles applied to the root element if `disabled={true}`. */
42+
disabled: {},
43+
/* Styles applied to the `input` element if `margin="dense"`. */
44+
marginDense: {},
45+
/* Styles applied to the root element if `startAdornment` is provided. */
46+
multiline: {
47+
"padding": 0,
48+
"backgroundColor": theme.palette.colors.black02,
49+
"&$marginDense": {
50+
padding: 0
51+
}
52+
},
53+
/* Styles applied to the `NotchedOutline` element. */
54+
notchedOutline: {
55+
borderColor: theme.palette.colors.black20,
56+
padding: "0"
57+
58+
},
59+
input: {
60+
backgroundColor: theme.palette.colors.black02,
61+
padding: "11.5px 6px",
62+
...theme.typography.body2
63+
}
64+
}));
65+
66+
// Styles for the label above the field
67+
const useInputLabelStyles = makeStyles((theme) => ({
68+
root: {
69+
marginBottom: theme.spacing(1),
70+
...theme.typography.h5
71+
},
72+
formControl: {
73+
position: "static",
74+
left: 0,
75+
top: 0,
76+
transform: "none"
77+
},
78+
shrink: {
79+
transform: "none",
80+
transformOrigin: "top left"
81+
},
82+
outlined: {
83+
"transform": "none",
84+
"&$shrink": {
85+
transform: "none"
86+
}
87+
}
88+
}));
89+
90+
// Styles for the helper text below the field
91+
const useFormHelperTextStyles = makeStyles((theme) => ({
92+
root: {
93+
...theme.typography.body2,
94+
color: theme.palette.colors.black55
95+
},
96+
contained: {
97+
marginLeft: 0,
98+
marginRight: 0
99+
}
100+
}));
101+
102+
/**
103+
* @name TextField
104+
* @param {Object} props Component props
105+
* @returns {React.Component} returns a React component
106+
*/
107+
const TextField = React.forwardRef(function TextField(props, ref) {
108+
const inputClasses = useInputStyles();
109+
const inputLabelClasses = useInputLabelStyles();
110+
const formHelperTextClasses = useFormHelperTextStyles();
111+
112+
return (
113+
<MuiTextField
114+
FormHelperTextProps={{
115+
classes: formHelperTextClasses
116+
}}
117+
InputProps={{
118+
classes: inputClasses,
119+
disableUnderline: true,
120+
notched: false,
121+
dense: true
122+
}}
123+
InputLabelProps={{
124+
shrink: true,
125+
classes: inputLabelClasses
126+
}}
127+
fullWidth
128+
variant="outlined"
129+
{...props}
130+
ref={ref}
131+
/>
132+
);
133+
});
134+
135+
/* eslint-disable react/boolean-prop-naming */
136+
/**
137+
*
138+
* The following prop-type definitions are copied from the Material UI TextField component to aide in documentation generation.
139+
* Source: [@material-ui/core/TextField](https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/TextField/TextField.js)
140+
*/
141+
TextField.propTypes = {
142+
/**
143+
* This prop helps users to fill forms faster, especially on mobile devices.
144+
* The name can be confusing, as it's more like an autofill.
145+
* You can learn more about it [following the specification](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill).
146+
*/
147+
FormHelperTextProps: PropTypes.object,
148+
/**
149+
* If `true`, the `input` element will be focused during the first mount.
150+
*/
151+
InputLabelProps: PropTypes.object,
152+
/**
153+
* @ignore
154+
*/
155+
InputProps: PropTypes.object,
156+
/**
157+
* Override or extend the styles applied to the component.
158+
* See [CSS API](#css) below for more details.
159+
*/
160+
SelectProps: PropTypes.object,
161+
/**
162+
* @ignore
163+
*/
164+
autoComplete: PropTypes.string,
165+
/**
166+
* The color of the component. It supports those theme colors that make sense for this component.
167+
*/
168+
autoFocus: PropTypes.bool,
169+
/**
170+
* The default value of the `input` element.
171+
*/
172+
children: PropTypes.node,
173+
/**
174+
* If `true`, the `input` element will be disabled.
175+
*/
176+
className: PropTypes.string,
177+
/**
178+
* If `true`, the label will be displayed in an error state.
179+
*/
180+
classes: PropTypes.object.isRequired,
181+
/**
182+
* Props applied to the [`FormHelperText`](/api/form-helper-text/) element.
183+
*/
184+
color: PropTypes.oneOf(["primary", "secondary"]),
185+
/**
186+
* If `true`, the input will take up the full width of its container.
187+
*/
188+
defaultValue: PropTypes.any,
189+
/**
190+
* The helper text content.
191+
*/
192+
disabled: PropTypes.bool,
193+
/**
194+
* @ignore
195+
*/
196+
error: PropTypes.bool,
197+
/**
198+
* The id of the `input` element.
199+
* Use this prop to make `label` and `helperText` accessible for screen readers.
200+
*/
201+
fullWidth: PropTypes.bool,
202+
/**
203+
* Props applied to the [`InputLabel`](/api/input-label/) element.
204+
*/
205+
helperText: PropTypes.node,
206+
/**
207+
* Props applied to the Input element.
208+
* It will be a [`FilledInput`](/api/filled-input/),
209+
* [`OutlinedInput`](/api/outlined-input/) or [`Input`](/api/input/)
210+
* component depending on the `variant` prop value.
211+
*/
212+
hiddenLabel: PropTypes.bool,
213+
/**
214+
* [Attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#Attributes) applied to the `input` element.
215+
*/
216+
id: PropTypes.string,
217+
/**
218+
* Pass a ref to the `input` element.
219+
*/
220+
inputProps: PropTypes.object,
221+
/**
222+
* The label content.
223+
*/
224+
inputRef: refType,
225+
/**
226+
* If `dense` or `normal`, will adjust vertical spacing of this and contained components.
227+
*/
228+
label: PropTypes.node,
229+
/**
230+
* If `true`, a textarea element will be rendered instead of an input.
231+
*/
232+
margin: PropTypes.oneOf(["none", "dense", "normal"]),
233+
/**
234+
* Name attribute of the `input` element.
235+
*/
236+
multiline: PropTypes.bool,
237+
/**
238+
* @ignore
239+
*/
240+
name: PropTypes.string,
241+
/**
242+
* Callback fired when the value is changed.
243+
*
244+
* @param {object} event The event source of the callback.
245+
* You can pull out the new value by accessing `event.target.value` (string).
246+
*/
247+
onBlur: PropTypes.func,
248+
/**
249+
* @ignore
250+
*/
251+
onChange: PropTypes.func,
252+
/**
253+
* The short hint displayed in the input before the user enters a value.
254+
*/
255+
onFocus: PropTypes.func,
256+
/**
257+
* If `true`, the label is displayed as required and the `input` element` will be required.
258+
*/
259+
placeholder: PropTypes.string,
260+
/**
261+
* Number of rows to display when multiline option is set to true.
262+
*/
263+
required: PropTypes.bool,
264+
/**
265+
* Maximum number of rows to display when multiline option is set to true.
266+
*/
267+
rows: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
268+
/**
269+
* Render a [`Select`](/api/select/) element while passing the Input element to `Select` as `input` parameter.
270+
* If this option is set you must pass the options of the select as children.
271+
*/
272+
rowsMax: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
273+
/**
274+
* Props applied to the [`Select`](/api/select/) element.
275+
*/
276+
select: PropTypes.bool,
277+
/**
278+
* The size of the text field.
279+
*/
280+
size: PropTypes.oneOf(["small", "medium"]),
281+
/**
282+
* Type of the `input` element. It should be [a valid HTML5 input type](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#Form_%3Cinput%3E_types).
283+
*/
284+
type: PropTypes.string,
285+
/**
286+
* The value of the `input` element, required for a controlled component.
287+
*/
288+
value: PropTypes.any,
289+
/**
290+
* The variant to use.
291+
*/
292+
variant: PropTypes.oneOf(["standard", "outlined", "filled"])
293+
};
294+
/* eslint-enable react/boolean-prop-naming */
295+
296+
export default TextField;

0 commit comments

Comments
 (0)