Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Change Log

## 2.1.2

* Add htmlFor/id attribute to labels associating them to inputs

## 2.1.1

* Increase contrast in disabled mini button text
Expand Down
2 changes: 2 additions & 0 deletions src/components/AutocompleteInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ export default class AutocompleteInput extends Component {
asText,
embedded,
readOnly,
id,
} = this.props;

const {
Expand All @@ -492,6 +493,7 @@ export default class AutocompleteInput extends Component {
readOnly={readOnly}
value={getDisplayName(value)}
embedded={embedded}
id={id}
/>
);
}
Expand Down
10 changes: 4 additions & 6 deletions src/components/CheckboxInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,12 @@ export default class CheckboxInput extends Component {
);
}

// FIXME: Don't break jsx-a11y/label-has-associated-control.

/* eslint-disable
jsx-a11y/label-has-associated-control,
jsx-a11y/no-static-element-interactions,
jsx-a11y/no-noninteractive-element-interactions,
jsx-a11y/click-events-have-key-events */
return (
<label className={classes} onClick={onClick}>
<span className={classes} onClick={onClick}>
<input
checked={checked}
data-name={name}
Expand All @@ -134,10 +132,10 @@ export default class CheckboxInput extends Component {
{...remainingProps}
/>
<span />
</label>
</span>
);
/* eslint-enable
jsx-a11y/label-has-associated-control,
jsx-a11y/no-static-element-interactions,
jsx-a11y/no-noninteractive-element-interactions,
jsx-a11y/click-events-have-key-events */
}
Expand Down
22 changes: 20 additions & 2 deletions src/components/CustomCompoundInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import get from 'lodash/get';
import { getPath, pathPropType } from '../helpers/pathHelpers';
import { isInput } from '../helpers/inputHelpers';
import styles from '../../styles/cspace-input/CompoundInput.css';
import labelToLegend from '../helpers/labelToLegend';

