Fix poll options not being selectable via keyboard (#12538)
* Fix poll options not being selectable via keyboard Fixes #12384 * Improve styling of poll option checkboxes/radio buttons * Use more appropriate ARIA roles for poll options * Allow switching between single and multiple choice from keyboard * Coding style * Avoid using .bind()
This commit is contained in:
		
							parent
							
								
									f1ef777d40
								
							
						
					
					
						commit
						c05ed8a625
					
				| @ -67,9 +67,7 @@ class Poll extends ImmutablePureComponent { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   handleOptionChange = e => { | ||||
|     const { target: { value } } = e; | ||||
| 
 | ||||
|   _toggleOption = value => { | ||||
|     if (this.props.poll.get('multiple')) { | ||||
|       const tmp = { ...this.state.selected }; | ||||
|       if (tmp[value]) { | ||||
| @ -83,8 +81,20 @@ class Poll extends ImmutablePureComponent { | ||||
|       tmp[value] = true; | ||||
|       this.setState({ selected: tmp }); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   handleOptionChange = ({ target: { value } }) => { | ||||
|     this._toggleOption(value); | ||||
|   }; | ||||
| 
 | ||||
|   handleOptionKeyPress = (e) => { | ||||
|     if (e.key === 'Enter' || e.key === ' ') { | ||||
|       this._toggleOption(e.target.getAttribute('data-index')); | ||||
|       e.stopPropagation(); | ||||
|       e.preventDefault(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   handleVote = () => { | ||||
|     if (this.props.disabled) { | ||||
|       return; | ||||
| @ -135,7 +145,17 @@ class Poll extends ImmutablePureComponent { | ||||
|             disabled={disabled} | ||||
|           /> | ||||
| 
 | ||||
|           {!showResults && <span className={classNames('poll__input', { checkbox: poll.get('multiple'), active })} />} | ||||
|           {!showResults && ( | ||||
|             <span | ||||
|               className={classNames('poll__input', { checkbox: poll.get('multiple'), active })} | ||||
|               tabIndex='0' | ||||
|               role={poll.get('multiple') ? 'checkbox' : 'radio'} | ||||
|               onKeyPress={this.handleOptionKeyPress} | ||||
|               aria-checked={active} | ||||
|               aria-label={option.get('title')} | ||||
|               data-index={optionIndex} | ||||
|             /> | ||||
|           )} | ||||
|           {showResults && <span className='poll__number'> | ||||
|             {!!voted && <Icon id='check' className='poll__vote__mark' title={intl.formatMessage(messages.voted)} />} | ||||
|             {Math.round(percent)}% | ||||
|  | ||||
| @ -13,6 +13,8 @@ const messages = defineMessages({ | ||||
|   add_option: { id: 'compose_form.poll.add_option', defaultMessage: 'Add a choice' }, | ||||
|   remove_option: { id: 'compose_form.poll.remove_option', defaultMessage: 'Remove this choice' }, | ||||
|   poll_duration: { id: 'compose_form.poll.duration', defaultMessage: 'Poll duration' }, | ||||
|   switchToMultiple: { id: 'compose_form.poll.switch_to_multiple', defaultMessage: 'Change poll to allow multiple choices' }, | ||||
|   switchToSingle: { id: 'compose_form.poll.switch_to_single', defaultMessage: 'Change poll to allow for a single choice' }, | ||||
|   minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' }, | ||||
|   hours: { id: 'intervals.full.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}}' }, | ||||
|   days: { id: 'intervals.full.days', defaultMessage: '{number, plural, one {# day} other {# days}}' }, | ||||
| @ -50,6 +52,12 @@ class Option extends React.PureComponent { | ||||
|     e.stopPropagation(); | ||||
|   }; | ||||
| 
 | ||||
|   handleCheckboxKeypress = e => { | ||||
|     if (e.key === 'Enter' || e.key === ' ') { | ||||
|       this.handleToggleMultiple(e); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   onSuggestionsClearRequested = () => { | ||||
|     this.props.onClearSuggestions(); | ||||
|   } | ||||
| @ -71,8 +79,11 @@ class Option extends React.PureComponent { | ||||
|           <span | ||||
|             className={classNames('poll__input', { checkbox: isPollMultiple })} | ||||
|             onClick={this.handleToggleMultiple} | ||||
|             onKeyPress={this.handleCheckboxKeypress} | ||||
|             role='button' | ||||
|             tabIndex='0' | ||||
|             title={intl.formatMessage(isPollMultiple ? messages.switchToMultiple : messages.switchToSingle)} | ||||
|             aria-label={intl.formatMessage(isPollMultiple ? messages.switchToMultiple : messages.switchToSingle)} | ||||
|           /> | ||||
| 
 | ||||
|           <AutosuggestInput | ||||
|  | ||||
| @ -91,6 +91,23 @@ | ||||
|       border-color: $valid-value-color; | ||||
|       background: $valid-value-color; | ||||
|     } | ||||
| 
 | ||||
|     &:active, | ||||
|     &:focus, | ||||
|     &:hover { | ||||
|       border-width: 4px; | ||||
|       background: none; | ||||
|     } | ||||
| 
 | ||||
|     &::-moz-focus-inner { | ||||
|       outline: 0 !important; | ||||
|       border: 0; | ||||
|     } | ||||
| 
 | ||||
|     &:focus, | ||||
|     &:active { | ||||
|       outline: 0 !important; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   &__number { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user