Skip to content
Open
Show file tree
Hide file tree
Changes from all 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