diff --git a/react/features/base/toolbox/components/AbstractButton.js b/react/features/base/toolbox/components/AbstractButton.js index ded2269d5..c0af079d9 100644 --- a/react/features/base/toolbox/components/AbstractButton.js +++ b/react/features/base/toolbox/components/AbstractButton.js @@ -230,13 +230,14 @@ export default class AbstractButton extends Component { /** * Helper function to be implemented by subclasses, which must return a - * {@code boolean} value indicating if this button is toggled or not. + * {@code boolean} value indicating if this button is toggled or not or + * undefined if the button is not toggleable. * * @protected - * @returns {boolean} + * @returns {?boolean} */ _isToggled() { - return false; + return undefined; } _onClick: (*) => void; diff --git a/react/features/base/toolbox/components/ToolboxItem.web.js b/react/features/base/toolbox/components/ToolboxItem.web.js index 7fdd225c0..73ff46e76 100644 --- a/react/features/base/toolbox/components/ToolboxItem.web.js +++ b/react/features/base/toolbox/components/ToolboxItem.web.js @@ -12,6 +12,69 @@ import type { Props } from './AbstractToolboxItem'; * Web implementation of {@code AbstractToolboxItem}. */ export default class ToolboxItem extends AbstractToolboxItem { + /** + * Initializes a new {@code ToolboxItem} instance. + * + * @inheritdoc + */ + constructor(props: Props) { + super(props); + + this._onKeyDown = this._onKeyDown.bind(this); + this._onKeyUp = this._onKeyUp.bind(this); + } + + _onKeyDown: (Object) => void; + + /** + * Handles 'Enter' key on the button to trigger onClick for accessibility. + * + * @param {Object} event - The key event. + * @private + * @returns {void} + */ + _onKeyDown(event) { + // If the event coming to the dialog has been subject to preventDefault + // we don't handle it here. + if (event.defaultPrevented) { + return; + } + + if (event.key === 'Enter') { + event.preventDefault(); + event.stopPropagation(); + this.props.onClick(); + } else if (event.key === ' ') { + // Space triggers button onKeyUp but we need to prevent PTT here + event.preventDefault(); + event.stopPropagation(); + } + } + + _onKeyUp: (Object) => void; + + /** + * Handles ' ' (Space) key on the button to trigger onClick for + * accessibility. + * + * @param {Object} event - The key event. + * @private + * @returns {void} + */ + _onKeyUp(event) { + // If the event coming to the dialog has been subject to preventDefault + // we don't handle it here. + if (event.defaultPrevented) { + return; + } + + if (event.key === ' ') { + event.preventDefault(); + event.stopPropagation(); + this.props.onClick(); + } + } + /** * Handles rendering of the actual item. If the label is being shown, which * is controlled with the `showLabel` prop, the item is rendered for its @@ -27,14 +90,22 @@ export default class ToolboxItem extends AbstractToolboxItem { elementAfter, onClick, showLabel, - tooltipPosition + tooltipPosition, + toggled } = this.props; const className = showLabel ? 'overflow-menu-item' : 'toolbox-button'; const props = { + 'aria-pressed': toggled, + 'aria-disabled': disabled, 'aria-label': this.accessibilityLabel, className: className + (disabled ? ' disabled' : ''), - onClick: disabled ? undefined : onClick + onClick: disabled ? undefined : onClick, + onKeyDown: this._onKeyDown, + onKeyUp: this._onKeyUp, + tabIndex: 0, + role: 'button' }; + const elementType = showLabel ? 'li' : 'div'; const useTooltip = this.tooltip && this.tooltip.length > 0; let children = ( diff --git a/react/features/toolbox/components/web/ToolbarButton.js b/react/features/toolbox/components/web/ToolbarButton.js index 5b779d530..c02a35543 100644 --- a/react/features/toolbox/components/web/ToolbarButton.js +++ b/react/features/toolbox/components/web/ToolbarButton.js @@ -41,6 +41,68 @@ class ToolbarButton extends AbstractToolbarButton { tooltipPosition: 'top' }; + /** + * Initializes a new {@code ToolbarButton} instance. + * + * @inheritdoc + */ + constructor(props: Props) { + super(props); + + this._onKeyDown = this._onKeyDown.bind(this); + this._onKeyUp = this._onKeyUp.bind(this); + } + + _onKeyDown: (Object) => void; + + /** + * Handles 'Enter' key on the button to trigger onClick for accessibility. + * + * @param {Object} event - The key event. + * @private + * @returns {void} + */ + _onKeyDown(event) { + // If the event coming to the dialog has been subject to preventDefault + // we don't handle it here. + if (event.defaultPrevented) { + return; + } + + if (event.key === 'Enter') { + event.preventDefault(); + event.stopPropagation(); + this.props.onClick(); + } else if (event.key === ' ') { + // Space triggers button onKeyUp but we need to prevent default here + event.preventDefault(); + } + } + + _onKeyUp: (Object) => void; + + /** + * Handles ' '(Space) key on the button to trigger onClick for + * accessibility. + * + * @param {Object} event - The key event. + * @private + * @returns {void} + */ + _onKeyUp(event) { + // If the event coming to the dialog has been subject to preventDefault + // we don't handle it here. + if (event.defaultPrevented) { + return; + } + + if (event.key === ' ') { + event.preventDefault(); + event.stopPropagation(); + this.props.onClick(); + } + } + /** * Renders the button of this {@code ToolbarButton}. * @@ -53,8 +115,13 @@ class ToolbarButton extends AbstractToolbarButton { return (
+ onClick = { this.props.onClick } + onKeyDown = { this._onKeyDown } + onKeyUp = { this._onKeyUp } + role = 'button' + tabIndex = { 0 }> { this.props.tooltip ?