Skip to content

Commit 9da2319

Browse files
eojthebravedawehner
authored andcommitted
[#691] First pass at adding a generic <Label> component (#708)
* [#691] First pass at adding a generic <Label> component * [#691] Change from unused labelFor to htmlFor property in Label component storybook entry.
1 parent 1b02a97 commit 9da2319

File tree

3 files changed

+103
-0
lines changed

3 files changed

+103
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from 'react';
2+
// eslint-disable-next-line import/no-extraneous-dependencies
3+
import { storiesOf } from '@storybook/react';
4+
// eslint-disable-next-line import/no-extraneous-dependencies
5+
import { boolean, object, text } from '@storybook/addon-knobs/react';
6+
7+
import Label from './Label';
8+
9+
storiesOf('FormElements/Label', module).addWithJSX('Default', () => (
10+
<Label
11+
fieldName="ControlOne"
12+
htmlFor={text('Label: htmlFor', 'test-label-for')}
13+
error={boolean('Label: error', false)}
14+
required={boolean('Label: required', false)}
15+
htmlAttributes={object('Label: htmlAttributes', { 'data-test': 'test' })}
16+
>
17+
{text('Label: label', 'Field label')}
18+
</Label>
19+
));
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { css } from 'emotion';
4+
5+
import colors from '../../Utils/colors';
6+
7+
const styles = {
8+
label: css`
9+
color: ${colors.text};
10+
`,
11+
labelRequired: css`
12+
:after {
13+
content: ' *';
14+
color: ${colors.maximumRed};
15+
}
16+
`,
17+
labelWithError: css`
18+
color: ${colors.maximumRed};
19+
`,
20+
};
21+
22+
/**
23+
* Renders an HTML <label> element.
24+
*
25+
* Example:
26+
*
27+
* @code
28+
* <Label htmlFor="title" required={true}>Article title</Label>
29+
* @endcode
30+
*/
31+
const Label = ({ children, htmlFor, error, required, htmlAttributes }) => {
32+
const classes = [styles.label];
33+
if (required) {
34+
classes.push(styles.labelRequired);
35+
}
36+
if (error) {
37+
classes.push(styles.labelWithError);
38+
}
39+
40+
return (
41+
<label
42+
htmlFor={htmlFor}
43+
className={css`
44+
${classes}
45+
`}
46+
{...htmlAttributes}
47+
>
48+
{children}
49+
</label>
50+
);
51+
};
52+
53+
Label.propTypes = {
54+
/** Content contained within the label element. */
55+
children: PropTypes.oneOfType([
56+
PropTypes.arrayOf(PropTypes.node),
57+
PropTypes.node,
58+
]).isRequired,
59+
60+
/** true if the label relates to an element with an error. */
61+
error: PropTypes.bool,
62+
63+
/** Any additional HTML properties to add to the label element. */
64+
htmlAttributes: PropTypes.objectOf([
65+
PropTypes.string,
66+
PropTypes.number,
67+
PropTypes.bool,
68+
]),
69+
70+
/** Content of the html "for" attribute to use for this label. */
71+
htmlFor: PropTypes.string.isRequired,
72+
73+
/** True if this label relates to an element that is required. */
74+
required: PropTypes.bool,
75+
};
76+
77+
Label.defaultProps = {
78+
error: false,
79+
htmlAttributes: {},
80+
required: false,
81+
};
82+
83+
export default Label;

packages/components/src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export { default as AdminUIButton } from './Components/Button/Button';
22
export { default as colors } from './Utils/colors';
3+
export { default as Label } from './Components/FormElements/Label';
34
export { default as typography } from './Utils/typography';

0 commit comments

Comments
 (0)