const propTypes = {
children: PropTypes.node,
className: PropTypes.string,
defaultChildSubpath: pathPropType,
id: PropTypes.string,
label: PropTypes.node,
name: PropTypes.string,
// TODO: Stop using propTypes in isInput. Until then, these unused props need to be declared so
// this component is recognized as an input.
Expand All @@ -29,10 +32,12 @@ const defaultProps = {
children: undefined,
className: undefined,
defaultChildSubpath: undefined,
label: undefined,
name: undefined,
parentPath: undefined,
subpath: undefined,
readOnly: undefined,
id: undefined,
value: {},
};

Expand Down Expand Up @@ -62,6 +67,7 @@ export default class CustomCompoundInput extends Component {
decorateInputs(children) {
const {
readOnly,
id: parentId,
} = this.props;

return React.Children.map(children, (child) => {
Expand All @@ -88,12 +94,19 @@ export default class CustomCompoundInput extends Component {
subpath = defaultChildSubpath;
}

return React.cloneElement(child, {
const overrides = {
readOnly,
subpath,
parentPath: getPath(this.props),
value: getChildValue(value, subpath, name),
});
};

// Propagate id to inputs that don't have one
if (!child.props.id && parentId && name) {
overrides.id = `${parentId}-${name}`;
}

return React.cloneElement(child, overrides);
}

return React.cloneElement(child, {
Expand All @@ -106,6 +119,7 @@ export default class CustomCompoundInput extends Component {
const {
children,
className,
label,
name,
readOnly,
} = this.props;
Expand All @@ -114,11 +128,14 @@ export default class CustomCompoundInput extends Component {
[styles.readOnly]: readOnly,
});

const legend = labelToLegend(label);

return (
<fieldset
className={classes}
data-name={name}
>
{legend}
{this.decorateInputs(children)}
</fieldset>
);
Expand All @@ -127,3 +144,4 @@ export default class CustomCompoundInput extends Component {

CustomCompoundInput.propTypes = propTypes;
CustomCompoundInput.defaultProps = defaultProps;
CustomCompoundInput.useLegend = true;
15 changes: 13 additions & 2 deletions src/components/InputTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@ import PropTypes from 'prop-types';
import InputTableHeader from './InputTableHeader';
import InputTableRow from './InputTableRow';
import styles from '../../styles/cspace-input/InputTable.css';
import labelToLegend from '../helpers/labelToLegend';

const propTypes = {
children: PropTypes.node,
embedded: PropTypes.bool,
id: PropTypes.string,
label: PropTypes.node,
renderLabel: PropTypes.func,
renderAriaLabel: PropTypes.func,
};

const defaultProps = {
children: undefined,
embedded: undefined,
id: undefined,
label: undefined,
renderLabel: undefined,
renderAriaLabel: undefined,
};
Expand All @@ -22,22 +27,28 @@ export default function InputTable(props) {
const {
children,
embedded,
id,
label,
renderLabel,
renderAriaLabel,
} = props;

const legend = labelToLegend(label);

return (
<div className={styles.common}>
<fieldset className={styles.common} id={id}>
{legend}
<InputTableHeader embedded={embedded} renderLabel={renderLabel}>
{children}
</InputTableHeader>

<InputTableRow embedded={embedded} renderAriaLabel={renderAriaLabel}>
{children}
</InputTableRow>
</div>
</fieldset>
);
}

InputTable.propTypes = propTypes;
InputTable.defaultProps = defaultProps;
InputTable.useLegend = true;
10 changes: 7 additions & 3 deletions src/components/Label.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ const propTypes = {
children: PropTypes.node,
readOnly: PropTypes.bool,
required: PropTypes.bool,
htmlFor: PropTypes.string,
id: PropTypes.string,
};

const defaultProps = {
children: undefined,
readOnly: undefined,
required: undefined,
htmlFor: undefined,
id: undefined,
};

/**
Expand All @@ -22,14 +26,14 @@ export default function Label(props) {
children,
readOnly,
required,
htmlFor,
id,
} = props;

const className = (required && !readOnly) ? styles.required : styles.common;

return (
// FIXME: Set the htmlFor prop to associate the labeled control.
// eslint-disable-next-line jsx-a11y/label-has-associated-control
<label className={className}>
<label className={className} htmlFor={htmlFor} id={id}>
{children}
</label>
);
Expand Down
9 changes: 8 additions & 1 deletion src/components/RepeatingInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import { getPath, pathPropType } from '../helpers/pathHelpers';
import miniButtonContainerStyles from '../../styles/cspace-input/MiniButtonContainer.css';
import moveToTopButtonStyles from '../../styles/cspace-input/MoveToTopButton.css';
import styles from '../../styles/cspace-input/RepeatingInput.css';
import labelToLegend from '../helpers/labelToLegend';

const propTypes = {
children: PropTypes.node,
id: PropTypes.string,
name: PropTypes.string,
/* eslint-disable react/no-unused-prop-types */
parentPath: pathPropType,
Expand Down Expand Up @@ -38,6 +40,7 @@ const propTypes = {

const defaultProps = {
children: undefined,
id: undefined,
name: undefined,
parentPath: undefined,
subpath: undefined,
Expand Down Expand Up @@ -77,7 +80,7 @@ const normalizeValue = (value) => {
return normalized;
};

const renderHeader = (label) => label;
const renderHeader = (label) => labelToLegend(label);

export default class RepeatingInput extends Component {
constructor(props) {
Expand Down Expand Up @@ -252,6 +255,7 @@ export default class RepeatingInput extends Component {

const template = React.Children.only(children);
const normalizedValue = normalizeValue(value);
const templateId = template.props.id;

return normalizedValue.map((instanceValue, index, list) => {
const instanceName = `${index}`;
Expand All @@ -264,6 +268,7 @@ export default class RepeatingInput extends Component {
name: instanceName,
parentPath: getPath(this.props),
value: instanceValue,
id: templateId ? `${templateId}-${instanceName}` : undefined,
// The template is expected to accept an onCommit prop.
onCommit: this.handleInstanceCommit,
};
Expand Down Expand Up @@ -347,6 +352,7 @@ export default class RepeatingInput extends Component {
render() {
const {
asText,
id,
name,
readOnly,
} = this.props;
Expand Down Expand Up @@ -387,6 +393,7 @@ export default class RepeatingInput extends Component {
<fieldset
className={className}
data-name={name}
id={id}
>
{isLabelEmbedded ? null : renderHeader(label)}

Expand Down
30 changes: 20 additions & 10 deletions src/components/TabularCompoundInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import InputTableHeader from './InputTableHeader';
import labelable from '../enhancers/labelable';
import repeatable from '../enhancers/repeatable';
import { getPath } from '../helpers/pathHelpers';
import labelToLegend from '../helpers/labelToLegend';

const BaseComponent = repeatable(labelable(CustomCompoundInput));

Expand All @@ -15,6 +16,7 @@ const propTypes = {
// eslint-disable-next-line react/forbid-foreign-prop-types
...BaseComponent.propTypes,
children: PropTypes.node,
label: PropTypes.node,
repeating: PropTypes.bool,
sortableFields: PropTypes.objectOf(PropTypes.bool),
onSortInstances: PropTypes.func,
Expand All @@ -23,6 +25,7 @@ const propTypes = {

const defaultProps = {
children: undefined,
label: undefined,
repeating: undefined,
sortableFields: undefined,
onSortInstances: undefined,
Expand All @@ -49,6 +52,7 @@ export default class TabularCompoundInput extends Component {
render() {
const {
children,
label,
repeating,
renderChildInputLabel,
sortableFields,
Expand All @@ -66,20 +70,26 @@ export default class TabularCompoundInput extends Component {
</InputTableHeader>
);

const legend = labelToLegend(label);

return (
<BaseComponent
// eslint-disable-next-line react/jsx-props-no-spreading
{...remainingProps}
label={tableHeader}
repeating={repeating}
>
<InputTableRow embedded={repeating}>
{children}
</InputTableRow>
</BaseComponent>
<>
{legend}
<BaseComponent
// eslint-disable-next-line react/jsx-props-no-spreading
{...remainingProps}
label={tableHeader}
repeating={repeating}
>
<InputTableRow embedded={repeating}>
{children}
</InputTableRow>
</BaseComponent>
</>
);
}
}

TabularCompoundInput.propTypes = propTypes;
TabularCompoundInput.defaultProps = defaultProps;
TabularCompoundInput.useLegend = true;
Loading
Loading