Skip to content

Commit 4052750

Browse files
committed
Create FileInputField component (#219)
1 parent a439850 commit 4052750

File tree

12 files changed

+665
-10
lines changed

12 files changed

+665
-10
lines changed
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import PropTypes from 'prop-types';
2+
import React from 'react';
3+
import getRootValidationStateClassName from '../../../helpers/getRootValidationStateClassName';
4+
import { withProviderContext } from '../../../provider';
5+
import transferProps from '../../../utils/transferProps';
6+
import withForwardedRef from '../withForwardedRef';
7+
import styles from './FileInputField.scss';
8+
9+
export const FileInputField = ({
10+
changeHandler,
11+
disabled,
12+
forwardedRef,
13+
fullWidth,
14+
helpText,
15+
id,
16+
inFormLayout,
17+
isLabelVisible,
18+
label,
19+
layout,
20+
required,
21+
validationState,
22+
validationText,
23+
...restProps
24+
}) => (
25+
<label
26+
className={[
27+
styles.root,
28+
fullWidth ? styles.isRootFullWidth : '',
29+
inFormLayout ? styles.isRootInFormLayout : '',
30+
layout === 'horizontal' ? styles.rootLayoutHorizontal : styles.rootLayoutVertical,
31+
disabled ? styles.isRootDisabled : '',
32+
required ? styles.isRootRequired : '',
33+
getRootValidationStateClassName(validationState, styles),
34+
].join(' ')}
35+
htmlFor={id}
36+
id={`${id}__label`}
37+
>
38+
<div
39+
className={[
40+
styles.label,
41+
isLabelVisible ? '' : styles.isLabelHidden,
42+
].join(' ')}
43+
id={`${id}__labelText`}
44+
>
45+
{label}
46+
</div>
47+
<div className={styles.field}>
48+
<div className={styles.inputContainer}>
49+
<input
50+
{...transferProps(restProps)}
51+
className={styles.input}
52+
disabled={disabled}
53+
id={id}
54+
onChange={changeHandler}
55+
ref={forwardedRef}
56+
required={required}
57+
type="file"
58+
/>
59+
</div>
60+
{helpText && (
61+
<div
62+
className={styles.helpText}
63+
id={`${id}__helpText`}
64+
>
65+
{helpText}
66+
</div>
67+
)}
68+
{validationText && (
69+
<div
70+
className={styles.validationText}
71+
id={`${id}__validationText`}
72+
>
73+
{validationText}
74+
</div>
75+
)}
76+
</div>
77+
</label>
78+
);
79+
80+
FileInputField.defaultProps = {
81+
changeHandler: null,
82+
disabled: false,
83+
forwardedRef: undefined,
84+
fullWidth: false,
85+
helpText: null,
86+
inFormLayout: false,
87+
isLabelVisible: true,
88+
layout: 'vertical',
89+
required: false,
90+
validationState: null,
91+
validationText: null,
92+
};
93+
94+
FileInputField.propTypes = {
95+
/**
96+
* Function to call when the input has changed.
97+
*/
98+
changeHandler: PropTypes.func,
99+
/**
100+
* If `true`, the input will be disabled.
101+
*/
102+
disabled: PropTypes.bool,
103+
/**
104+
* Reference forwarded to the `input` element.
105+
*/
106+
forwardedRef: PropTypes.oneOfType([
107+
PropTypes.func,
108+
// eslint-disable-next-line react/forbid-prop-types
109+
PropTypes.shape({ current: PropTypes.any }),
110+
]),
111+
/**
112+
* If `true`, the field will span the full width of its parent.
113+
*/
114+
fullWidth: PropTypes.bool,
115+
/**
116+
* Optional help text.
117+
*/
118+
helpText: PropTypes.node,
119+
/**
120+
* ID of the input HTML element. It also serves as a prefix for important inner elements:
121+
* `<ID>__label`, `<ID>__labelText`, `<ID>__helpText`, and `<ID>__validationText`.
122+
*/
123+
id: PropTypes.string.isRequired,
124+
/**
125+
* Treat the field differently when it's inside a FormLayout. Do not set manually!
126+
*/
127+
inFormLayout: PropTypes.bool,
128+
/**
129+
* If `false`, the label will be visually hidden (but remains accessible by assistive
130+
* technologies).
131+
*/
132+
isLabelVisible: PropTypes.bool,
133+
/**
134+
* Text field label.
135+
*/
136+
label: PropTypes.string.isRequired,
137+
/**
138+
* Layout of the field.
139+
*/
140+
layout: PropTypes.oneOf(['horizontal', 'vertical']),
141+
/**
142+
* If `true`, the input will be required.
143+
*/
144+
required: PropTypes.bool,
145+
/**
146+
* Alter the field to provide feedback based on validation result.
147+
*/
148+
validationState: PropTypes.oneOf(['invalid', 'valid', 'warning']),
149+
/**
150+
* Validation message to be displayed.
151+
*/
152+
validationText: PropTypes.node,
153+
};
154+
155+
export const FileInputFieldWithContext = withForwardedRef(withProviderContext(FileInputField, 'FileInputField'));
156+
157+
export default FileInputFieldWithContext;
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
@use '../../../styles/tools/form-fields/box-field-elements';
2+
@use '../../../styles/tools/form-fields/box-field-layout';
3+
@use '../../../styles/tools/form-fields/foundation';
4+
@use '../../../styles/tools/form-fields/relationships';
5+
@use '../../../styles/tools/form-fields/variants';
6+
@use '../../../styles/tools/accessibility';
7+
8+
// Foundation
9+
.root {
10+
@include foundation.root();
11+
@include relationships.horizontal-neighbor();
12+
}
13+
14+
.label {
15+
@include foundation.label();
16+
}
17+
18+
.inputContainer {
19+
@include box-field-elements.input-container();
20+
}
21+
22+
.input {
23+
@include accessibility.focus-ring();
24+
}
25+
26+
.helpText,
27+
.validationText {
28+
@include foundation.help-text();
29+
}
30+
31+
.isRootRequired .label {
32+
@include foundation.label-required();
33+
}
34+
35+
// States
36+
.isRootStateInvalid {
37+
@include variants.validation(invalid);
38+
}
39+
40+
.isRootStateValid {
41+
@include variants.validation(valid);
42+
}
43+
44+
.isRootStateWarning {
45+
@include variants.validation(warning);
46+
}
47+
48+
// Invisible label
49+
.isLabelHidden {
50+
@include accessibility.hide-text();
51+
}
52+
53+
// Layouts
54+
.rootLayoutVertical,
55+
.rootLayoutHorizontal {
56+
@include box-field-layout.vertical();
57+
}
58+
59+
.rootLayoutHorizontal {
60+
@include box-field-layout.horizontal();
61+
}
62+
63+
.isRootFullWidth {
64+
@include box-field-layout.full-width();
65+
@include relationships.vertical-neighbor();
66+
}
67+
68+
.isRootInFormLayout {
69+
@include box-field-layout.in-form-layout();
70+
}

0 commit comments

Comments
 (0)