Bug 1922570 - Show global actions on seperate row from heuristic. r=daisuke,desktop-theme-reviewers,urlbar-reviewers,dao

Differential Revision: https://phabricator.services.mozilla.com/D225051
This commit is contained in:
Dale Harvey 2024-10-21 19:36:57 +00:00
parent c281f85c81
commit 492d53d62e
22 changed files with 272 additions and 211 deletions

View File

@ -436,6 +436,7 @@ pref("browser.urlbar.suggest.topsites", true);
pref("browser.urlbar.suggest.engines", true);
pref("browser.urlbar.suggest.calculator", false);
pref("browser.urlbar.suggest.recentsearches", true);
pref("browser.urlbar.suggest.quickactions", true);
pref("browser.urlbar.deduplication.enabled", false);
pref("browser.urlbar.deduplication.thresholdDays", 7);

View File

@ -30,6 +30,7 @@ Preferences.addAll([
{ id: "browser.urlbar.trending.featureGate", type: "bool" },
{ id: "browser.urlbar.recentsearches.featureGate", type: "bool" },
{ id: "browser.urlbar.suggest.recentsearches", type: "bool" },
{ id: "browser.urlbar.scotchBonnet.enableOverride", type: "bool" },
]);
const ENGINE_FLAVOR = "text/x-moz-search-engine";
@ -446,8 +447,13 @@ var gSearchPane = {
_initQuickActionsSection() {
let showPref = Preferences.get("browser.urlbar.quickactions.showPrefs");
let scotchBonnet = Preferences.get(
"browser.urlbar.scotchBonnet.enableOverride"
);
let showQuickActionsGroup = () => {
document.getElementById("quickActionsBox").hidden = !showPref.value;
document.getElementById("quickActionsBox").hidden = !(
showPref.value || scotchBonnet.value
);
};
showPref.on("change", showQuickActionsGroup);
showQuickActionsGroup();

View File

@ -13,10 +13,7 @@ ChromeUtils.defineESModuleGetters(this, {
add_setup(async function setup() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.urlbar.secondaryActions.featureGate", true],
["browser.urlbar.quickactions.enabled", true],
],
set: [["browser.urlbar.secondaryActions.featureGate", true]],
});
ActionsProviderQuickActions.addAction("testaction", {

View File

@ -33,10 +33,10 @@ export class ActionsProvider {
*
* @param {UrlbarQueryContext} _queryContext The query context object.
* @param {UrlbarController} _controller The urlbar controller.
* @returns {ActionsResult}
* @returns {Array} An array of ActionResult's
* @abstract
*/
async queryAction(_queryContext, _controller) {
async queryActions(_queryContext, _controller) {
throw new Error("Not implemented.");
}
@ -64,6 +64,7 @@ export class ActionsResult {
#l10nArgs;
#icon;
#dataset;
#onPick;
/**
* @param {object} options
@ -79,13 +80,16 @@ export class ActionsResult {
* @param {object} options.dataset
* An object of properties we set on the action button that
* can be used to pass data when it is selected.
* @param { Function} options.onPick
* A callback function called when the result has been picked.
*/
constructor({ key, l10nId, l10nArgs, icon, dataset }) {
constructor({ key, l10nId, l10nArgs, icon, dataset, onPick }) {
this.#key = key;
this.#l10nId = l10nId;
this.#l10nArgs = l10nArgs;
this.#icon = icon;
this.#dataset = dataset;
this.#onPick = onPick;
}
get key() {
@ -107,4 +111,8 @@ export class ActionsResult {
get dataset() {
return this.#dataset;
}
get onPick() {
return this.#onPick;
}
}

View File

@ -12,6 +12,7 @@ import {
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
OpenSearchEngine: "resource://gre/modules/OpenSearchEngine.sys.mjs",
loadAndParseOpenSearchEngine:
"resource://gre/modules/OpenSearchLoader.sys.mjs",
@ -43,7 +44,7 @@ class ProviderContextualSearch extends ActionsProvider {
);
}
async queryAction(queryContext, controller) {
async queryActions(queryContext) {
let instance = this.queryInstance;
const hostname = URL.parse(queryContext.currentPage)?.hostname;
@ -52,7 +53,7 @@ class ProviderContextualSearch extends ActionsProvider {
return null;
}
let engine = await this.fetchEngine(controller);
let engine = await this.fetchEngine();
let icon = engine?.icon || (await engine?.getIconURL?.());
let defaultEngine = lazy.UrlbarSearchUtils.getDefaultEngine();
@ -64,16 +65,22 @@ class ProviderContextualSearch extends ActionsProvider {
return null;
}
return new ActionsResult({
key: "contextual-search",
l10nId: "urlbar-result-search-with",
l10nArgs: { engine: engine.name || engine.title },
icon,
});
return [
new ActionsResult({
key: "contextual-search",
l10nId: "urlbar-result-search-with",
l10nArgs: { engine: engine.name || engine.title },
icon,
onPick: (context, controller) => {
this.pickAction(context, controller);
},
}),
];
}
async fetchEngine(controller) {
let browser = controller.browserWindow.gBrowser.selectedBrowser;
async fetchEngine() {
let browser =
lazy.BrowserWindowTracker.getTopWindow().gBrowser.selectedBrowser;
let hostname = browser?.currentURI.host;
if (this.engines.has(hostname)) {
@ -90,8 +97,8 @@ class ProviderContextualSearch extends ActionsProvider {
return engines[0] ?? browser?.engines?.[0];
}
async pickAction(queryContext, controller, _element) {
let engine = await this.fetchEngine(controller);
async pickAction(queryContext, controller) {
let engine = await this.fetchEngine();
let enterSeachMode = true;
if (engine.uri && !queryContext.private) {

View File

@ -15,7 +15,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
});
// These prefs are relative to the `browser.urlbar` branch.
const ENABLED_PREF = "quickactions.enabled";
const ENABLED_PREF = "suggest.quickactions";
const MATCH_IN_PHRASE_PREF = "quickactions.matchInPhrase";
const MIN_SEARCH_PREF = "quickactions.minimumSearchString";
@ -29,7 +29,7 @@ class ProviderQuickActions extends ActionsProvider {
isActive(queryContext) {
return (
lazy.UrlbarPrefs.getScotchBonnetPref(ENABLED_PREF) &&
lazy.UrlbarPrefs.get(ENABLED_PREF) &&
!queryContext.searchMode &&
queryContext.trimmedSearchString.length < 50 &&
queryContext.trimmedSearchString.length >=
@ -37,7 +37,7 @@ class ProviderQuickActions extends ActionsProvider {
);
}
async queryAction(queryContext) {
async queryActions(queryContext) {
let input = queryContext.trimmedLowerCaseSearchString;
let results = await this.getActions(input);
@ -59,15 +59,18 @@ class ProviderQuickActions extends ActionsProvider {
return null;
}
let action = this.#actions.get(results[0]);
return new ActionsResult({
key: results[0],
l10nId: action.label,
icon: action.icon,
dataset: {
action: results[0],
inputLength: queryContext.trimmedSearchString.length,
},
return results.map(key => {
let action = this.#actions.get(key);
return new ActionsResult({
key,
l10nId: action.label,
icon: action.icon,
dataset: {
action: key,
inputLength: queryContext.trimmedSearchString.length,
},
onPick: action.onPick,
});
});
}

View File

@ -1046,6 +1046,7 @@ class TelemetryEvent {
.join(",");
let actions = currentResults
.map((r, i) => lazy.UrlbarUtils.searchEngagementTelemetryAction(r, i))
.filter(v => v)
.join(",");
const search_engine_default_id = Services.search.defaultEngine.telemetryId;

View File

@ -27,9 +27,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
UrlbarQueryContext: "resource:///modules/UrlbarUtils.sys.mjs",
UrlbarProviderOpenTabs: "resource:///modules/UrlbarProviderOpenTabs.sys.mjs",
UrlbarProvidersManager: "resource:///modules/UrlbarProvidersManager.sys.mjs",
UrlbarProviderActionsSearchMode:
"resource:///modules/UrlbarProviderActionsSearchMode.sys.mjs",
UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.sys.mjs",
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.sys.mjs",
UrlbarUtils: "resource:///modules/UrlbarUtils.sys.mjs",
@ -984,26 +981,6 @@ export class UrlbarInput {
if (!result) {
return;
}
if (
element?.dataset.action &&
element?.dataset.action != "tabswitch" &&
result.providerName != lazy.UrlbarProviderActionsSearchMode.name
) {
this.controller.engagementEvent.record(event, {
result,
element,
searchString: this._lastSearchString,
selType: "action",
searchSource: this.getSearchSource(event),
});
this.view.close();
let provider = lazy.UrlbarProvidersManager.getActionProvider(
element.dataset.providerName
);
let { queryContext } = this.controller._lastQueryContextWrapper || {};
provider.pickAction(queryContext, this.controller, element);
return;
}
this.pickResult(result, event, element);
}

View File

@ -0,0 +1,147 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This module exports a provider that returns all the available
* global actions for a query.
*/
import {
UrlbarProvider,
UrlbarUtils,
} from "resource:///modules/UrlbarUtils.sys.mjs";
const lazy = {};
// Default icon shown for actions if no custom one is provided.
const DEFAULT_ICON = "chrome://global/skin/icons/settings.svg";
const DYNAMIC_TYPE_NAME = "actions";
// The suggestion index of the actions row within the urlbar results.
const SUGGESTED_INDEX = 1;
const SCOTCH_BONNET_PREF = "scotchBonnet.enableOverride";
const ACTIONS_PREF = "secondaryActions.featureGate";
ChromeUtils.defineESModuleGetters(lazy, {
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
UrlbarResult: "resource:///modules/UrlbarResult.sys.mjs",
});
import { ActionsProviderQuickActions } from "resource:///modules/ActionsProviderQuickActions.sys.mjs";
import { ActionsProviderContextualSearch } from "resource:///modules/ActionsProviderContextualSearch.sys.mjs";
let globalActionsProviders = [
ActionsProviderContextualSearch,
ActionsProviderQuickActions,
];
/**
* A provider that lets the user view all available global actions for a query.
*/
class ProviderGlobalActions extends UrlbarProvider {
// A Map of the last queried actions.
#actions = new Map();
get name() {
return "UrlbarProviderGlobalActions";
}
get type() {
return UrlbarUtils.PROVIDER_TYPE.PROFILE;
}
isActive() {
return (
lazy.UrlbarPrefs.get(SCOTCH_BONNET_PREF) ||
lazy.UrlbarPrefs.get(ACTIONS_PREF)
);
}
async startQuery(queryContext, addCallback) {
this.#actions.clear();
for (let provider of globalActionsProviders) {
if (provider.isActive(queryContext)) {
for (let action of (await provider.queryActions(queryContext)) || []) {
this.#actions.set(action.key, action);
}
}
}
if (!this.#actions.size) {
return;
}
let result = new lazy.UrlbarResult(
UrlbarUtils.RESULT_TYPE.DYNAMIC,
UrlbarUtils.RESULT_SOURCE.ACTIONS,
{
results: [...this.#actions.keys()],
dynamicType: DYNAMIC_TYPE_NAME,
inputLength: queryContext.searchString.length,
}
);
result.suggestedIndex = SUGGESTED_INDEX;
addCallback(this, result);
}
onEngagement(queryContext, controller, details) {
let key = details.element.dataset.action;
let options = this.#actions.get(key).onPick(queryContext, controller);
if (options?.focusContent) {
details.element.ownerGlobal.gBrowser.selectedBrowser.focus();
}
controller.view.close();
}
getViewTemplate(result) {
return {
children: [
{
name: "buttons",
tag: "div",
children: result.payload.results.map((key, i) => {
let action = this.#actions.get(key);
return {
name: `button-${i}`,
tag: "span",
classList: ["urlbarView-action-btn"],
attributes: {
inputLength: result.payload.inputLength,
"data-action": key,
role: "button",
},
children: [
{
tag: "img",
attributes: {
src: action.icon || DEFAULT_ICON,
},
},
{
name: `label-${i}`,
tag: "span",
},
],
};
}),
},
],
};
}
getViewUpdate(result) {
let viewUpdate = {};
result.payload.results.forEach((key, i) => {
let action = this.#actions.get(key);
viewUpdate[`label-${i}`] = {
l10n: { id: action.l10nId, args: action.l10nArgs, cacheable: true },
};
});
return viewUpdate;
}
}
export var UrlbarProviderGlobalActions = new ProviderGlobalActions();

View File

@ -33,6 +33,8 @@ var localProviderModules = {
"resource:///modules/UrlbarProviderAboutPages.sys.mjs",
UrlbarProviderActionsSearchMode:
"resource:///modules/UrlbarProviderActionsSearchMode.sys.mjs",
UrlbarProviderGlobalActions:
"resource:///modules/UrlbarProviderGlobalActions.sys.mjs",
UrlbarProviderAliasEngines:
"resource:///modules/UrlbarProviderAliasEngines.sys.mjs",
UrlbarProviderAutofill: "resource:///modules/UrlbarProviderAutofill.sys.mjs",
@ -86,14 +88,6 @@ var localMuxerModules = {
"resource:///modules/UrlbarMuxerUnifiedComplete.sys.mjs",
};
import { ActionsProviderQuickActions } from "resource:///modules/ActionsProviderQuickActions.sys.mjs";
import { ActionsProviderContextualSearch } from "resource:///modules/ActionsProviderContextualSearch.sys.mjs";
let globalActionsProviders = [
ActionsProviderContextualSearch,
ActionsProviderQuickActions,
];
const DEFAULT_MUXER = "UnifiedComplete";
/**
@ -207,17 +201,6 @@ class ProvidersManager {
return this.providers.find(p => p.name == name);
}
/**
* Returns the provider with the given name.
*
* @param {string} name
* The provider name.
* @returns {UrlbarProvider} The provider.
*/
getActionProvider(name) {
return globalActionsProviders.find(p => p.name == name);
}
/**
* Registers a muxer object with the manager.
*
@ -324,14 +307,6 @@ class ProvidersManager {
// history and bookmarks even if search engines are not available.
}
// All current global actions are currently memory lookups so it is safe to
// wait on them.
this.#globalAction = lazy.UrlbarPrefs.getScotchBonnetPref(
"secondaryActions.featureGate"
)
? await this.pickGlobalAction(queryContext, controller)
: null;
if (query.canceled) {
return;
}
@ -511,25 +486,6 @@ class ProvidersManager {
);
}
}
#globalAction = null;
async pickGlobalAction(queryContext, controller) {
for (let provider of globalActionsProviders) {
if (provider.isActive(queryContext)) {
let action = await provider.queryAction(queryContext, controller);
if (action) {
action.providerName = provider.name;
return action;
}
}
}
return null;
}
getGlobalAction() {
return this.#globalAction;
}
}
export var UrlbarProvidersManager = new ProvidersManager();

View File

@ -1508,6 +1508,8 @@ export var UrlbarUtils = {
return "fxsuggest_data_sharing_opt_in";
case "Weather":
return "weather";
case "UrlbarProviderGlobalActions":
return "action";
}
break;
case UrlbarUtils.RESULT_TYPE.KEYWORD:
@ -1605,13 +1607,11 @@ export var UrlbarUtils = {
return "unknown";
},
searchEngagementTelemetryAction(result, index) {
let action =
index == 0
? lazy.UrlbarProvidersManager.getGlobalAction()
: result.payload.action;
return action?.key ?? "none";
searchEngagementTelemetryAction(result) {
if (result.providerName != "UrlbarProviderGlobalActions") {
return result.payload.action?.key ?? "none";
}
return result.payload.results.map(({ key }) => key).join(",");
},
_getQuickSuggestTelemetryType(result) {

View File

@ -15,6 +15,8 @@ ChromeUtils.defineESModuleGetters(lazy, {
ObjectUtils: "resource://gre/modules/ObjectUtils.sys.mjs",
UrlbarProviderOpenTabs: "resource:///modules/UrlbarProviderOpenTabs.sys.mjs",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
UrlbarProviderGlobalActions:
"resource:///modules/UrlbarProviderGlobalActions.sys.mjs",
UrlbarProviderQuickSuggest:
"resource:///modules/UrlbarProviderQuickSuggest.sys.mjs",
UrlbarProviderRecentSearches:
@ -341,10 +343,18 @@ export class UrlbarView {
}
return;
}
this.selectedRowIndex = Math.max(
0,
Math.min(end, selectedRowIndex + amount * (reverse ? -1 : 1))
);
let index = Math.min(end, selectedRowIndex + amount * (reverse ? -1 : 1));
// When navigating with arrow keys we skip rows that contain
// global actions.
if (
this.#rows.children[index]?.result.providerName ==
lazy.UrlbarProviderGlobalActions.name &&
this.#rows.children.length > 2
) {
index = index + (reverse ? -1 : 1);
}
this.selectedRowIndex = Math.max(0, index);
return;
}
@ -1780,10 +1790,7 @@ export class UrlbarView {
item._content.id = item.id + "-inner";
let isFirstChild = item === this.#rows.children[0];
let secAction =
result.heuristic || isFirstChild
? lazy.UrlbarProvidersManager.getGlobalAction()
: result.payload.action;
let secAction = result.payload.action;
let container = item.querySelector(".urlbarView-actions-container");
if (secAction && !container) {
item.appendChild(this.#createSecondaryAction(secAction, isFirstChild));

View File

@ -243,6 +243,7 @@ urlbar:
description: >
The type of the result the user selected. The `unknown` type should
not occur and indicates a bug. The possible types are:
`action`,
`addon`,
`autofill_about`,
`autofill_adaptive`,
@ -369,6 +370,7 @@ urlbar:
Comma separated list of result types in the order they were shown to
the user. The `unknown` type should not occur and indicates a bug. The
possible types are:
`action`,
`addon`,
`autofill_about`,
`autofill_adaptive`,

View File

@ -31,6 +31,7 @@ EXTRA_JS_MODULES += [
"UrlbarProviderBookmarkKeywords.sys.mjs",
"UrlbarProviderCalculator.sys.mjs",
"UrlbarProviderClipboard.sys.mjs",
"UrlbarProviderGlobalActions.sys.mjs",
"UrlbarProviderHeuristicFallback.sys.mjs",
"UrlbarProviderHistoryUrlHeuristic.sys.mjs",
"UrlbarProviderInputHistory.sys.mjs",

View File

@ -33,7 +33,7 @@ add_setup(async function setup() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.urlbar.quickactions.enabled", true],
["browser.urlbar.secondaryActions.featureGate", true],
["browser.urlbar.scotchBonnet.enableOverride", true],
],
});
@ -238,14 +238,14 @@ add_task(async function test_whitespace() {
value: "",
});
const countForEmpty = window.document.querySelectorAll(
".urlbarView-quickaction-button"
".urlbarView-action-btn"
).length;
await UrlbarTestUtils.promiseAutocompleteResultPopup({
window,
value: " ",
});
const countForWhitespace = window.document.querySelectorAll(
".urlbarView-quickaction-button"
".urlbarView-action-btn"
).length;
Assert.equal(
countForEmpty,

View File

@ -46,7 +46,7 @@ add_task(async function test_quickaction() {
Assert.equal(
UrlbarTestUtils.getResultCount(window),
1,
2,
"We matched the action"
);

View File

@ -170,9 +170,9 @@ add_task(async function general() {
assert: () =>
assertAbandonmentTelemetry([
{
groups: "heuristic,general",
results: "search_engine,bookmark",
n_results: 2,
groups: "heuristic,suggested_index,general",
results: "search_engine,action,bookmark",
n_results: 3,
},
]),
});

View File

@ -170,9 +170,9 @@ add_task(async function general() {
assert: () =>
assertEngagementTelemetry([
{
groups: "heuristic,general",
results: "search_engine,bookmark",
n_results: 2,
groups: "heuristic,suggested_index,general",
results: "search_engine,action,bookmark",
n_results: 3,
},
]),
});

View File

@ -101,6 +101,9 @@ add_task(async function selected_result_autofill_url() {
add_task(async function selected_result_bookmark() {
await doTest(async () => {
await SpecialPowers.pushPrefEnv({
set: [["browser.urlbar.secondaryActions.featureGate", false]],
});
await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
url: "https://example.com/bookmark",
@ -938,11 +941,11 @@ add_task(async function selected_result_action() {
assertEngagementTelemetry([
{
selected_result: "action_settings",
selected_position: 1,
provider: "HeuristicFallback",
results: "search_engine",
actions: "settings",
selected_result: "action",
selected_position: 2,
provider: "UrlbarProviderGlobalActions",
results: "search_engine,action",
actions: "none",
},
]);
});

View File

@ -10,28 +10,28 @@ ChromeUtils.defineESModuleGetters(this, {
});
add_setup(async () => {
UrlbarPrefs.set("quickactions.enabled", true);
UrlbarPrefs.set("secondaryActions.featureGate", true);
ActionsProviderQuickActions.addAction("newaction", {
commands: ["newaction"],
});
registerCleanupFunction(async () => {
UrlbarPrefs.clear("quickactions.enabled");
UrlbarPrefs.clear("secondaryActions.featureGate");
ActionsProviderQuickActions.removeAction("newaction");
});
});
add_task(async function nomatch() {
let context = createContext("this doesnt match", {});
let result = await ActionsProviderQuickActions.queryAction(context);
Assert.ok(result === null, "there were no matches");
let results = await ActionsProviderQuickActions.queryActions(context);
Assert.ok(results === null, "there were no matches");
});
add_task(async function quickactions_match() {
let context = createContext("new", {});
let result = await ActionsProviderQuickActions.queryAction(context);
Assert.ok(result.key == "newaction", "Matched the new action");
let results = await ActionsProviderQuickActions.queryActions(context);
Assert.ok(results[0].key == "newaction", "Matched the new action");
});
add_task(async function duplicate_matches() {
@ -40,9 +40,9 @@ add_task(async function duplicate_matches() {
});
let context = createContext("test", {});
let result = await ActionsProviderQuickActions.queryAction(context);
let results = await ActionsProviderQuickActions.queryActions(context);
Assert.ok(result.key == "testaction", "Matched the test action");
Assert.ok(results[0].key == "testaction", "Matched the test action");
ActionsProviderQuickActions.removeAction("testaction");
});
@ -54,7 +54,7 @@ add_task(async function remove_action() {
ActionsProviderQuickActions.removeAction("testaction");
let context = createContext("test", {});
let result = await ActionsProviderQuickActions.queryAction(context);
let result = await ActionsProviderQuickActions.queryActions(context);
Assert.ok(result === null, "there were no matches");
});
@ -66,11 +66,11 @@ add_task(async function minimum_search_string() {
UrlbarPrefs.set("quickactions.minimumSearchString", minimumSearchString);
for (let i = 1; i < 4; i++) {
let context = createContext(searchString.substring(0, i), {});
let result = await ActionsProviderQuickActions.queryAction(context);
let result = await ActionsProviderQuickActions.queryActions(context);
let isActive = ActionsProviderQuickActions.isActive(context);
if (i >= minimumSearchString) {
Assert.ok(result.key == "newaction", "Matched the new action");
Assert.ok(result[0].key == "newaction", "Matched the new action");
Assert.equal(isActive, true, "Provider is active");
} else {
Assert.equal(isActive, false, "Provider is not active");

View File

@ -164,66 +164,14 @@
}
/**
* Quick actions
* Actions
*/
.urlbarView-dynamic-quickactions-buttons {
display: flex;
flex-grow: 1;
gap: 0.9em 1.8em;
max-width: 100%;
&[data-is-quickactions-searchmode] {
flex-wrap: wrap;
}
}
.urlbarView-quickaction-button {
font-size: var(--urlbarView-small-font-size);
font-weight: var(--font-weight-bold);
box-shadow: 0 0 1px rgba(128, 128, 142, 0.9), 0 0 4px rgba(128, 128, 142, 0.5);
border-radius: 4px;
display: flex;
padding: .5em;
margin-top: 2px;
position: relative;
overflow: hidden;
min-width: 16px;
&[disabled] {
opacity: var(--toolbarbutton-disabled-opacity);
}
&:hover:not([disabled]):not([selected]) {
background-color: var(--urlbarView-hover-background);
}
&[selected] {
background-color: var(--urlbarView-highlight-background);
color: var(--urlbarView-highlight-color);
}
> .urlbarView-label {
overflow: hidden;
text-overflow: ellipsis;
}
> .urlbarView-favicon {
display: flex;
align-items: center;
justify-content: center;
margin-inline: 0 .5em;
> .urlbarView-favicon-img {
width: 16px;
height: 16px;
}
}
}
.urlbarView-row[dynamicType=quickactions][label]::before {
top: -1em;
margin-inline-start: 6px;
.urlbarView-row[dynamicType=actions] > .urlbarView-row-inner {
/* Reduce the padding to 2px so the outline does not get
cropped and the actions + outline are aligned with the
rest of the results */
padding-inline: 2px;
}
/**

View File

@ -52,9 +52,8 @@
--urlbarView-labeled-row-label-top: calc(-1.27em - 2px);
--urlbarView-labeled-tip-margin-top-extra: 8px;
--urlbarView-action-button-background-color: light-dark(white, var(--color-gray-90));
--urlbarView-action-button-hover-color: light-dark(var(--color-gray-70), var(--color-gray-05));
--urlbarView-action-button-selected-color: light-dark(var(--color-gray-90), var(--urlbarView-action-button-background-color));
--urlbarView-action-button-background-color: color-mix(in srgb, var(--urlbarView-hover-background) 50%, transparent);
--urlbarView-action-button-hover-background-color: var(--urlbarView-hover-background);
&:-moz-locale-dir(rtl) {
--urlbarView-action-slide-in-distance: -200px;
@ -962,14 +961,14 @@
.urlbarView-action-btn {
font-size: smaller;
color: var(--toolbar-field-focus-color);
font-weight: var(--font-weight-bold);
border-radius: var(--toolbarbutton-border-radius);
border: 1px solid transparent;
padding: .4em .6em;
display: inline-flex;
align-items: center;
background-color: var(--urlbarView-action-button-background-color);
box-shadow: 0 0px 4px rgba(0, 0, 0, 0.23);
margin-inline-end: var(--space-large);
> img {
width: 16px;
@ -979,14 +978,12 @@
}
&:hover {
color: var(--urlbarView-result-button-hover-color);
background-color: var(--urlbarView-action-button-hover-color);
background-color: var(--urlbarView-action-button-hover-background-color);
}
&[selected] {
color: light-dark(var(--urlbarView-result-button-hover-color), var(--toolbar-field-focus-color));
background-color: var(--urlbarView-action-button-selected-color);
border-color: light-dark(transparent, white);
&[selected],
&:hover:active {
outline: var(--focus-outline);
}
&.urlbarView-userContext {