Bug 1520107 - fix focus and keyboard triggered context menu handling in a11y panel tree. r=gl

MozReview-Commit-ID: 2kzvA2Eb1eF

Differential Revision: https://phabricator.services.mozilla.com/D16986
This commit is contained in:
Yura Zenevich
2019-01-19 18:13:55 +00:00
parent 6c5ce840ce
commit 4358b687fe
4 changed files with 34 additions and 18 deletions

View File

@@ -228,30 +228,28 @@ body {
min-width: 50%; min-width: 50%;
} }
.treeTable:focus, .treeTable:focus {
.treeTable > tbody:focus {
outline: 0; outline: 0;
} }
.treeTable::-moz-focus-inner, .treeTable::-moz-focus-inner {
.treeTable > tbody::-moz-focus-inner {
border: 0; border: 0;
} }
.treeTable:not(:focus) tbody:not(:focus) .treeRow.selected { .treeTable:not(:focus) .treeRow.selected {
background-color: var(--accessibility-unfocused-tree-focused-node-background); background-color: var(--accessibility-unfocused-tree-focused-node-background);
} }
.treeTable:not(:focus) tbody:not(:focus) .treeRow.selected .theme-twisty { .treeTable:not(:focus) .treeRow.selected .theme-twisty {
fill: var(--accessibility-unfocused-tree-focused-node-twisty-fill); fill: var(--accessibility-unfocused-tree-focused-node-twisty-fill);
} }
.treeTable:not(:focus) tbody:not(:focus) .treeRow.selected *, .treeTable:not(:focus) .treeRow.selected *,
.treeTable:not(:focus) tbody:not(:focus) .treeRow.selected .treeLabelCell:after { .treeTable:not(:focus) .treeRow.selected .treeLabelCell:after {
color: inherit; color: inherit;
} }
.treeTable:not(:focus) tbody:not(:focus) .treeRow.selected .objectBox-string { .treeTable:not(:focus) .treeRow.selected .objectBox-string {
color: var(--string-color); color: var(--string-color);
} }

View File

@@ -61,6 +61,7 @@ class AccessibilityRow extends Component {
static get propTypes() { static get propTypes() {
return { return {
...TreeRow.propTypes, ...TreeRow.propTypes,
hasContextMenu: PropTypes.bool.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
walker: PropTypes.object, walker: PropTypes.object,
}; };
@@ -193,11 +194,6 @@ class AccessibilityRow extends Component {
} }
} }
get hasContextMenu() {
const { supports } = this.props;
return supports.snapshot;
}
/** /**
* Render accessible row component. * Render accessible row component.
* @returns acecssible-row React component. * @returns acecssible-row React component.
@@ -205,7 +201,7 @@ class AccessibilityRow extends Component {
render() { render() {
const { object } = this.props.member; const { object } = this.props.member;
const props = Object.assign({}, this.props, { const props = Object.assign({}, this.props, {
onContextMenu: this.hasContextMenu && (e => this.onContextMenu(e)), onContextMenu: this.props.hasContextMenu && (e => this.onContextMenu(e)),
onMouseOver: () => this.highlight(object), onMouseOver: () => this.highlight(object),
onMouseOut: () => this.unhighlight(), onMouseOut: () => this.unhighlight(),
}); });
@@ -218,4 +214,5 @@ const mapStateToProps = ({ ui }) => ({
supports: ui.supports, supports: ui.supports,
}); });
module.exports = connect(mapStateToProps)(AccessibilityRow); module.exports =
connect(mapStateToProps, null, null, { withRef: true })(AccessibilityRow);

View File

@@ -34,6 +34,7 @@ class AccessibilityTree extends Component {
expanded: PropTypes.object, expanded: PropTypes.object,
selected: PropTypes.string, selected: PropTypes.string,
highlighted: PropTypes.object, highlighted: PropTypes.object,
supports: PropTypes.object,
}; };
} }
@@ -137,9 +138,14 @@ class AccessibilityTree extends Component {
expanded, expanded,
selected, selected,
highlighted: highlightedItem, highlighted: highlightedItem,
supports,
walker, walker,
} = this.props; } = this.props;
// Historically, the first context menu item is snapshot function and it is available
// for all accessible object.
const hasContextMenu = supports.snapshot;
const renderValue = props => { const renderValue = props => {
return Rep(Object.assign({}, props, { return Rep(Object.assign({}, props, {
defaultRep: Grip, defaultRep: Grip,
@@ -152,6 +158,7 @@ class AccessibilityTree extends Component {
const highlighted = object === highlightedItem; const highlighted = object === highlightedItem;
return AccessibilityRow(Object.assign({}, rowProps, { return AccessibilityRow(Object.assign({}, rowProps, {
walker, walker,
hasContextMenu,
highlighted, highlighted,
decorator: { decorator: {
getRowClass: function() { getRowClass: function() {
@@ -180,6 +187,17 @@ class AccessibilityTree extends Component {
} }
this.selectRow(event.currentTarget); this.selectRow(event.currentTarget);
}, },
onContextMenuTree: hasContextMenu && function(e) {
// If context menu event is triggered on (or bubbled to) the TreeView, it was
// done via keyboard. Open context menu for currently selected row.
let row = this.getSelectedRow();
if (!row) {
return;
}
row = row.getWrappedInstance();
row.onContextMenu(e);
},
}) })
); );
} }
@@ -189,6 +207,7 @@ const mapStateToProps = ({ accessibles, ui }) => ({
accessibles, accessibles,
expanded: ui.expanded, expanded: ui.expanded,
selected: ui.selected, selected: ui.selected,
supports: ui.supports,
highlighted: ui.highlighted, highlighted: ui.highlighted,
}); });
// Exports from this module // Exports from this module

View File

@@ -117,6 +117,8 @@ define(function(require, exports, module) {
onSort: PropTypes.func, onSort: PropTypes.func,
// Custom row click callback // Custom row click callback
onClickRow: PropTypes.func, onClickRow: PropTypes.func,
// Tree context menu event handler
onContextMenuTree: PropTypes.func,
// A header is displayed if set to true // A header is displayed if set to true
header: PropTypes.bool, header: PropTypes.bool,
// Long string is expandable by a toggle button // Long string is expandable by a toggle button
@@ -512,8 +514,8 @@ define(function(require, exports, module) {
const classNames = ["treeTable"]; const classNames = ["treeTable"];
this.rows = []; this.rows = [];
const { className, onContextMenuTree } = this.props;
// Use custom class name from props. // Use custom class name from props.
const className = this.props.className;
if (className) { if (className) {
classNames.push(...className.split(" ")); classNames.push(...className.split(" "));
} }
@@ -541,6 +543,7 @@ define(function(require, exports, module) {
}, },
tabIndex: 0, tabIndex: 0,
onKeyDown: this.onKeyDown, onKeyDown: this.onKeyDown,
onContextMenu: onContextMenuTree && onContextMenuTree.bind(this),
"aria-label": this.props.label || "", "aria-label": this.props.label || "",
"aria-activedescendant": this.state.selected, "aria-activedescendant": this.state.selected,
cellPadding: 0, cellPadding: 0,
@@ -548,7 +551,6 @@ define(function(require, exports, module) {
TreeHeader(props), TreeHeader(props),
dom.tbody({ dom.tbody({
role: "presentation", role: "presentation",
tabIndex: -1,
}, rows) }, rows)
) )
); );