Skip to content
This repository has been archived by the owner on Aug 21, 2023. It is now read-only.

Commit

Permalink
- Adds the ability to select/deselect choice using Enter.
Browse files Browse the repository at this point in the history
- Fixes focus on radiocard
  • Loading branch information
Juan Pablo Lomeli Diaz committed Jul 29, 2020
1 parent 1d1ae67 commit 1497103
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 50 deletions.
2 changes: 1 addition & 1 deletion src/components/Button/Button.jsx
Expand Up @@ -205,7 +205,7 @@ Button.propTypes = {
'link',
]),
/** Sets the size of the button. */
size: PropTypes.oneOf(['sm', 'md', 'lg']),
size: PropTypes.oneOf(['sm', 'md', 'lg', 'xl', 'xs', 'xss']),
/** A special property that... spins the button if `isLoading`. */
spinButtonOnLoading: PropTypes.bool,
/** Applies state styles to the button.
Expand Down
17 changes: 15 additions & 2 deletions src/components/Choice/Choice.Input.jsx
@@ -1,5 +1,6 @@
import React from 'react'
import PropTypes from 'prop-types'
import { key } from '../../constants/Keys'
import InputBackdropV2 from '../Input/Input.BackdropV2'
import Icon from '../Icon'
import { classNames } from '../../utilities/classNames'
Expand Down Expand Up @@ -32,6 +33,15 @@ class ChoiceInput extends React.PureComponent {
event.stopPropagation()
}

handleOnKeyDown = event => {
const isEnter = event.key === key.ENTER

if (isEnter) {
const { id, onEnter, value } = this.props
onEnter(value, !event.target.checked, id)
}
}

handleOnFocus = event => {
this.setState({
isFocused: true,
Expand Down Expand Up @@ -92,7 +102,6 @@ class ChoiceInput extends React.PureComponent {
value,
'data-cy': dataCy,
} = this.props

const { isFocused } = this.state

const componentClassName = classNames(
Expand Down Expand Up @@ -129,6 +138,7 @@ class ChoiceInput extends React.PureComponent {
onBlur={this.handleOnBlur}
onChange={this.handleOnChange}
onFocus={this.handleOnFocus}
onKeyDown={this.handleOnKeyDown}
readOnly={readOnly}
type={type}
value={value}
Expand Down Expand Up @@ -161,6 +171,7 @@ ChoiceInput.defaultProps = {
onBlur: noop,
onChange: noop,
onFocus: noop,
onEnter: noop,
inputRef: noop,
innerRef: noop,
readOnly: false,
Expand All @@ -186,10 +197,12 @@ ChoiceInput.propTypes = {
onBlur: PropTypes.func,
onChange: PropTypes.func,
onFocus: PropTypes.func,
/** Callback when pressing enter whenthe input is focused. */
onEnter: PropTypes.func,
name: PropTypes.string,
readOnly: PropTypes.bool,
state: PropTypes.string,
type: PropTypes.string,
type: PropTypes.oneOf(['checkbox', 'radio']),
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
}

Expand Down
20 changes: 20 additions & 0 deletions src/components/Choice/Choice.jsx
Expand Up @@ -38,6 +38,12 @@ class Choice extends React.PureComponent {
this.props.onChange(value, checked)
}

handleOnEnter = (value, checked) => {
this.setState({ checked })

this.props.onEnter(value, checked)
}

handleOnBlur = event => {
this.props.onBlur(event)
}
Expand All @@ -46,6 +52,16 @@ class Choice extends React.PureComponent {
this.props.onFocus(event)
}

handleOnEnterWithContext = contextProps => {
return (...args) => {
this.handleOnEnter.apply(null, args)

if (contextProps.onEnter) {
contextProps.onEnter.apply(null, args)
}
}
}

