diff --git a/packages/app/component-tests/browser-pane-restore.spec.ts b/packages/app/component-tests/browser-pane-restore.spec.ts index ff87a96ac657..7bc627bf12e3 100644 --- a/packages/app/component-tests/browser-pane-restore.spec.ts +++ b/packages/app/component-tests/browser-pane-restore.spec.ts @@ -429,6 +429,45 @@ story("⌘T and ⌘W follow focus: side tabs inside the side panel, session tabs await expect(sessions).toHaveText("1") }) +story("⌘L selects the browser address from the page and the pane, and nowhere else", async ({ page }) => { + const root = page.getByTestId("browser-region-fixture") + const mod = (await page.evaluate(() => /Mac|iPhone|iPad|iPod/.test(navigator.platform))) ? "Meta" : "Control" + const outside = root.getByRole("button", { name: "Beta", exact: true }) + const address = root.getByRole("combobox", { name: "Browser address", exact: true }) + const editor = page.frameLocator('iframe[title="Browser page"]').getByRole("textbox", { name: "Editor page input" }) + + const selected = () => + address.evaluate( + (input: HTMLInputElement) => + document.activeElement === input && + input.value.length > 0 && + input.selectionStart === 0 && + input.selectionEnd === input.value.length, + ) + + await expect(root.getByText("Registrations: 1", { exact: true })).toBeVisible() + await outside.click() + await root.getByRole("button", { name: "First inventory", exact: true }).click() + await expect(root.getByTestId("selected")).toHaveText(/^browser:/) + + // In the main column ⌘L does not reach into the side panel. + await outside.focus() + await outside.press(`${mod}+l`) + await expect(address).not.toBeFocused() + + // A focused page hands ⌘L to the pane, as it does ⌘T and ⌘W, without typing it. + await editor.click() + await editor.press(`${mod}+l`) + await expect.poll(selected).toBe(true) + await expect(editor).not.toHaveValue(/l$/) + + // On the pane's own surface too. + await page.locator('#browser-panel [data-component="browser-bar"]').click({ position: { x: 2, y: 2 } }) + await expect(address).not.toBeFocused() + await page.keyboard.press(`${mod}+l`) + await expect.poll(selected).toBe(true) +}) + story("keeps ⌘T in the browser pane after a click on its loading surface", async ({ page }) => { const root = page.getByTestId("browser-region-fixture") const mod = (await page.evaluate(() => /Mac|iPhone|iPad|iPod/.test(navigator.platform))) ? "Meta" : "Control" diff --git a/packages/app/component-tests/browser-pane.spec.ts b/packages/app/component-tests/browser-pane.spec.ts index 6913e00c9b87..adf570dda0e9 100644 --- a/packages/app/component-tests/browser-pane.spec.ts +++ b/packages/app/component-tests/browser-pane.spec.ts @@ -535,14 +535,6 @@ story("adds the whole page to the session and keeps the draft when the button is await expect(root.getByTestId("fixture-comments").getByRole("listitem")).toHaveText([/: Check the header layout$/]) }) -story("focuses the address field when the page uses the address shortcut", async ({ page }) => { - const root = page.getByTestId("browser-pane-fixture") - await root.getByRole("button", { name: "Address shortcut", exact: true }).click() - const address = root.getByRole("combobox", { name: "Browser address", exact: true }) - await expect(address).toBeFocused() - await expect(address).toHaveJSProperty("selectionEnd", "https://alpha.example/".length) -}) - story("shows the page's cookies in the site information and clears them", async ({ page }) => { const root = page.getByTestId("browser-pane-fixture") await root.getByRole("button", { name: "Site information", exact: true }).click() diff --git a/packages/gui-extensions/src/browser/chromium.ts b/packages/gui-extensions/src/browser/chromium.ts index e40f2528a050..f4781261be19 100644 --- a/packages/gui-extensions/src/browser/chromium.ts +++ b/packages/gui-extensions/src/browser/chromium.ts @@ -136,8 +136,6 @@ export function createBrowserPage( detail?: (detail: PageDetail) => void /** The page's zoom changed, which Chromium applies to every page of the same origin in the partition. */ zoomed?: () => void - /** The user pressed the address shortcut while the page had focus. */ - address?: () => void /** Hands a browser or shell shortcut to the app window. */ shortcut?: (shortcut: PageShortcut) => void /** The page took keyboard focus. */ @@ -214,14 +212,6 @@ export function createBrowserPage( return } - // The system browser's address shortcut. The app's own focus moves to the address field. - if (!input.shift && pageLetter(input) === "l") { - event.preventDefault() - options.address?.() - - return - } - const direction = zoomKey(input) if (!direction) return diff --git a/packages/gui-extensions/src/browser/connection.test.ts b/packages/gui-extensions/src/browser/connection.test.ts index 0d0e21d754cb..945fcc9234bb 100644 --- a/packages/gui-extensions/src/browser/connection.test.ts +++ b/packages/gui-extensions/src/browser/connection.test.ts @@ -110,7 +110,6 @@ function fixture(strip: string[] = []) { preview: (path) => routed.preview.push(path), inspect: (event) => routed.inspect.push(event), page: () => undefined, - address: () => undefined, shortcut: () => undefined, focused: () => undefined, }) diff --git a/packages/gui-extensions/src/browser/connection.ts b/packages/gui-extensions/src/browser/connection.ts index e7628bfa4961..6773b28a4c30 100644 --- a/packages/gui-extensions/src/browser/connection.ts +++ b/packages/gui-extensions/src/browser/connection.ts @@ -58,8 +58,6 @@ export function createConnection(input: { inspect: (event: InspectEvent) => void /** A page's icon or zoom changed. */ page: (event: PageEvent) => void - /** The user pressed the address shortcut while the page had focus. */ - address: (tabID: Browser.TabID) => void /** A focused page handed a browser or shell shortcut to the window. */ shortcut: (event: ShortcutEvent) => void /** The user put keyboard focus in a page. */ @@ -162,8 +160,6 @@ export function createConnection(input: { if (event.type === "page") return input.page(event) - if (event.type === "address") return input.address(event.tabID) - if (event.type === "shortcut") return input.shortcut(event) if (event.type === "focused") return input.focused() diff --git a/packages/gui-extensions/src/browser/ipc.ts b/packages/gui-extensions/src/browser/ipc.ts index 79e10d850338..dbea6c2273d2 100644 --- a/packages/gui-extensions/src/browser/ipc.ts +++ b/packages/gui-extensions/src/browser/ipc.ts @@ -50,8 +50,6 @@ export const PaneEvent = Schema.Union([ icon: Schema.optionalKey(detail(MAX_ICON_URL).check(Schema.isStartingWith("data:image/"))), zoom: Schema.Finite.check(Schema.isBetween({ minimum: 0.25, maximum: 5 })), }), - // The page asked for the address field, with the platform's address shortcut. - Schema.Struct({ type: Schema.Literal("address"), tabID: Browser.TabID }), // The user put keyboard focus in the page, outside the window's own document. Schema.Struct({ type: Schema.Literal("focused"), tabID: Browser.TabID }), // The page handed a browser or shell shortcut to the window, which runs it as its own key press. diff --git a/packages/gui-extensions/src/browser/keys.test.ts b/packages/gui-extensions/src/browser/keys.test.ts index cf07909e6bba..323b76e6bda2 100644 --- a/packages/gui-extensions/src/browser/keys.test.ts +++ b/packages/gui-extensions/src/browser/keys.test.ts @@ -45,6 +45,10 @@ test("forwards browser and shell shortcuts while leaving page editing, find, rel ["mod", "w", true, "w"], ["mod", "w", false, "w"], ["mod", "\u0432", true, "w", "KeyW"], + // The address field, as in a browser. + ["mod", "l", true, "l"], + ["mod", "l", false, "l"], + ["mod", "l", true, "l", "KeyP"], ["mod", "n", true, "n"], ["mod", "n", false, "n"], ["mod", "1", true, "1"], @@ -98,7 +102,7 @@ test("forwards browser and shell shortcuts while leaving page editing, find, rel ["mod", "a", false, undefined], ["mod", "z", false, undefined], ["mod", "y", false, undefined], - // Find, reload, history, and the pane's own address, picker and zoom chords. + // Find, reload, history, and the pane's own picker and zoom chords. ["mod", "f", true, undefined], ["mod", "g", true, undefined], ["mod+shift", "G", true, undefined], @@ -106,7 +110,6 @@ test("forwards browser and shell shortcuts while leaving page editing, find, rel ["mod", "r", false, undefined], ["mod", "[", true, undefined], ["mod", "]", true, undefined], - ["mod", "l", true, undefined], ["mod+shift", "C", true, undefined], ["mod", "=", true, undefined], ["mod", "-", true, undefined], diff --git a/packages/gui-extensions/src/browser/keys.ts b/packages/gui-extensions/src/browser/keys.ts index ff9b39197c2d..2dfc6a0bdf31 100644 --- a/packages/gui-extensions/src/browser/keys.ts +++ b/packages/gui-extensions/src/browser/keys.ts @@ -11,8 +11,8 @@ export type PageShortcut = { } // Unshifted chords with the platform's modifier that belong to the app shell or browser pane rather than the page: -// opening, closing or switching tabs, opening settings, and toggling the file tree. -const shellKeys = ["t", "w", "n", "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", "\\"] +// opening, closing or switching tabs, focusing the address field, opening settings, and toggling the file tree. +const shellKeys = ["t", "w", "l", "n", "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", "\\"] // Shifted chords with the platform's modifier that belong to the app shell rather than the page: reopening a tab, // switching side-panel tabs, toggling the side panel, opening the command palette, or running session commands. New Window and Close Window diff --git a/packages/gui-extensions/src/browser/model.ts b/packages/gui-extensions/src/browser/model.ts index 04cc272b0cb0..1adde2c0b5fe 100644 --- a/packages/gui-extensions/src/browser/model.ts +++ b/packages/gui-extensions/src/browser/model.ts @@ -99,7 +99,6 @@ export function createModel(ctx: SetupContext) { const live = new Map() const listeners = new Map void>() const inspectors = new Map void>>() - const addressed = new Map void>>() // Sessions where the user just opened a tab; its pane focuses the address field once the blank page shows. const opening = new Set() // Each tab's last recorded page, so a state that repeats it does not write the history again. @@ -218,7 +217,6 @@ export function createModel(ctx: SetupContext) { if (visits) history.set({ visits }) }, - address: (tabID) => addressed.get(id)?.forEach((listener) => listener(tabID)), // Only the pane on screen holds the page that had focus. shortcut: (event) => { if (sessions.current()?.key === id) panes()[0]?.press(event) @@ -498,18 +496,6 @@ export function createModel(ctx: SetupContext) { recorded.clear() history.set({ visits: [] }) }, - /** The page asking for the address field with its shortcut. */ - onAddress(session: Session, listener: (tabID: Browser.TabID) => void) { - const set = addressed.get(session.key) ?? new Set() - set.add(listener) - addressed.set(session.key, set) - - return () => { - set.delete(listener) - - if (!set.size) addressed.delete(session.key) - } - }, pending, /** * Tab IDs to list in the side panel: the desktop's inventory, limited to tabs stored in the strip. Until the first diff --git a/packages/gui-extensions/src/browser/pane.ts b/packages/gui-extensions/src/browser/pane.ts index 5cc16b581d95..fb263be4b3de 100644 --- a/packages/gui-extensions/src/browser/pane.ts +++ b/packages/gui-extensions/src/browser/pane.ts @@ -504,16 +504,10 @@ export function createBrowserPane(input: { if (entry.pages.has(id)) report(entry, { type: "page", tabID: id, ...value }) }, zoomed: () => entry.pages.forEach((page) => page.detail()), - address: () => { - if (!entry.pages.has(id) || entry.win.isDestroyed()) return - // The page held keyboard focus; the app's address field needs it back. - entry.win.webContents.focus() - publish(entry, { type: "address", tabID: id }) - }, shortcut: (shortcut) => { if (!entry.pages.has(id) || entry.focusedTabID !== id || entry.win.isDestroyed()) return - // As for the address shortcut: the command runs in the app, which may move focus there. + // The page held keyboard focus; the command runs in the app, which may move focus there, as ⌘L does. if (entry.win.isFocused()) entry.win.webContents.focus() publish(entry, { type: "shortcut", ...shortcut }) }, diff --git a/packages/gui-extensions/src/browser/panel.fixture.tsx b/packages/gui-extensions/src/browser/panel.fixture.tsx index 62548c980c08..6cf2f72ea458 100644 --- a/packages/gui-extensions/src/browser/panel.fixture.tsx +++ b/packages/gui-extensions/src/browser/panel.fixture.tsx @@ -495,9 +495,6 @@ export function mountBrowserPane(input: PaneHost) { -

Captures: {store.captures}

Zoom: {Math.round(store.zoom * 100)}

diff --git a/packages/gui-extensions/src/browser/panel.tsx b/packages/gui-extensions/src/browser/panel.tsx index 8beb81a79846..aac710adcec0 100644 --- a/packages/gui-extensions/src/browser/panel.tsx +++ b/packages/gui-extensions/src/browser/panel.tsx @@ -451,17 +451,6 @@ export default function SessionBrowserPane(props: { ), ) - // The page's address shortcut moves focus to this field when the page is the one on screen. - createKeyed( - () => props.session.key, - (sessionKey) => - onCleanup( - props.model.onAddress({ key: sessionKey }, (tabID) => { - if (tabID === state()?.id && visible()) focusAddress() - }), - ), - ) - // A tab the user just opened starts in its address field, once its blank page is on screen. Syncs DOM focus. createKeyed( () => (visible() && empty() ? state()?.id : undefined), diff --git a/packages/gui-extensions/src/browser/renderer.tsx b/packages/gui-extensions/src/browser/renderer.tsx index 6a9dc452c31f..2d7d6c95afcc 100644 --- a/packages/gui-extensions/src/browser/renderer.tsx +++ b/packages/gui-extensions/src/browser/renderer.tsx @@ -92,8 +92,8 @@ const setup: Setup = (ctx) => { } }) - // The system browser's address shortcut. While the page has focus, the page claims it and main forwards it; here it - // covers focus elsewhere in the pane. Ctrl+L focuses the composer outside the pane on Windows and Linux. + // The system browser's address shortcut, in the pane and, forwarded like mod+t and mod+w, from a page with focus. + // Ctrl+L focuses the composer outside the pane on Windows and Linux. ctx.add(Command, (): Command | undefined => { const pane = model()?.pane()