Skip to content

Commit

Permalink
feat(react): allow toast auto-focus to be disabled (#143)
Browse files Browse the repository at this point in the history
  • Loading branch information
scurker authored Dec 21, 2020
1 parent 5222427 commit bb6efa4
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 5 deletions.
4 changes: 4 additions & 0 deletions docs/patterns/components/Toast/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ export default class Demo extends Component {
type: 'boolean',
description: 'whether or not to show the toast'
},
focus: {
type: 'boolean',
description: 'whether or not to focus the toast'
},
type: {
type: 'string',
required: true,
Expand Down
28 changes: 28 additions & 0 deletions packages/react/__tests__/src/components/Toast/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ const defaultProps = {
show: false
};

beforeEach(() => {
document.activeElement.blur();
});

test('handles initial show prop on mount', done => {
const wrapper = mount(
<Toast {...defaultProps} show={true}>
Expand Down Expand Up @@ -162,6 +166,30 @@ test('clicking the dismiss button properly dismisses toast', done => {
}, 10);
});

test('toast should be focused by default', done => {
const wrapper = mount(
<Toast {...defaultProps} show={true}>
{'hi'}
</Toast>
);
setTimeout(() => {
expect(wrapper.getDOMNode()).toBe(document.activeElement);
done();
}, 10);
});

test('toast should not be focused with falsey focus prop', done => {
const wrapper = mount(
<Toast {...defaultProps} show={true} focus={false}>
{'hi'}
</Toast>
);
setTimeout(() => {
expect(document.body).toBe(document.activeElement);
done();
}, 10);
});

test('should return no axe violations', async () => {
const toast = mount(
<Toast {...defaultProps} show={true}>
Expand Down
31 changes: 26 additions & 5 deletions packages/react/src/components/Toast/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface ToastProps {
onDismiss: () => void;
dismissText?: string;
toastRef: React.Ref<HTMLDivElement>;
focus?: boolean;
show?: boolean;
}

Expand All @@ -26,6 +27,7 @@ export default class Toast extends React.Component<ToastProps, ToastState> {
dismissText: 'Dismiss',
onDismiss: () => {},
toastRef: () => {},
focus: true,
show: false
};

Expand All @@ -43,6 +45,8 @@ export default class Toast extends React.Component<ToastProps, ToastState> {
PropTypes.func,
PropTypes.shape({ current: PropTypes.any })
]),
// whether or not to focus the toast
focus: PropTypes.bool,
// whether or not to show the toast
show: PropTypes.bool
};
Expand Down Expand Up @@ -88,21 +92,38 @@ export default class Toast extends React.Component<ToastProps, ToastState> {

render() {
const { animationClass } = this.state;
const { type, children, dismissText, toastRef, show } = this.props;
const {
type,
children,
dismissText,
toastRef,
focus,
show,
...otherProps
} = this.props;
const scrim =
type === 'action-needed' && show ? (
<div className="Scrim--light Scrim--show Scrim--fade-in" />
) : null;

const defaultProps: React.HTMLAttributes<HTMLDivElement> = {
tabIndex: -1,
className: `Toast Toast--${typeMap[type].className} ${animationClass}`
};

if (!focus) {
defaultProps.role = 'alert';
}

return (
<React.Fragment>
<div
tabIndex={-1}
className={`Toast Toast--${typeMap[type].className} ${animationClass}`}
ref={el => {
this.el = el;
setRef(toastRef, el);
}}
{...defaultProps}
{...otherProps}
>
<div className="Toast__message">
<Icon type={typeMap[type].icon} />
Expand Down Expand Up @@ -152,7 +173,7 @@ export default class Toast extends React.Component<ToastProps, ToastState> {
}

showToast() {
const { type } = this.props;
const { type, focus } = this.props;

this.setState(
{
Expand All @@ -166,7 +187,7 @@ export default class Toast extends React.Component<ToastProps, ToastState> {
isolator.activate();
}

if (this.el) {
if (this.el && !!focus) {
// focus the toast
this.el.focus();
}
Expand Down

0 comments on commit bb6efa4

Please sign in to comment.