Skip to content

Commit

Permalink
Ability to trigger change event for SelectionControl on enter key (#949)
Browse files Browse the repository at this point in the history
  • Loading branch information
gamtiq authored Sep 14, 2020
1 parent dad3d6c commit 9e75bb6
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 31 deletions.
5 changes: 5 additions & 0 deletions src/js/SelectionControls/Checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ export default class Checkbox extends PureComponent {
*/
inline: PropTypes.bool,

/**
* Whether the `change` event should be triggered for `Checkbox` on pressing of `Enter` key.
*/
changeOnEnter: PropTypes.bool,

/**
* The icon to display when the checkbox is checked.
*/
Expand Down
5 changes: 5 additions & 0 deletions src/js/SelectionControls/Radio.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ export default class Radio extends PureComponent {
*/
inline: PropTypes.bool,

/**
* Whether the `change` event should be triggered for `Radio` on pressing of `Enter` key.
*/
changeOnEnter: PropTypes.bool,

/**
* The icon to display when the radio is checked/selected.
*/
Expand Down
1 change: 1 addition & 0 deletions src/js/SelectionControls/SelectionControl.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface BaseSelectionControlProps extends ControlProps {
checked?: boolean;
defaultChecked?: boolean;
inline?: boolean;
changeOnEnter?: boolean;
'aria-label'?: string;
'aria-labelledby'?: IdPropType;
className?: ClassNameType;
Expand Down
16 changes: 11 additions & 5 deletions src/js/SelectionControls/SelectionControl.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import cn from 'classnames';
import deprecated from 'react-prop-types/lib/deprecated';
import isRequiredForA11y from 'react-prop-types/lib/isRequiredForA11y';

import { SPACE } from '../constants/keyCodes';
import { ENTER, SPACE } from '../constants/keyCodes';
import getField from '../utils/getField';
import themeColors from '../utils/themeColors';
import oneRequiredForA11y from '../utils/PropTypes/oneRequiredForA11y';
Expand Down Expand Up @@ -153,7 +153,7 @@ export default class SelectionControl extends PureComponent {
]))),

/**
* Boolean if the `Radio` is disabled.
* Boolean if the `SelectionControl` is disabled.
*/
disabled: PropTypes.bool,

Expand Down Expand Up @@ -209,6 +209,11 @@ export default class SelectionControl extends PureComponent {
*/
inline: PropTypes.bool,

/**
* Whether the `change` event should be triggered for `SelectionControl` on pressing of `Enter` key.
*/
changeOnEnter: PropTypes.bool,

/**
* The icon to use for a checked `checkbox` selection control.
*/
Expand Down Expand Up @@ -343,12 +348,13 @@ export default class SelectionControl extends PureComponent {
};

_handleKeyDown = (e) => {
if (this.props.onKeyDown) {
this.props.onKeyDown(e);
const { props } = this;
if (props.onKeyDown) {
props.onKeyDown(e);
}

const key = e.which || e.keyCode;
if (key === SPACE) {
if (key === SPACE || (key === ENTER && props.changeOnEnter)) {
this._input.click();
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/js/SelectionControls/Switch.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ export default class Switch extends PureComponent {
*/
checked: controlled(PropTypes.bool, 'onChange', 'defaultChecked'),

/**
* Whether the `change` event should be triggered for `Switch` on pressing of `Enter` key.
*/
changeOnEnter: PropTypes.bool,

defaultToggled: deprecated(PropTypes.bool, 'Use the `defaultChecked` prop instead'),
toggled: deprecated(PropTypes.bool, 'Use the `checked` prop instead'),
};
Expand Down
60 changes: 34 additions & 26 deletions src/js/SelectionControls/__tests__/SelectionControl.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import AccessibleFakeInkedButton from '../../Helpers/AccessibleFakeInkedButton';
import SelectionControl from '../SelectionControl';
import SwitchTrack from '../SwitchTrack';
import SwitchThumb from '../SwitchThumb';
import { SPACE } from '../../constants/keyCodes';
import { ENTER, SPACE } from '../../constants/keyCodes';

jest.mock('../../Inks/InkContainer'); // can't calc left warning

Expand All @@ -19,6 +19,35 @@ const PROPS = {
label: 'Label',
};

function checkKeyHandling(props, keyCode) {
const onChange = jest.fn();
const control = mount(<SelectionControl {...props} onChange={onChange} />);

// While testing, the input.click() doesn't do anything, so mock it in here
let input = control.find('input').instance();
input.click = () => onChange();

let toggle = control.find(AccessibleFakeInkedButton);
toggle.simulate('keyDown', { which: keyCode, keyCode });

expect(onChange.mock.calls.length).toBe(1);

control.setProps({ type: 'radio' });
input = control.find('input').instance();
input.click = () => onChange();
toggle = control.find(AccessibleFakeInkedButton);
toggle.simulate('keyDown', { which: keyCode, keyCode });
expect(onChange.mock.calls.length).toBe(2);

control.setProps({ type: 'switch' });
input = control.find('input').instance();
input.click = () => onChange();

toggle = control.find(SwitchThumb);
toggle.simulate('keyDown', { which: keyCode, keyCode });
expect(onChange.mock.calls.length).toBe(3);
}

describe('SelectionControl', () => {
it('should correctly apply styles and className', () => {
const props = {
Expand Down Expand Up @@ -91,32 +120,11 @@ describe('SelectionControl', () => {
});

it('should correctly trigger the change event when the spacebar key is pressed while focusing the toggle by clicking the input', () => {
const onChange = jest.fn();
const control = mount(<SelectionControl {...PROPS} onChange={onChange} />);

// While testing, the input.click() doesn't do anything, so mock it in here
let input = control.find('input').instance();
input.click = () => onChange();

let toggle = control.find(AccessibleFakeInkedButton);
toggle.simulate('keyDown', { which: SPACE, keyCode: SPACE });

expect(onChange.mock.calls.length).toBe(1);

control.setProps({ type: 'radio' });
input = control.find('input').instance();
input.click = () => onChange();
toggle = control.find(AccessibleFakeInkedButton);
toggle.simulate('keyDown', { which: SPACE, keyCode: SPACE });
expect(onChange.mock.calls.length).toBe(2);

control.setProps({ type: 'switch' });
input = control.find('input').instance();
input.click = () => onChange();
checkKeyHandling(PROPS, SPACE);
});

toggle = control.find(SwitchThumb);
toggle.simulate('keyDown', { which: SPACE, keyCode: SPACE });
expect(onChange.mock.calls.length).toBe(3);
it('should correctly trigger the change event when the enter key is pressed while focusing the toggle by clicking the input', () => {
checkKeyHandling({ ...PROPS, changeOnEnter: true }, ENTER);
});

it('should call the onChange prop with the correct values', () => {
Expand Down

0 comments on commit 9e75bb6

Please sign in to comment.