Ver código fonte

Improve accessibility of Buttons in Webapp (#5432)

* Expose toggle buttons better via ARIA

* Wire up the divs/li as role=button as per ARIA patterns

* Add flow annotations to appease the linter

* For role=button use aria-pressed not aria-checked
j8
Michael Telatynski 5 anos atrás
pai
commit
953f838a2a
Nenhuma conta vinculada ao e-mail do autor do commit

+ 4
- 3
react/features/base/toolbox/components/AbstractButton.js Ver arquivo

@@ -230,13 +230,14 @@ export default class AbstractButton<P: Props, S: *> extends Component<P, S> {
230 230
 
231 231
     /**
232 232
      * Helper function to be implemented by subclasses, which must return a
233
-     * {@code boolean} value indicating if this button is toggled or not.
233
+     * {@code boolean} value indicating if this button is toggled or not or
234
+     * undefined if the button is not toggleable.
234 235
      *
235 236
      * @protected
236
-     * @returns {boolean}
237
+     * @returns {?boolean}
237 238
      */
238 239
     _isToggled() {
239
-        return false;
240
+        return undefined;
240 241
     }
241 242
 
242 243
     _onClick: (*) => void;

+ 73
- 2
react/features/base/toolbox/components/ToolboxItem.web.js Ver arquivo

@@ -12,6 +12,69 @@ import type { Props } from './AbstractToolboxItem';
12 12
  * Web implementation of {@code AbstractToolboxItem}.
13 13
  */
14 14
 export default class ToolboxItem extends AbstractToolboxItem<Props> {
15
+    /**
16
+     * Initializes a new {@code ToolboxItem} instance.
17
+     *
18
+     * @inheritdoc
19
+     */
20
+    constructor(props: Props) {
21
+        super(props);
22
+
23
+        this._onKeyDown = this._onKeyDown.bind(this);
24
+        this._onKeyUp = this._onKeyUp.bind(this);
25
+    }
26
+
27
+    _onKeyDown: (Object) => void;
28
+
29
+    /**
30
+     * Handles 'Enter' key on the button to trigger onClick for accessibility.
31
+     *
32
+     * @param {Object} event - The key event.
33
+     * @private
34
+     * @returns {void}
35
+     */
36
+    _onKeyDown(event) {
37
+        // If the event coming to the dialog has been subject to preventDefault
38
+        // we don't handle it here.
39
+        if (event.defaultPrevented) {
40
+            return;
41
+        }
42
+
43
+        if (event.key === 'Enter') {
44
+            event.preventDefault();
45
+            event.stopPropagation();
46
+            this.props.onClick();
47
+        } else if (event.key === ' ') {
48
+            // Space triggers button onKeyUp but we need to prevent PTT here
49
+            event.preventDefault();
50
+            event.stopPropagation();
51
+        }
52
+    }
53
+
54
+    _onKeyUp: (Object) => void;
55
+
56
+    /**
57
+     * Handles ' ' (Space) key on the button to trigger onClick for
58
+     * accessibility.
59
+     *
60
+     * @param {Object} event - The key event.
61
+     * @private
62
+     * @returns {void}
63
+     */
64
+    _onKeyUp(event) {
65
+        // If the event coming to the dialog has been subject to preventDefault
66
+        // we don't handle it here.
67
+        if (event.defaultPrevented) {
68
+            return;
69
+        }
70
+
71
+        if (event.key === ' ') {
72
+            event.preventDefault();
73
+            event.stopPropagation();
74
+            this.props.onClick();
75
+        }
76
+    }
77
+
15 78
     /**
16 79
      * Handles rendering of the actual item. If the label is being shown, which
17 80
      * is controlled with the `showLabel` prop, the item is rendered for its
@@ -27,14 +90,22 @@ export default class ToolboxItem extends AbstractToolboxItem<Props> {
27 90
             elementAfter,
28 91
             onClick,
29 92
             showLabel,
30
-            tooltipPosition
93
+            tooltipPosition,
94
+            toggled
31 95
         } = this.props;
32 96
         const className = showLabel ? 'overflow-menu-item' : 'toolbox-button';
33 97
         const props = {
98
+            'aria-pressed': toggled,
99
+            'aria-disabled': disabled,
34 100
             'aria-label': this.accessibilityLabel,
35 101
             className: className + (disabled ? ' disabled' : ''),
36
-            onClick: disabled ? undefined : onClick
102
+            onClick: disabled ? undefined : onClick,
103
+            onKeyDown: this._onKeyDown,
104
+            onKeyUp: this._onKeyUp,
105
+            tabIndex: 0,
106
+            role: 'button'
37 107
         };
108
+
38 109
         const elementType = showLabel ? 'li' : 'div';
39 110
         const useTooltip = this.tooltip && this.tooltip.length > 0;
40 111
         let children = (

+ 68
- 1
react/features/toolbox/components/web/ToolbarButton.js Ver arquivo

@@ -41,6 +41,68 @@ class ToolbarButton extends AbstractToolbarButton<Props> {
41 41
         tooltipPosition: 'top'
42 42
     };
43 43
 
44
+    /**
45
+     * Initializes a new {@code ToolbarButton} instance.
46
+     *
47
+     * @inheritdoc
48
+     */
49
+    constructor(props: Props) {
50
+        super(props);
51
+
52
+        this._onKeyDown = this._onKeyDown.bind(this);
53
+        this._onKeyUp = this._onKeyUp.bind(this);
54
+    }
55
+
56
+    _onKeyDown: (Object) => void;
57
+
58
+    /**
59
+     * Handles 'Enter' key on the button to trigger onClick for accessibility.
60
+     *
61
+     * @param {Object} event - The key event.
62
+     * @private
63
+     * @returns {void}
64
+     */
65
+    _onKeyDown(event) {
66
+        // If the event coming to the dialog has been subject to preventDefault
67
+        // we don't handle it here.
68
+        if (event.defaultPrevented) {
69
+            return;
70
+        }
71
+
72
+        if (event.key === 'Enter') {
73
+            event.preventDefault();
74
+            event.stopPropagation();
75
+            this.props.onClick();
76
+        } else if (event.key === ' ') {
77
+            // Space triggers button onKeyUp but we need to prevent default here
78
+            event.preventDefault();
79
+        }
80
+    }
81
+
82
+    _onKeyUp: (Object) => void;
83
+
84
+    /**
85
+     * Handles ' '(Space) key on the button to trigger onClick for
86
+     * accessibility.
87
+     *
88
+     * @param {Object} event - The key event.
89
+     * @private
90
+     * @returns {void}
91
+     */
92
+    _onKeyUp(event) {
93
+        // If the event coming to the dialog has been subject to preventDefault
94
+        // we don't handle it here.
95
+        if (event.defaultPrevented) {
96
+            return;
97
+        }
98
+
99
+        if (event.key === ' ') {
100
+            event.preventDefault();
101
+            event.stopPropagation();
102
+            this.props.onClick();
103
+        }
104
+    }
105
+
44 106
     /**
45 107
      * Renders the button of this {@code ToolbarButton}.
46 108
      *
@@ -53,8 +115,13 @@ class ToolbarButton extends AbstractToolbarButton<Props> {
53 115
         return (
54 116
             <div
55 117
                 aria-label = { this.props.accessibilityLabel }
118
+                aria-pressed = { this.props.toggled }
56 119
                 className = 'toolbox-button'
57
-                onClick = { this.props.onClick }>
120
+                onClick = { this.props.onClick }
121
+                onKeyDown = { this._onKeyDown }
122
+                onKeyUp = { this._onKeyUp }
123
+                role = 'button'
124
+                tabIndex = { 0 }>
58 125
                 { this.props.tooltip
59 126
                     ? <Tooltip
60 127
                         content = { this.props.tooltip }

Carregando…
Cancelar
Salvar