commit ea8e66f2a395cfce142b15a9c015fb4dca6a2a68
parent 7374c542014937ba08c1df36cf4b17abdad25379
Author: Mark Striemer <mstriemer@mozilla.com>
Date: Fri, 24 Oct 2025 15:28:18 +0000
Bug 1981715 - moz-button keyboard support for PanelMultiView r=daleharvey,desktop-theme-reviewers,hjones
Differential Revision: https://phabricator.services.mozilla.com/D269429
Diffstat:
4 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/browser/base/content/browser-trustPanel.js b/browser/base/content/browser-trustPanel.js
@@ -499,6 +499,7 @@ class TrustPanel {
let children = blockers.map(async blocker => {
let button = document.createElement("moz-button");
+ button.classList.add("moz-button-subviewbutton-nav");
button.setAttribute("iconsrc", blocker.iconSrc);
button.setAttribute("type", "ghost icon");
document.l10n.setAttributes(
diff --git a/browser/components/customizableui/PanelMultiView.sys.mjs b/browser/components/customizableui/PanelMultiView.sys.mjs
@@ -1594,6 +1594,7 @@ export var PanelView = class extends AssociatedToNode {
localName == "toolbarbutton" ||
localName == "checkbox" ||
localName == "a" ||
+ localName == "moz-button" ||
localName == "moz-toggle" ||
node.classList.contains("text-link") ||
(!arrowKey && isNavigableWithTabOnly) ||
@@ -1884,7 +1885,13 @@ export var PanelView = class extends AssociatedToNode {
// If the current button is _not_ one that points to a subview, pressing
// the arrow key shouldn't do anything.
let button = this.selectedElement;
- if (!button || !button.classList.contains("subviewbutton-nav")) {
+ if (
+ !button ||
+ !(
+ button.classList.contains("subviewbutton-nav") ||
+ button.classList.contains("moz-button-subviewbutton-nav")
+ )
+ ) {
break;
}
}
diff --git a/browser/components/customizableui/test/browser_PanelMultiView_keyboard.js b/browser/components/customizableui/test/browser_PanelMultiView_keyboard.js
@@ -34,6 +34,8 @@ let gBrowserBrowser;
let gIframeView;
let gIframeIframe;
let gToggle;
+let gMozButton;
+let gMozButtonSubviewNav;
let gComponentView;
let gShadowRoot;
let gShadowRootButtonA;
@@ -157,6 +159,15 @@ add_setup(async function () {
gToggle = document.createElement("moz-toggle");
gToggle.label = "Test label";
gMainView.appendChild(gToggle);
+ gMozButton = document.createElement("moz-button");
+ gMozButton.label = "gMozButton";
+ gMozButton.id = "gMozButton";
+ gMainView.appendChild(gMozButton);
+ gMozButtonSubviewNav = document.createElement("moz-button");
+ gMozButtonSubviewNav.label = "gMozButtonSubviewNav";
+ gMozButtonSubviewNav.id = "gMozButtonSubviewNav";
+ gMozButtonSubviewNav.classList.add("moz-button-subviewbutton-nav");
+ gMainView.appendChild(gMozButtonSubviewNav);
gMainTabOrder = [
gMainButton1,
@@ -169,6 +180,8 @@ add_setup(async function () {
gNamespacedLink,
gLink,
gToggle,
+ gMozButton,
+ gMozButtonSubviewNav,
];
gMainArrowOrder = [
gMainButton1,
@@ -178,6 +191,8 @@ add_setup(async function () {
gNamespacedLink,
gLink,
gToggle,
+ gMozButton,
+ gMozButtonSubviewNav,
];
gSubView = document.createXULElement("panelview");
@@ -447,6 +462,48 @@ add_task(async function testLeftArrowTextarea() {
await hidePopup();
});
+add_task(async function testRightArrow() {
+ await openPopup();
+
+ // Ensure non moz-button-subviewbutton-navs respond to the right arrow
+ let clicked = false;
+ let assertNoClick = () => {
+ clicked = true;
+ };
+ gMozButton.addEventListener("click", assertNoClick);
+ // Focus using the arrow keys so PanelMultiView#selectedElement is set
+ for (let i = 0; i < gMainTabOrder.length; i++) {
+ EventUtils.synthesizeKey("KEY_ArrowUp");
+ if (document.activeElement == gMozButton) {
+ break;
+ }
+ }
+ is(document.activeElement, gMozButton, "gMozButton focused");
+ EventUtils.synthesizeKey("KEY_ArrowRight");
+ ok(!clicked, "click handler should not be triggered for regular button");
+ EventUtils.synthesizeKey(" ");
+ ok(clicked, "click handler triggered on space");
+ gMozButton.removeEventListener("click", assertNoClick);
+
+ // Ensure moz-button-subviewbutton-nav gets click on right arrow
+ gMozButtonSubviewNav.addEventListener(
+ "click",
+ () => gPanelMultiView.showSubView(gSubView, gMozButtonSubviewNav),
+ { once: true }
+ );
+ let shown = BrowserTestUtils.waitForEvent(gSubView, "ViewShown");
+ EventUtils.synthesizeKey("KEY_ArrowDown");
+ is(
+ document.activeElement,
+ gMozButtonSubviewNav,
+ "gMozButtonSubviewNav focused"
+ );
+ EventUtils.synthesizeKey("KEY_ArrowRight");
+ await shown;
+ ok(true, "Triggered moz-button-subviewbutton-nav on right arrow");
+ await hidePopup();
+});
+
// Test navigation to a button which is initially disabled and later enabled.
add_task(async function testDynamicButton() {
gMainButton2.disabled = true;
diff --git a/browser/themes/shared/controlcenter/panel.css b/browser/themes/shared/controlcenter/panel.css
@@ -968,7 +968,7 @@
}
}
-#trustpanel-blockerView moz-button {
+.moz-button-subviewbutton-nav {
--button-font-weight: normal;
--button-alignment: inline-start;
--button-border-radius: var(--border-radius-small);