handleOnBlurWithContext = contextProps => {
return (...args) => {
this.handleOnBlur.apply(null, args)
Expand Down Expand Up @@ -169,6 +185,7 @@ class Choice extends React.PureComponent {
onBlur: this.handleOnBlurWithContext(contextProps),
onFocus: this.handleOnFocusWithContext(contextProps),
onChange: this.handleOnChangeWithContext(contextProps),
onEnter: this.handleOnEnterWithContext(contextProps),
readOnly,
state,
type,
Expand Down Expand Up @@ -274,6 +291,7 @@ Choice.defaultProps = {
onBlur: noop,
onChange: noop,
onFocus: noop,
onEnter: noop,
inputRef: noop,
innerRef: noop,
isBlock: false,
Expand Down Expand Up @@ -315,6 +333,8 @@ Choice.propTypes = {
onChange: PropTypes.func,
/** Callback when the input is focused. */
onFocus: PropTypes.func,
/** Callback when pressing enter whenthe input is focused. */
onEnter: PropTypes.func,
/** Disable editing of the input. */
readOnly: PropTypes.bool,
/** Stacks the input above the label. */
Expand Down
16 changes: 16 additions & 0 deletions src/components/Choice/Choice.test.js
Expand Up @@ -203,6 +203,22 @@ describe('Events', () => {
expect(spy).toHaveBeenCalledWith('Value', false)
wrapper.unmount()
})

test('onEnter changes value and triggers callback', () => {
const spy = jest.fn()
const wrapper = mount(<Choice onEnter={spy} value="Value" checked />)
const input = wrapper.find('input')

input.simulate('keydown', { key: 'Enter' })

expect(spy).toHaveBeenCalledWith('Value', false)

wrapper.setProps({ checked: false })
input.simulate('keydown', { key: 'Enter' })

expect(spy).toHaveBeenCalledWith('Value', true)
wrapper.unmount()
})
})

describe('States', () => {
Expand Down
10 changes: 10 additions & 0 deletions src/components/Choice/ChoiceInput.test.js
Expand Up @@ -72,6 +72,16 @@ describe('Events', () => {

expect(spy).toHaveBeenCalled()
})

test('Can trigger onEnter callback', () => {
const spy = jest.fn()
const wrapper = mount(<Input onEnter={spy} checked value="Value" />)
const input = wrapper.find('input')

input.simulate('keydown', { key: 'Enter' })

expect(spy).toHaveBeenCalled()
})
})

describe('States', () => {
Expand Down
14 changes: 14 additions & 0 deletions src/components/ChoiceGroup/ChoiceGroup.jsx
Expand Up @@ -63,13 +63,24 @@ class ChoiceGroup extends React.Component {
onChange(selectedValue)
}

handleOnEnter = (value, checked) => {
const { multiSelect, onEnter } = this.props
const selectedValue = multiSelect
? this.getMultiSelectValue(value, checked)
: [value]

this.setState({ selectedValue })
onEnter(selectedValue)
}

getContextProps = () => {
const { onBlur, onFocus, name } = this.props
const { selectedValue } = this.state

return {
onBlur,
onChange: this.handleOnChange,
onEnter: this.handleOnEnter,
onFocus,
name,
selectedValue,
Expand Down Expand Up @@ -109,6 +120,7 @@ class ChoiceGroup extends React.Component {
onBlur,
onChange,
onFocus,
onEnter,
multiSelect,
name,
...rest
Expand Down Expand Up @@ -147,6 +159,7 @@ ChoiceGroup.defaultProps = {
onBlur: noop,
onChange: noop,
onFocus: noop,
onEnter: noop,
multiSelect: true,
}

Expand All @@ -168,6 +181,7 @@ ChoiceGroup.propTypes = {
onChange: PropTypes.func,
/** Callback when an input is focused. */
onFocus: PropTypes.func,
onEnter: PropTypes.func,
/** The default value of input group. */
value: PropTypes.any,
/** Allow multiple choice selection */
Expand Down
16 changes: 16 additions & 0 deletions src/components/ChoiceGroup/ChoiceGroup.test.js
Expand Up @@ -92,6 +92,22 @@ describe('ChoiceGroup', () => {

expect(spy).toHaveBeenCalledWith(['1'])
})

test('Can trigger onEnter callback', () => {
const spy = jest.fn()
const wrapper = mount(
<ChoiceGroup onEnter={spy}>
<Radio value="1" />
<Radio value="2" />
<Radio value="3" />
</ChoiceGroup>
)
const input = wrapper.find('.c-Radio').first().find('input')

input.simulate('keydown', { key: 'Enter' })

expect(spy).toHaveBeenCalledWith(['1'])
})
})

describe('MultiSelect', () => {
Expand Down
25 changes: 19 additions & 6 deletions src/components/RadioCard/RadioCard.css.js
Expand Up @@ -26,13 +26,15 @@ export const config = {
maxWidth: '75px',
width: '100%',
transition: 'box-shadow 200ms linear',
willChange: 'box-shadow',
willChange: 'box-shadow, border',
}

export const RadioCardUI = styled('label')`
align-items: center;
border-radius: ${config.borderRadius}px;
box-shadow: ${config.boxShadow};
border-radius: 4px;
/* box-shadow: ${config.boxShadow}; */
border: 1px solid rgba(0, 0, 0, 0.04);
box-shadow: 0px 5px 8px rgba(99, 116, 134, 0.03), 0px 2px 8px rgba(0, 0, 0, 0.04);
cursor: pointer;
display: flex;
flex-direction: column;
Expand All @@ -42,15 +44,26 @@ export const RadioCardUI = styled('label')`
padding: ${config.padding};
position: relative;
width: ${config.width};
transition: ${config.transition};
transition: all 0.15s;
will-change: ${config.willChange};
&:hover {
box-shadow: ${config.boxShadowHover};
border: 1px solid ${getColor('grey.500')};
box-shadow: 0px 5px 8px rgba(99, 116, 134, 0.03), 0px 2px 8px rgba(0, 0, 0, 0.04);
transform: translateY(-2px)
}
&.is-focused,
&.is-focused.is-checked,
&:focus-within,
&.is-checked:focus-within {
border: 2px solid ${getColor('blue.500')};
border-radius: 7px;
}
&.is-checked {
box-shadow: ${config.boxShadowHover};
border: 1px solid ${getColor('grey.500')};
box-shadow: 0px 5px 8px rgba(99, 116, 134, 0.03), 0px 2px 8px rgba(0, 0, 0, 0.04);
}
`

Expand Down
34 changes: 14 additions & 20 deletions src/components/RadioCard/RadioCard.jsx
Expand Up @@ -11,7 +11,6 @@ import Radio from '../Radio'
import {
RadioCardUI,
IconWrapperUI,
FocusUI,
ContentUI,
HeadingUI,
} from './RadioCard.css'
Expand All @@ -26,28 +25,28 @@ class RadioCard extends React.PureComponent {

this.state = {
id: props.id || uniqueID(),
isFocused: props.isFocused,
}

this.radioCardRef = React.createRef()
}

componentDidMount() {
if (this.props.isFocused && this.inputNode) {
this.inputNode.focus()
}
}

handleOnBlur = event => {
this.setState({
isFocused: false,
})
this.radioCardRef.current.classList.remove('is-focused')
this.props.onBlur(event)
}

handleOnFocus = event => {
this.showFocus()
this.radioCardRef.current.focus()
this.radioCardRef.current.classList.add('is-focused')
this.props.onFocus(event)
}

showFocus = () => {
this.setState({
isFocused: true,
})
}

getContentMarkup = () => {
const { content } = this.props

Expand Down Expand Up @@ -102,25 +101,20 @@ class RadioCard extends React.PureComponent {
)
}

getFocusMarkup = () => {
const { isFocused } = this.state

return isFocused && <FocusUI className="c-RadioCard__focus" />
}

getCardMarkup = contextProps => {
const {
checked,
className,
content,
heading,
icon,
isFocused,
maxWidth,
title,
value,
...rest
} = this.props
const { id, isFocused } = this.state
const { id } = this.state

const isChecked =
(contextProps.selectedValue &&
Expand All @@ -140,6 +134,7 @@ class RadioCard extends React.PureComponent {
className={componentClassName}
title={title}
maxWidth={maxWidth}
ref={this.radioCardRef}
>
<IconWrapperUI
className={classNames(
Expand All @@ -161,7 +156,6 @@ class RadioCard extends React.PureComponent {
onFocus={this.handleOnFocus}
value={value}
/>
{this.getFocusMarkup()}
</RadioCardUI>
)
}
Expand Down

0 comments on commit 1497103

Please sign in to comment.