From a91a6fa10ec87ad0a5e2abd4aaef16aadf54c9dd Mon Sep 17 00:00:00 2001 From: Amit Singh Date: Sun, 12 Jul 2026 10:01:22 +0530 Subject: [PATCH 1/3] fix(extension): restore Cmd+S save and title caret in bookmarks - Pass empty tagsToIgnore to the bookmarks header useHotkeys so mod+S fires even when focus is in an input (restores pre-mantine behavior) - Place the caret at the start of the title input when the add/edit bookmark modal opens via base-ui initialFocus - Add e2e tests reproducing both bugs Fixes #4064 Co-Authored-By: Claude Opus 4.8 --- .../components/BookmarkAddEditDialog.tsx | 20 +++++++++- .../components/BookmarksHeader.tsx | 23 ++++++----- apps/extension/tests/specs/bookmarks.spec.ts | 40 +++++++++++++++++++ 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/apps/extension/src/entrypoints/popup/panels/BookmarksPanel/components/BookmarkAddEditDialog.tsx b/apps/extension/src/entrypoints/popup/panels/BookmarksPanel/components/BookmarkAddEditDialog.tsx index 81a04c408..f05d3bc38 100644 --- a/apps/extension/src/entrypoints/popup/panels/BookmarksPanel/components/BookmarkAddEditDialog.tsx +++ b/apps/extension/src/entrypoints/popup/panels/BookmarksPanel/components/BookmarkAddEditDialog.tsx @@ -1,7 +1,7 @@ import { z } from 'zod/mini'; import { useForm } from '@tanstack/react-form'; import { useDisclosure } from '@mantine/hooks'; -import { useCallback, useEffect, useMemo } from 'react'; +import { useCallback, useEffect, useMemo, useRef } from 'react'; import { useLocation } from 'wouter'; import { useShallow } from 'zustand/react/shallow'; import { @@ -80,6 +80,17 @@ function BookmarkAddEditDialog({ curFolderId, handleScroll }: Props) { ); const { operation, url: bmUrl } = bookmarkOperation; const [openDialog, dialogHandlers] = useDisclosure(false); + const titleInputRef = useRef(null); + + const focusCaretAtTitleStart = () => { + const input = titleInputRef.current; + if (!input) { + return true; // fallback to default focus behavior + } + input.focus(); + input.setSelectionRange(0, 0); + return false; // focus already handled; don't let base-ui override it + }; const { folderOptions, defaultFolderId } = useMemo(() => { const decodedFolderList = getDecodedFolderList(folderList); @@ -189,7 +200,11 @@ function BookmarkAddEditDialog({ curFolderId, handleScroll }: Props) { return ( - + {HEADING[operation]} @@ -208,6 +223,7 @@ function BookmarkAddEditDialog({ curFolderId, handleScroll }: Props) { Title * { - e.preventDefault(); - e.stopPropagation(); - if (!disableSave) { - handleSaveClick(); - } - }, + [ + 'mod+S', + (e) => { + e.preventDefault(); + e.stopPropagation(); + if (!disableSave) { + handleSaveClick(); + } + }, + ], ], - ]); + [] // fire even when focus is inside an input + ); const onBackClick = () => { if (isSaveButtonActive) { diff --git a/apps/extension/tests/specs/bookmarks.spec.ts b/apps/extension/tests/specs/bookmarks.spec.ts index 100ecaa7d..cc587ed4b 100644 --- a/apps/extension/tests/specs/bookmarks.spec.ts +++ b/apps/extension/tests/specs/bookmarks.spec.ts @@ -91,6 +91,28 @@ test.describe('Bookmarks Panel', () => { await expect(dialog).toBeHidden(); }); + test('should focus the title input with caret at start when opening the edit modal', async ({ + bookmarksPage, + }) => { + const panel = new BookmarksPanel(bookmarksPage); + await panel.ensureAtRoot(); + + const dialog = await panel.openEditBookmarkDialog( + TEST_BOOKMARKS.REACT_DOCS + ); + const titleInput = dialog.getByTestId('bookmark-title-input'); + await expect(titleInput).toBeFocused(); + + const selection = await titleInput.evaluate((el) => ({ + start: (el as HTMLInputElement).selectionStart, + end: (el as HTMLInputElement).selectionEnd, + })); + expect(selection.start).toBe(0); + expect(selection.end).toBe(0); + + await panel.closeDialog(); + }); + test('should add and remove person tag from bookmark', async ({ bookmarksPage, }) => { @@ -420,4 +442,22 @@ test.describe('Bookmarks Panel', () => { await panel.verifyFolderNotExists(folderName); }); + + test('should save via Cmd+S while focus is in the search input', async ({ + bookmarksPage, + }) => { + const panel = new BookmarksPanel(bookmarksPage); + await panel.ensureAtRoot(); + + // Create a pending change so the Save button is active + await panel.createFolder('Cmd S Save Test Folder'); + + const search = panel.getSearchInput(); + await search.click(); + await expect(search).toBeFocused(); + + await bookmarksPage.keyboard.press('Meta+s'); + + await expect(bookmarksPage.getByText('Saved temporarily')).toBeVisible(); + }); }); From 81afb82f836920395bb467d1b8630b67663f7298 Mon Sep 17 00:00:00 2001 From: Amit Singh Date: Sun, 12 Jul 2026 10:17:10 +0530 Subject: [PATCH 2/3] fix(extension): address PR review on bookmarks Cmd+S/caret fix - Skip the panel Cmd+S save when focus is inside a dialog so an in-progress bookmark form edit isn't dropped from the saved snapshot - Assert the edited title's value in the caret-at-start e2e test - Use ControlOrMeta+s in the Cmd+S e2e test for cross-platform CI Co-Authored-By: Claude Opus 4.8 --- .../panels/BookmarksPanel/components/BookmarksHeader.tsx | 5 +++++ apps/extension/tests/specs/bookmarks.spec.ts | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/extension/src/entrypoints/popup/panels/BookmarksPanel/components/BookmarksHeader.tsx b/apps/extension/src/entrypoints/popup/panels/BookmarksPanel/components/BookmarksHeader.tsx index 28b6546c5..e34c32dbc 100644 --- a/apps/extension/src/entrypoints/popup/panels/BookmarksPanel/components/BookmarksHeader.tsx +++ b/apps/extension/src/entrypoints/popup/panels/BookmarksPanel/components/BookmarksHeader.tsx @@ -50,6 +50,11 @@ function BookmarksHeader({ onSearchChange, folderId }: Props) { (e) => { e.preventDefault(); e.stopPropagation(); + // Skip when focus is inside a dialog (e.g. the add/edit bookmark + // form) so an in-progress edit isn't excluded from the saved snapshot. + if (document.activeElement?.closest('[role="dialog"]')) { + return; + } if (!disableSave) { handleSaveClick(); } diff --git a/apps/extension/tests/specs/bookmarks.spec.ts b/apps/extension/tests/specs/bookmarks.spec.ts index cc587ed4b..eef982cad 100644 --- a/apps/extension/tests/specs/bookmarks.spec.ts +++ b/apps/extension/tests/specs/bookmarks.spec.ts @@ -101,6 +101,7 @@ test.describe('Bookmarks Panel', () => { TEST_BOOKMARKS.REACT_DOCS ); const titleInput = dialog.getByTestId('bookmark-title-input'); + await expect(titleInput).toHaveValue(TEST_BOOKMARKS.REACT_DOCS); await expect(titleInput).toBeFocused(); const selection = await titleInput.evaluate((el) => ({ @@ -456,7 +457,7 @@ test.describe('Bookmarks Panel', () => { await search.click(); await expect(search).toBeFocused(); - await bookmarksPage.keyboard.press('Meta+s'); + await bookmarksPage.keyboard.press('ControlOrMeta+s'); await expect(bookmarksPage.getByText('Saved temporarily')).toBeVisible(); }); From 8276417a2727b15d2ed132573fb42e791ad777b9 Mon Sep 17 00:00:00 2001 From: Amit Singh Date: Sun, 12 Jul 2026 10:24:42 +0530 Subject: [PATCH 3/3] Update package.json --- apps/extension/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/extension/package.json b/apps/extension/package.json index bb8efe8b1..7f6fc49c2 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -1,7 +1,7 @@ { "name": "@bypass/extension", "type": "module", - "version": "24.12.0", + "version": "24.12.1", "private": true, "description": "Bypass links from various sites to required links, with added functionality of Bookmarks Manager, Tagging Panel.", "scripts": {