diff --git a/components/autocomplete/Autocomplete.js b/components/autocomplete/Autocomplete.js
index 099a03378..8143d11ea 100644
--- a/components/autocomplete/Autocomplete.js
+++ b/components/autocomplete/Autocomplete.js
@@ -146,6 +146,10 @@ const factory = (Chip, Input) => {
);
if (event.which === 13) {
+ if (!this.state.query.trim().length && !this.state.active) {
+ events.pauseEvent(event)
+ return
+ }
this.selectOrCreateActiveItem(event);
}
};
diff --git a/components/button/Button.js b/components/button/Button.js
index 90634ea87..192ba848a 100644
--- a/components/button/Button.js
+++ b/components/button/Button.js
@@ -33,6 +33,7 @@ const factory = (ripple, FontIcon) => {
button: PropTypes.string,
flat: PropTypes.string,
floating: PropTypes.string,
+ label: PropTypes.string,
icon: PropTypes.string,
inverse: PropTypes.string,
mini: PropTypes.string,
@@ -122,7 +123,7 @@ const factory = (ripple, FontIcon) => {
return React.createElement(element, props,
icon ? : null,
- label,
+ {label},
children,
);
}
diff --git a/components/button/IconButton.js b/components/button/IconButton.js
index c50496c3d..9f8eb2ab2 100644
--- a/components/button/IconButton.js
+++ b/components/button/IconButton.js
@@ -88,7 +88,7 @@ const factory = (ripple, FontIcon) => {
} = this.props;
const element = href ? 'a' : 'button';
const level = this.getLevel();
- const classes = classnames([theme.toggle], {
+ const classes = classnames(theme.button, [theme.toggle], {
[theme[level]]: neutral,
[theme.inverse]: inverse,
}, className);
diff --git a/components/button/base.d.ts b/components/button/base.d.ts
index bd54431f9..ae05ed4b8 100644
--- a/components/button/base.d.ts
+++ b/components/button/base.d.ts
@@ -18,6 +18,10 @@ export interface ButtonTheme {
* Used when the button is floating for the root element.
*/
floating?: string;
+ /**
+ * For the label inside a button.
+ */
+ label?: string;
/**
* For the icon inside a button.
*/
diff --git a/components/checkbox/Checkbox.js b/components/checkbox/Checkbox.js
index b209fb1a0..ebd6e9be0 100644
--- a/components/checkbox/Checkbox.js
+++ b/components/checkbox/Checkbox.js
@@ -10,6 +10,7 @@ import checkFactory from './Check';
const factory = (Check) => {
class Checkbox extends Component {
+
static propTypes = {
checked: PropTypes.bool,
children: PropTypes.node,
@@ -38,6 +39,11 @@ const factory = (Check) => {
disabled: false,
};
+ constructor(props) {
+ super(props);
+ this._id = uuidv4();
+ }
+
handleToggle = (event) => {
if (event.pageX !== 0 && event.pageY !== 0) this.blur();
if (!this.props.disabled && this.props.onChange) {
@@ -63,24 +69,27 @@ const factory = (Check) => {
const className = classnames(theme.field, {
[theme.disabled]: this.props.disabled,
}, this.props.className);
- const id = `field_${uuidv4()}`;
+ const inputId = `input_${this._id}`;
+ const labelId = `label_${this._id}`;
return (
: null}
{hint ? {hint} : null}
- {error ? {error} : null}
+
{maxLength ? {length}/{maxLength} : null}
+ {error
+ ?
+ {error}
+
+ : null}
+ {description
+ ?
+ {description}
+
+ : null}
{children}
);
diff --git a/components/input/theme.css b/components/input/theme.css
index a39cb8741..a4f3b0f4a 100644
--- a/components/input/theme.css
+++ b/components/input/theme.css
@@ -144,11 +144,20 @@
}
.error,
+.description,
.counter {
- color: var(--input-text-error-color);
font-size: var(--input-label-font-size);
line-height: var(--input-underline-height);
- margin-bottom: calc(-1 * var(--input-underline-height));
+}
+
+.error {
+ color: var(--input-text-error-color);
+ display: block;
+}
+
+.description {
+ color: var(--input-text-label-color);
+ display: block;
}
.counter {
@@ -157,6 +166,10 @@
right: 0;
}
+.withCounter {
+ padding-right: 3.125rem;
+}
+
.disabled > .inputElement {
border-bottom-style: dotted;
color: var(--input-text-disabled-text-color);
diff --git a/components/list/ListDivider.js b/components/list/ListDivider.js
index 8ad53022b..5c4cf5b9f 100644
--- a/components/list/ListDivider.js
+++ b/components/list/ListDivider.js
@@ -3,15 +3,19 @@ import PropTypes from 'prop-types';
import { themr } from 'react-css-themr';
import { LIST } from '../identifiers';
-const ListDivider = ({ inset, theme }) => (
-
-);
+const ListDivider = ({ inset, li, theme }) => {
+ const hr = (
+
+ );
+ return li ? {hr} : hr;
+};
ListDivider.propTypes = {
inset: PropTypes.bool,
+ li: PropTypes.bool,
theme: PropTypes.shape({
divider: PropTypes.string,
inset: PropTypes.string,
@@ -20,6 +24,7 @@ ListDivider.propTypes = {
ListDivider.defaultProps = {
inset: false,
+ li: true,
};
export default themr(LIST)(ListDivider);
diff --git a/components/list/ListItem.js b/components/list/ListItem.js
index 4562dbf5a..b8716d66a 100644
--- a/components/list/ListItem.js
+++ b/components/list/ListItem.js
@@ -113,19 +113,24 @@ const factory = (ripple, ListItemLayout, ListItemContent) => {
} = this.props;
const children = this.groupChildren();
const content = ;
+ const tabIndexProp = onClick && !to ? {
+ tabIndex,
+ 'aria-label': ariaLabel,
+ } : {};
return (
- {to ? {content} : content}
+ {to ? (
+ {content}
+ ) : content}
{children.ignored}
{altText ? {altText} : null}
diff --git a/components/menu/MenuItem.d.ts b/components/menu/MenuItem.d.ts
index 457718443..151e38837 100644
--- a/components/menu/MenuItem.d.ts
+++ b/components/menu/MenuItem.d.ts
@@ -29,6 +29,10 @@ export interface MenuItemTheme {
}
export interface MenuItemProps extends ReactToolbox.Props {
+ /**
+ * Aria-label for the DOM element
+ */
+ ariaLabel?: string;
/**
* The text to include in the menu item. Required.
*/
diff --git a/components/menu/MenuItem.js b/components/menu/MenuItem.js
index 412f78c3f..5d0b562e1 100644
--- a/components/menu/MenuItem.js
+++ b/components/menu/MenuItem.js
@@ -9,6 +9,7 @@ import rippleFactory from '../ripple/Ripple';
const factory = (ripple) => {
class MenuItem extends Component {
static propTypes = {
+ ariaLabel: PropTypes.string,
caption: PropTypes.string,
children: PropTypes.node,
className: PropTypes.string,
@@ -52,6 +53,7 @@ const factory = (ripple) => {
render() {
const {
+ ariaLabel,
caption,
children,
disabled,
@@ -77,6 +79,7 @@ const factory = (ripple) => {
role="menuitem"
tabIndex={disabled ? '-1' : tabIndex}
aria-disabled={disabled}
+ aria-label={ariaLabel}
>
{icon ? : null}
{caption}
diff --git a/components/progress_bar/ProgressBar.d.ts b/components/progress_bar/ProgressBar.d.ts
index 90db36011..daf116fe9 100644
--- a/components/progress_bar/ProgressBar.d.ts
+++ b/components/progress_bar/ProgressBar.d.ts
@@ -47,6 +47,16 @@ export interface ProgressBarProps extends ReactToolbox.Props {
* @default false
*/
disabled?: boolean;
+ /**
+ * Whether or not the progress bar should be hidden from the screen reader.
+ *
+ * Can be used if the caller wishes to provide more context for progress updates than just
+ * the percent. Also useful to work around an issue with IE11 + JAWS reading the aria-valuenow
+ * attribute instead of the aria-valuetext attribute on updates.
+ *
+ * @default false
+ */
+ hiddenFromScreenReader?: boolean
/**
* Maximum value permitted.
* @default 100
diff --git a/components/progress_bar/ProgressBar.js b/components/progress_bar/ProgressBar.js
index 58eb44dfc..fc0520638 100644
--- a/components/progress_bar/ProgressBar.js
+++ b/components/progress_bar/ProgressBar.js
@@ -10,6 +10,7 @@ class ProgressBar extends Component {
buffer: PropTypes.number,
className: PropTypes.string,
disabled: PropTypes.bool,
+ hiddenFromScreenReader: PropTypes.bool,
max: PropTypes.number,
min: PropTypes.number,
mode: PropTypes.oneOf(['determinate', 'indeterminate']),
@@ -36,6 +37,7 @@ class ProgressBar extends Component {
mode: 'indeterminate',
multicolor: false,
type: 'linear',
+ hiddenFromScreenReader: false,
value: 0,
};
@@ -80,7 +82,18 @@ class ProgressBar extends Component {
}
render() {
- const { className, disabled, max, min, mode, multicolor, type, theme, value } = this.props;
+ const {
+ className,
+ disabled,
+ hiddenFromScreenReader,
+ max,
+ min,
+ mode,
+ multicolor,
+ type,
+ theme,
+ value,
+ } = this.props;
const _className = classnames(theme[type], {
[theme.indeterminate]: mode === 'indeterminate',
[theme.multicolor]: multicolor,
@@ -95,6 +108,7 @@ class ProgressBar extends Component {
aria-valuenow={value}
aria-valuemin={min}
aria-valuemax={max}
+ aria-hidden={hiddenFromScreenReader}
className={_className}
>
{type === 'circular' ? this.renderCircular() : this.renderLinear()}
diff --git a/components/radio/RadioButton.js b/components/radio/RadioButton.js
index a2290236e..7e765df97 100644
--- a/components/radio/RadioButton.js
+++ b/components/radio/RadioButton.js
@@ -9,6 +9,7 @@ import radioFactory from './Radio';
const factory = (Radio) => {
class RadioButton extends Component {
+
static propTypes = {
checked: PropTypes.bool,
children: PropTypes.node,
@@ -39,6 +40,11 @@ const factory = (Radio) => {
disabled: false,
};
+ constructor(props) {
+ super(props);
+ this._id = uuidv4();
+ }
+
handleClick = (event) => {
const { checked, disabled, onChange } = this.props;
if (event.pageX !== 0 && event.pageY !== 0) this.blur();
@@ -72,24 +78,27 @@ const factory = (Radio) => {
...others
} = this.props;
const _className = classnames(theme[this.props.disabled ? 'disabled' : 'field'], className);
- const id = `field_${uuidv4()}`;
+ const inputId = `input_${this._id}`;
+ const labelId = `label_${this._id}`;
return (