commit 8e7e26472b2441bd235c6c4bff463f9e43cb5866
parent 91433997c262acd9e848fe87ab47d96ee767a41b
Author: Florian Zia <fzia@mozilla.com>
Date: Fri, 2 Jan 2026 21:57:26 +0000
Bug 2003063 - Part 2: Add a new mode to SmartBar r=mak,frontend-codestyle-reviewers,urlbar-reviewers,ai-frontend-reviewers,Standard8
Adds a smartbar mode with the initial multiline editor support. The flag #isSmarbarMode and early returns serve as safety guards for addressbar specific behaviour until we get to merge back together with UrlbarInput.
Differential Revision: https://phabricator.services.mozilla.com/D276133
Diffstat:
11 files changed, 341 insertions(+), 45 deletions(-)
diff --git a/browser/base/content/browser-main.js b/browser/base/content/browser-main.js
@@ -32,6 +32,9 @@
Services.scriptloader.loadSubScript("chrome://browser/content/places/places-menupopup.js", this);
Services.scriptloader.loadSubScript("chrome://browser/content/search/autocomplete-popup.js", this);
Services.scriptloader.loadSubScript("chrome://browser/content/search/searchbar.js", this);
+ if (AIWindow.isOpeningAIWindow(window)) {
+ ChromeUtils.importESModule("chrome://browser/content/urlbar/SmartbarInput.mjs", { global: "current" });
+ }
ChromeUtils.importESModule("chrome://browser/content/urlbar/UrlbarInput.mjs", { global: "current" });
}
diff --git a/browser/components/aiwindow/ui/modules/AIWindow.sys.mjs b/browser/components/aiwindow/ui/modules/AIWindow.sys.mjs
@@ -102,7 +102,7 @@ export const AIWindow = {
/**
* Is current window an AI Window
*
- * @param {object} win current Window
+ * @param {Window} win current Window
* @returns {boolean} whether current Window is an AI Window
*/
isAIWindowActive(win) {
@@ -123,6 +123,21 @@ export const AIWindow = {
},
/**
+ * Check if window is being opened as an AI Window.
+ *
+ * @param {Window} win - The window to check
+ * @returns {boolean} whether the window is being opened as an AI Window
+ */
+ isOpeningAIWindow(win) {
+ const windowArgs = win?.arguments?.[1];
+ if (!(windowArgs instanceof Ci.nsIPropertyBag2)) {
+ return false;
+ }
+
+ return windowArgs.hasKey("ai-window");
+ },
+
+ /**
* Is AI Window content page active
*
* @param {nsIURI} uri current URI
diff --git a/browser/components/genai/content/smart-assist.mjs b/browser/components/genai/content/smart-assist.mjs
@@ -305,6 +305,28 @@ export class SmartAssist extends MozLitElement {
}
}
+ /**
+ * Helper method to get or create the smartbar element
+ *
+ * @param {Document} chromeDoc - The chrome document
+ * @param {Element} box - The container element
+ */
+ _getOrCreateSmartbar(chromeDoc, box) {
+ // Find existing Smartbar, or create it the first time we open the sidebar.
+ let smartbar = chromeDoc.getElementById("ai-window-smartbar");
+
+ if (!smartbar) {
+ smartbar = chromeDoc.createElement("moz-smartbar");
+ smartbar.id = "ai-window-smartbar";
+ smartbar.setAttribute("sap-name", "smartbar");
+ smartbar.setAttribute("pageproxystate", "invalid");
+ smartbar.setAttribute("popover", "manual");
+ smartbar.classList.add("smartbar", "urlbar");
+ box.append(smartbar);
+ }
+ return smartbar;
+ }
+
_toggleAIWindowSidebar() {
const chromeDoc = this._getChromeDocument();
const box = chromeDoc.getElementById("ai-window-box");
@@ -315,6 +337,7 @@ export class SmartAssist extends MozLitElement {
}
this._getOrCreateBrowser(chromeDoc, box);
+ this._getOrCreateSmartbar(chromeDoc, box);
// Toggle visibility
const opening = box.hidden;
diff --git a/browser/components/urlbar/content/SmartbarInput.mjs b/browser/components/urlbar/content/SmartbarInput.mjs
@@ -12,6 +12,7 @@ const { AppConstants } = ChromeUtils.importESModule(
/**
* @import {UrlbarSearchOneOffs} from "moz-src:///browser/components/urlbar/UrlbarSearchOneOffs.sys.mjs"
+ * @import {SmartbarInputController} from "chrome://browser/content/urlbar/SmartbarInputController.mjs"
*/
const lazy = XPCOMUtils.declareLazy({
@@ -31,6 +32,8 @@ const lazy = XPCOMUtils.declareLazy({
"moz-src:///browser/components/urlbar/SearchModeSwitcher.sys.mjs",
SearchUIUtils: "moz-src:///browser/components/search/SearchUIUtils.sys.mjs",
SearchUtils: "moz-src:///toolkit/components/search/SearchUtils.sys.mjs",
+ SmartbarInputController:
+ "chrome://browser/content/urlbar/SmartbarInputController.mjs",
UrlbarController:
"moz-src:///browser/components/urlbar/UrlbarController.sys.mjs",
UrlbarEventBufferer:
@@ -65,7 +68,11 @@ const lazy = XPCOMUtils.declareLazy({
pref: "privacy.query_stripping.strip_on_share.enabled",
default: false,
},
- logger: () => lazy.UrlbarUtils.getLogger({ prefix: "Input" }),
+ createEditor: () =>
+ ChromeUtils.importESModule(
+ "chrome://browser/content/urlbar/SmartbarInputUtils.mjs"
+ ).createEditor,
+ logger: () => lazy.UrlbarUtils.getLogger({ prefix: "SmartbarInput" }),
});
const UNLIMITED_MAX_RESULTS = 99;
@@ -77,7 +84,7 @@ let px = number => number.toFixed(2) + "px";
/**
* Implements the text input part of the address bar UI.
*/
-export class UrlbarInput extends HTMLElement {
+export class SmartbarInput extends HTMLElement {
static get #markup() {
return `
<hbox class="urlbar-background"/>
@@ -156,17 +163,6 @@ export class UrlbarInput extends HTMLElement {
</vbox>`;
}
- /** @type {DocumentFragment} */
- static get fragment() {
- if (!UrlbarInput.#fragment) {
- UrlbarInput.#fragment = window.MozXULElement.parseXULToFragment(
- UrlbarInput.#markup
- );
- }
- // @ts-ignore
- return document.importNode(UrlbarInput.#fragment, true);
- }
-
/**
* @type {DocumentFragment=}
*
@@ -174,6 +170,15 @@ export class UrlbarInput extends HTMLElement {
*/
static #fragment;
+ /** @type {DocumentFragment} */
+ static get fragment() {
+ if (!this.#fragment) {
+ this.#fragment = window.MozXULElement.parseXULToFragment(this.#markup);
+ }
+ // @ts-ignore
+ return document.importNode(this.#fragment, true);
+ }
+
static #inputFieldEvents = [
"compositionstart",
"compositionend",
@@ -200,7 +205,19 @@ export class UrlbarInput extends HTMLElement {
#gBrowserListenersAdded = false;
#breakoutBlockerCount = 0;
#isAddressbar = false;
+ /**
+ * `True` if this instance is in `smartbar` mode.
+ *
+ * Smartbar mode is enabled by adding the attribute `sap-name="smartbar"`.
+ * Both `#isSmartbarMode` and `#isAddressbar` are `false` if `sap-name` is neither
+ * `smartbar` nor `urlbar`.
+ */
+ #isSmartbarMode = false;
#sapName = "";
+ /** @type {object | null} */
+ #smartbarEditor = null;
+ /** @type {SmartbarEditorController | null} */
+ #smartbarEditorController = null;
_userTypedValue = "";
_actionOverrideKeyCount = 0;
_lastValidURLStr = "";
@@ -277,6 +294,7 @@ export class UrlbarInput extends HTMLElement {
#initOnce() {
this.#sapName = this.getAttribute("sap-name");
this.#isAddressbar = this.#sapName == "urlbar";
+ this.#isSmartbarMode = this.#sapName == "smartbar";
// This listener must be added before connecting the fragment
// because the event could fire while or after connecting it.
@@ -285,7 +303,7 @@ export class UrlbarInput extends HTMLElement {
this.#onContextMenuRebuilt.bind(this)
);
- this.appendChild(UrlbarInput.fragment);
+ this.appendChild(SmartbarInput.fragment);
// Make sure all children have been parsed before calling #populateSlots.
if (document.readyState === "loading") {
@@ -302,6 +320,9 @@ export class UrlbarInput extends HTMLElement {
this.inputField = /** @type {HTMLInputElement} */ (
this.querySelector(".urlbar-input")
);
+ if (this.#isSmartbarMode) {
+ this.#ensureSmartbarEditor();
+ }
this._inputContainer = this.querySelector(".urlbar-input-container");
this.controller = new lazy.UrlbarController({ input: this });
@@ -373,7 +394,7 @@ export class UrlbarInput extends HTMLElement {
this._initCopyCutController();
- for (let event of UrlbarInput.#inputFieldEvents) {
+ for (let event of SmartbarInput.#inputFieldEvents) {
this.inputField.addEventListener(event, this);
}
@@ -460,7 +481,7 @@ export class UrlbarInput extends HTMLElement {
delete this._copyCutController;
}
- for (let event of UrlbarInput.#inputFieldEvents) {
+ for (let event of SmartbarInput.#inputFieldEvents) {
this.inputField.removeEventListener(event, this);
}
@@ -515,6 +536,10 @@ export class UrlbarInput extends HTMLElement {
}
addGBrowserListeners() {
+ // The following listeners are only used for the address bar.
+ if (!this.#isAddressbar) {
+ return;
+ }
if (this.window.gBrowser && !this.#gBrowserListenersAdded) {
this.window.gBrowser.tabContainer.addEventListener("TabSelect", this);
this.window.gBrowser.tabContainer.addEventListener("TabClose", this);
@@ -523,6 +548,23 @@ export class UrlbarInput extends HTMLElement {
}
}
+ #initSmartbarEditor() {
+ const adapter = lazy.createEditor(this.inputField);
+ if (!adapter) {
+ return;
+ }
+ this.#smartbarEditorController = new lazy.SmartbarInputController(adapter);
+ this.inputField = adapter.input;
+ this.#smartbarEditor = adapter.editor;
+ }
+
+ #ensureSmartbarEditor() {
+ if (!this.#smartbarEditorController) {
+ this.#initSmartbarEditor();
+ }
+ return this.#smartbarEditor;
+ }
+
#lazy = XPCOMUtils.declareLazy({
valueFormatter: () => new lazy.UrlbarValueFormatter(this),
addSearchEngineHelper: () => new AddSearchEngineHelper(this),
@@ -536,7 +578,7 @@ export class UrlbarInput extends HTMLElement {
}
/**
- * The search access point name of the UrlbarInput for use with telemetry or
+ * The search access point name of the SmartbarInput for use with telemetry or
* logging, e.g. `urlbar`, `searchbar`.
*/
get sapName() {
@@ -707,7 +749,7 @@ export class UrlbarInput extends HTMLElement {
} = {}) {
if (!this.#isAddressbar) {
throw new Error(
- "Cannot set URI for UrlbarInput that is not an address bar"
+ "Cannot set URI for SmartbarInput that is not an address bar"
);
}
// We only need to update the searchModeUI on tab switch conditionally
@@ -950,10 +992,10 @@ export class UrlbarInput extends HTMLElement {
try {
this[methodName](event);
} catch (e) {
- console.error(`Error calling UrlbarInput::${methodName}:`, e);
+ console.error(`Error calling SmartbarInput::${methodName}:`, e);
}
} else {
- throw new Error("Unrecognized UrlbarInput event: " + event.type);
+ throw new Error("Unrecognized SmartbarInput event: " + event.type);
}
}
@@ -1017,6 +1059,20 @@ export class UrlbarInput extends HTMLElement {
* The principal that the action was triggered from.
*/
handleNavigation({ event, oneOffParams, triggeringPrincipal }) {
+ if (this.#isSmartbarMode) {
+ const committedValue = this.untrimmedValue;
+ lazy.logger.debug(`commit: ${committedValue}`);
+ this.#clearSmartbarInput();
+ this.dispatchEvent(
+ new CustomEvent("smartbar-commit", {
+ detail: { value: committedValue, event },
+ })
+ );
+ if (!this.window.gBrowser) {
+ return;
+ }
+ // Fall through to default navigation behaviour.
+ }
let element = this.view.selectedElement;
let result = this.view.getResultFromElement(element);
let openParams = oneOffParams?.openParams || { triggeringPrincipal };
@@ -1259,6 +1315,9 @@ export class UrlbarInput extends HTMLElement {
}
maybeHandleRevertFromPopup(anchorElement) {
+ if (!this.#isAddressbar) {
+ return;
+ }
let state = this.getBrowserState(this.window.gBrowser.selectedBrowser);
if (anchorElement?.closest("#urlbar") && state.persist?.shouldPersist) {
this.handleRevert();
@@ -1768,6 +1827,15 @@ export class UrlbarInput extends HTMLElement {
);
}
+ #clearSmartbarInput() {
+ this.value = "";
+ this.userTypedValue = "";
+ this._lastSearchString = "";
+ this._autofillPlaceholder = null;
+ this._resultForCurrentValue = null;
+ this.setSelectionRange(0, 0);
+ }
+
/**
* Called by the view when moving through results with the keyboard, and when
* picking a result. This sets the input value to the value of the result and
@@ -2262,7 +2330,6 @@ export class UrlbarInput extends HTMLElement {
*
* @param {MozBrowser} browser
* The search mode for this browser will be returned.
- * Pass the selected browser for the searchbar.
* @param {boolean} [confirmedOnly]
* Normally, if the browser has both preview and confirmed modes, preview
* mode will be returned since it takes precedence. If this argument is
@@ -2310,6 +2377,9 @@ export class UrlbarInput extends HTMLElement {
* Pass the selected browser for the searchbar.
*/
async setSearchMode(searchMode, browser) {
+ if (this.#isSmartbarMode) {
+ return;
+ }
let currentSearchMode = this.getSearchMode(browser);
let areSearchModesSame =
(!currentSearchMode && !searchMode) ||
@@ -2447,9 +2517,11 @@ export class UrlbarInput extends HTMLElement {
* Restores the current browser search mode from a previously stored state.
*/
restoreSearchModeState() {
- this.searchMode = this.#getSearchModesObject(
- this.window.gBrowser.selectedBrowser
- ).confirmed;
+ if (this.#isSmartbarMode) {
+ return;
+ }
+ let state = this.getBrowserState(this.window.gBrowser.selectedBrowser);
+ this.searchMode = state.searchModes?.confirmed;
}
/**
@@ -2489,6 +2561,9 @@ export class UrlbarInput extends HTMLElement {
// Getters and Setters below.
get editor() {
+ if (this.#isSmartbarMode) {
+ return this.#ensureSmartbarEditor();
+ }
return this.inputField.editor;
}
@@ -2531,6 +2606,9 @@ export class UrlbarInput extends HTMLElement {
}
get searchMode() {
+ if (this.#isSmartbarMode) {
+ return null;
+ }
if (!this.window.gBrowser) {
// This only happens before DOMContentLoaded.
return null;
@@ -2539,6 +2617,9 @@ export class UrlbarInput extends HTMLElement {
}
set searchMode(searchMode) {
+ if (this.#isSmartbarMode) {
+ return;
+ }
this.setSearchMode(searchMode, this.window.gBrowser.selectedBrowser);
this.searchModeSwitcher?.onSearchModeChanged();
lazy.UrlbarSearchTermsPersistence.onSearchModeChanged(this.window);
@@ -2634,6 +2715,9 @@ export class UrlbarInput extends HTMLElement {
updatePopupNotifications,
forceUnifiedSearchButtonAvailable = false
) {
+ if (!this.#isAddressbar) {
+ return;
+ }
let prevState = this.getAttribute("pageproxystate");
this.setAttribute("pageproxystate", state);
@@ -3607,6 +3691,10 @@ export class UrlbarInput extends HTMLElement {
// beginning. Do not allow it to be trimmed.
this._setValue(value, { untrimmedValue });
this.inputField.setSelectionRange(selectionStart, selectionEnd);
+ // Ensure selection state is cached for contenteditable and events fire.
+ this.inputField.dispatchEvent(
+ new Event("selectionchange", { bubbles: true, cancelable: false })
+ );
this._autofillPlaceholder = {
value,
type,
@@ -3916,6 +4004,10 @@ export class UrlbarInput extends HTMLElement {
}
_initCopyCutController() {
+ // Clipboard handling is managed by the multiline editor in smartbar mode.
+ if (this.#isSmartbarMode) {
+ return;
+ }
if (this._copyCutController) {
return;
}
@@ -4366,6 +4458,9 @@ export class UrlbarInput extends HTMLElement {
isSameDocument,
uri,
}) {
+ if (!this.#isAddressbar) {
+ return false;
+ }
if (!lazy.UrlbarPrefs.isPersistedSearchTermsEnabled()) {
if (state.persist) {
this.removeAttribute("persistsearchterms");
@@ -4516,6 +4611,9 @@ export class UrlbarInput extends HTMLElement {
* @param {boolean} available If true Unified Search Button will be available.
*/
setUnifiedSearchButtonAvailability(available) {
+ if (this.#isSmartbarMode) {
+ return;
+ }
this.toggleAttribute("unifiedsearchbutton-available", available);
this.getBrowserState(
this.window.gBrowser.selectedBrowser
@@ -4940,19 +5038,21 @@ export class UrlbarInput extends HTMLElement {
this.setPageProxyState("invalid", true);
}
- let state = this.getBrowserState(this.window.gBrowser.selectedBrowser);
- if (
- state.persist?.shouldPersist &&
- this.value !== state.persist.searchTerms
- ) {
- state.persist.shouldPersist = false;
- this.removeAttribute("persistsearchterms");
+ if (this.#isAddressbar) {
+ let state = this.getBrowserState(this.window.gBrowser.selectedBrowser);
+ if (
+ state.persist?.shouldPersist &&
+ this.value !== state.persist.searchTerms
+ ) {
+ state.persist.shouldPersist = false;
+ this.removeAttribute("persistsearchterms");
+ }
}
if (this.view.isOpen) {
if (lazy.UrlbarPrefs.get("closeOtherPanelsOnOpen")) {
- // UrlbarView rolls up all popups when it opens, but we should
- // do the same for UrlbarInput when it's already open in case
+ // SmartbarView rolls up all popups when it opens, but we should
+ // do the same for SmartbarInput when it's already open in case
// a tab preview was opened
this.window.docShell.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
@@ -5208,11 +5308,6 @@ export class UrlbarInput extends HTMLElement {
sapName: this.sapName,
maxResults,
searchString,
- userContextId: parseInt(
- this.window.gBrowser.selectedBrowser.getAttribute("usercontextid") || 0
- ),
- tabGroup: this.window.gBrowser.selectedTab.group?.id ?? null,
- currentPage: this.window.gBrowser.currentURI.spec,
prohibitRemoteResults:
event &&
lazy.UrlbarUtils.isPasteEvent(event) &&
@@ -5220,6 +5315,15 @@ export class UrlbarInput extends HTMLElement {
event.data?.length,
};
+ // Only add gBrowser-dependent properties if gBrowser exists.
+ if (this.window.gBrowser) {
+ options.userContextId = parseInt(
+ this.window.gBrowser.selectedBrowser?.getAttribute("usercontextid") ?? 0
+ );
+ options.tabGroup = this.window.gBrowser.selectedTab.group?.id ?? null;
+ options.currentPage = this.window.gBrowser.currentURI?.spec ?? "";
+ }
+
if (this.searchMode) {
options.searchMode = this.searchMode;
if (this.searchMode.source) {
@@ -5784,8 +5888,8 @@ function losslessDecodeURI(aURI) {
*/
class CopyCutController {
/**
- * @param {UrlbarInput} urlbar
- * The UrlbarInput instance to use this controller for.
+ * @param {SmartbarInput} urlbar
+ * The SmartbarInput instance to use this controller for.
*/
constructor(urlbar) {
this.urlbar = urlbar;
@@ -5868,7 +5972,7 @@ class AddSearchEngineHelper {
shortcutButtons;
/**
- * @param {UrlbarInput} input The parent UrlbarInput.
+ * @param {SmartbarInput} input The parent SmartbarInput.
*/
constructor(input) {
this.input = input;
@@ -6007,4 +6111,4 @@ class AddSearchEngineHelper {
}
}
-customElements.define("moz-urlbar", UrlbarInput);
+customElements.define("moz-smartbar", SmartbarInput);
diff --git a/browser/components/urlbar/content/SmartbarInputController.mjs b/browser/components/urlbar/content/SmartbarInputController.mjs
@@ -0,0 +1,34 @@
+/* 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/. */
+
+/**
+ * Controller for the Smartbar editor.
+ *
+ * The controller abstracts the underlying editor implementation allowing
+ * the Smartbar to also work with a standard HTML input.
+ *
+ * @property {Element} input - The input element or object.
+ * @property {object} editor - The editor object.
+ * @property {object} adapter - The adapter providing input and editor references.
+ * @property {boolean} readOnly - Whether the input is read-only.
+ * @property {string} placeholder - The placeholder text.
+ * @property {string} value - The current value of the input.
+ * @property {number} selectionStart - The start offset of the selection.
+ * @property {number} selectionEnd - The end offset of the selection.
+ * @property {boolean} composing - Whether the editor is in composition mode.
+ * @property {number} selectionRangeCount - The number of selection ranges.
+ */
+class SmartbarInputController {
+ constructor(adapter) {
+ this.adapter = adapter;
+ this.input = adapter?.input ?? null;
+ this.editor = adapter?.editor ?? null;
+ }
+
+ focus() {
+ this.input?.focus();
+ }
+}
+
+export { SmartbarInputController };
diff --git a/browser/components/urlbar/content/SmartbarInputUtils.mjs b/browser/components/urlbar/content/SmartbarInputUtils.mjs
@@ -0,0 +1,87 @@
+/* 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/. */
+
+import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
+
+/**
+ * Minimal multiline editor placeholder for SmartBarInput.
+ */
+class SmartbarEditor extends MozLitElement {
+ createRenderRoot() {
+ return this;
+ }
+
+ get value() {
+ return this.textContent ?? "";
+ }
+
+ set value(val) {
+ this.textContent = val ?? "";
+ }
+
+ initializeFromInput(inputElement) {
+ if (!inputElement) {
+ return null;
+ }
+
+ // Copy existing input attributes.
+ for (const inputAttribute of inputElement.attributes) {
+ this.setAttribute(inputAttribute.name, inputAttribute.value);
+ }
+
+ this.setAttribute("contenteditable", "true");
+ this.setAttribute("aria-multiline", "true");
+ this.removeAttribute("type");
+ this.removeAttribute("value");
+ this.className = inputElement.className;
+ this.textContent = inputElement.value ?? "";
+
+ inputElement.replaceWith(this);
+ return { input: this, editor: createEditorAdapter(this) };
+ }
+}
+
+function createEditor(inputElement) {
+ if (!inputElement) {
+ return null;
+ }
+ if (inputElement.localName == "moz-smartbar-editor") {
+ return {
+ input: inputElement,
+ editor: createEditorAdapter(inputElement),
+ };
+ }
+ const host = inputElement.ownerDocument.createElement("moz-smartbar-editor");
+ return host.initializeFromInput(inputElement);
+}
+
+// Adapter for Smartbar editor element.
+function createEditorAdapter(editorElement) {
+ return {
+ get composing() {
+ return false;
+ },
+ selection: {
+ get rangeCount() {
+ const selection = editorElement.ownerGlobal.getSelection();
+ return selection?.rangeCount ?? 0;
+ },
+ toStringWithFormat() {
+ const selection = editorElement.ownerGlobal.getSelection();
+ if (
+ !selection ||
+ !selection.rangeCount ||
+ !editorElement.contains(selection.anchorNode)
+ ) {
+ return "";
+ }
+ return selection.toString();
+ },
+ },
+ };
+}
+
+customElements.define("moz-smartbar-editor", SmartbarEditor);
+
+export { createEditor, createEditorAdapter };
diff --git a/browser/components/urlbar/jar.mn b/browser/components/urlbar/jar.mn
@@ -3,5 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
browser.jar:
- content/browser/urlbar/SmartbarInput.mjs (content/SmartbarInput.mjs)
- content/browser/urlbar/UrlbarInput.mjs (content/UrlbarInput.mjs)
+ content/browser/urlbar/SmartbarInput.mjs (content/SmartbarInput.mjs)
+ content/browser/urlbar/SmartbarInputController.mjs (content/SmartbarInputController.mjs)
+ content/browser/urlbar/SmartbarInputUtils.mjs (content/SmartbarInputUtils.mjs)
+ content/browser/urlbar/UrlbarInput.mjs (content/UrlbarInput.mjs)
diff --git a/browser/themes/shared/browser-shared.css b/browser/themes/shared/browser-shared.css
@@ -24,6 +24,7 @@
@import url("chrome://browser/skin/places/editBookmarkPanel.css");
@import url("chrome://browser/skin/searchbar.css");
@import url("chrome://browser/skin/sidebar.css");
+@import url("chrome://browser/skin/smartbar.css");
@import url("chrome://browser/skin/aiWindowSidebar.css");
@import url("chrome://browser/skin/customizableui/customizeMode.css");
@import url("chrome://browser/skin/UITour.css");
diff --git a/browser/themes/shared/jar.inc.mn b/browser/themes/shared/jar.inc.mn
@@ -27,6 +27,7 @@
skin/classic/browser/sanitizeDialog_v2.css (../shared/sanitizeDialog_v2.css)
skin/classic/browser/setDesktopBackground.css (../shared/setDesktopBackground.css)
skin/classic/browser/sidebar.css (../shared/sidebar.css)
+ skin/classic/browser/smartbar.css (../shared/smartbar.css)
skin/classic/browser/toolbarbuttons.css (../shared/toolbarbuttons.css)
skin/classic/browser/toolbarbutton-icons.css (../shared/toolbarbutton-icons.css)
skin/classic/browser/urlbar/flight-airline.svg (../shared/urlbar/flight-airline.svg)
diff --git a/browser/themes/shared/smartbar.css b/browser/themes/shared/smartbar.css
@@ -0,0 +1,25 @@
+/* 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/. */
+
+.smartbar {
+ --smartbar-min-height: var(--urlbar-min-height);
+ bottom: 0;
+ display: block;
+ height: auto;
+ min-height: var(--smartbar-min-height);
+ position: absolute;
+ width: 100%;
+}
+
+.smartbar .urlbar-input-box {
+ align-items: stretch;
+}
+
+.smartbar .urlbar-input {
+ box-sizing: border-box;
+ height: auto;
+ min-height: var(--smartbar-min-height);
+ white-space: pre-wrap;
+ width: 100%;
+}
diff --git a/stylelint-rollouts.config.js b/stylelint-rollouts.config.js
@@ -171,6 +171,7 @@ module.exports = [
"browser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css",
"browser/themes/shared/search/searchbar.css",
"browser/themes/shared/sidebar.css",
+ "browser/themes/shared/smartbar.css",
"browser/themes/shared/syncedtabs/sidebar.css",
"browser/themes/shared/tab-list-tree.css",
"browser/themes/shared/tabbrowser/content-area.css",