fix: close the Contacts and Files drawer when you pick something in it

This commit is contained in:
Linus Rath
2026-10-28 02:43:58 +01:00
parent 893696791d
commit fdc3535c7b
3 changed files with 50 additions and 27 deletions
@@ -74,7 +74,7 @@ describe('ContactsApp', () => {
});
});
it('takes the closed drawer out of reach, so it can\'t cover the nav rail or catch Tab', () => {
it("takes the closed drawer out of reach, so it can't cover the nav rail or catch Tab", () => {
renderContacts();
expect(drawer()).toHaveAttribute('inert');
expect(drawer().className).toContain('invisible');
@@ -83,4 +83,15 @@ describe('ContactsApp', () => {
expect(drawer()).not.toHaveAttribute('inert');
expect(within(drawer()).getByText('tabs.all')).toBeInTheDocument();
});
it("closes the drawer when something in it is picked, so it doesn't stay over the form", () => {
renderContacts();
fireEvent.click(screen.getAllByRole('button', { name: 'open_categories' })[0]);
expect(drawer()).not.toHaveAttribute('inert');
// The header's "+" menu, then "New contact".
fireEvent.click(within(drawer()).getAllByRole('button')[0]);
fireEvent.click(within(drawer()).getByText('create_new'));
expect(drawer()).toHaveAttribute('inert');
});
});
+23 -16
View File
@@ -151,6 +151,13 @@ function ContactsAppContent({ linkSegments: routeSegments }: ContactsAppProps =
const isNarrow = !isDesktop;
const [narrowSidebarOpen, setNarrowSidebarOpen] = useState(false);
useEffect(() => { if (!isNarrow) setNarrowSidebarOpen(false); }, [isNarrow]);
// A new view (a form, a group, a contact) replaces whatever the drawer was for.
useEffect(() => { setNarrowSidebarOpen(false); }, [view]);
// Anything picked in the drawer closes it (R7).
const fromDrawer = <A extends unknown[], R>(action: (...args: A) => R) => (...args: A): R => {
setNarrowSidebarOpen(false);
return action(...args);
};
// Panel resize state - sidebar (categories)
const [sidebarWidth, setSidebarWidth] = useState(() => {
@@ -1013,31 +1020,31 @@ function ContactsAppContent({ linkSegments: routeSegments }: ContactsAppProps =
addressBooks={addressBooks}
activeCategory={activeCategory}
onSelectCategory={handleSelectCategory}
onCreateGroup={handleCreateGroup}
onCreateContact={handleCreateNew}
onCreateAddressBook={client ? () => setCreatingAddressBook(true) : undefined}
onImport={() => setShowImportDialog(true)}
onEditGroup={handleEditGroupFromSidebar}
onDeleteGroup={handleDeleteGroupFromSidebar}
onComposeGroup={handleComposeGroupFromSidebar}
onCreateGroup={fromDrawer(handleCreateGroup)}
onCreateContact={fromDrawer(handleCreateNew)}
onCreateAddressBook={client ? fromDrawer(() => setCreatingAddressBook(true)) : undefined}
onImport={fromDrawer(() => setShowImportDialog(true))}
onEditGroup={fromDrawer(handleEditGroupFromSidebar)}
onDeleteGroup={fromDrawer(handleDeleteGroupFromSidebar)}
onComposeGroup={fromDrawer(handleComposeGroupFromSidebar)}
onDropContacts={handleDropContacts}
onDropContactsToCategory={handleDropContactsToCategory}
onRenameAddressBook={client ? (book) => setRenamingAddressBook(book) : undefined}
onShareAddressBook={client ? (book) => setSharingAddressBookId(book.id) : undefined}
onSetDefaultAddressBook={client ? async (book) => {
onRenameAddressBook={client ? fromDrawer((book: AddressBook) => setRenamingAddressBook(book)) : undefined}
onShareAddressBook={client ? fromDrawer((book: AddressBook) => setSharingAddressBookId(book.id)) : undefined}
onSetDefaultAddressBook={client ? fromDrawer(async (book: AddressBook) => {
try {
await setDefaultAddressBook(client, book);
toast.success(t("address_books.default_updated"));
} catch {
toast.error(t("address_books.set_default_failed"));
}
} : undefined}
onCreateContactInBook={(book) => {
}) : undefined}
onCreateContactInBook={fromDrawer((book: AddressBook) => {
setDefaultBookIdForCreate(book.id);
setSelectedContact(null);
setView("create");
}}
onDeleteAddressBook={client ? async (book) => {
})}
onDeleteAddressBook={client ? fromDrawer(async (book: AddressBook) => {
const ok = await confirmDialog({
title: t("address_books.delete"),
message: t("address_books.confirm_delete", { name: book.name }),
@@ -1051,8 +1058,8 @@ function ContactsAppContent({ linkSegments: routeSegments }: ContactsAppProps =
} catch {
toast.error(t("address_books.delete_failed"));
}
} : undefined}
onRenameKeyword={(kw) => setRenamingKeyword(kw)}
}) : undefined}
onRenameKeyword={fromDrawer((kw: string) => setRenamingKeyword(kw))}
directoryCount={showDirectory ? directoryPrincipals.length : undefined}
multiAccountMode={multiAccountEnabled && accountClients.length > 1}
/>
+15 -10
View File
@@ -242,6 +242,11 @@ export function FileBrowser({
const [narrowSidebarOpen, setNarrowSidebarOpen] = useState(false);
useEffect(() => { if (!isNarrow) setNarrowSidebarOpen(false); }, [isNarrow]);
useEffect(() => { setNarrowSidebarOpen(false); }, [currentPath]);
// Anything picked in the drawer closes it (R7).
const fromDrawer = <A extends unknown[], R>(action: (...args: A) => R) => (...args: A): R => {
setNarrowSidebarOpen(false);
return action(...args);
};
const [sidebarWidth, setSidebarWidth] = useState(() => {
if (typeof window !== "undefined") {
const saved = Number(localStorage.getItem("files-sidebar-width"));
@@ -891,19 +896,19 @@ export function FileBrowser({
canCreate={canCreate}
onNavigate={onNavigate}
onOpenRecent={onOpenRecent}
onUploadFiles={() => fileInputRef.current?.click()}
onUploadFolder={() => folderInputRef.current?.click()}
onNewFolder={() => setShowNewFolder(true)}
onNewTextFile={() => setShowNewTextFile(true)}
onUploadFiles={fromDrawer(() => fileInputRef.current?.click())}
onUploadFolder={fromDrawer(() => folderInputRef.current?.click())}
onNewFolder={fromDrawer(() => setShowNewFolder(true))}
onNewTextFile={fromDrawer(() => setShowNewTextFile(true))}
onToggleFavorite={onToggleFavorite}
onDropItems={moveNames}
canShare={canShare}
onShare={(r) => setShareTargetId(r.id)}
onCreateIn={createIn}
onRenameFolder={setRenameFolder}
onDeleteFolder={(folder) => void onDeleteNode(folder.id, folder.name)}
onRevealRecent={(id) => void onRevealNode(id)}
onDownloadRecent={(id) => void onDownloadNode(id)}
onShare={fromDrawer((r: FileResource) => setShareTargetId(r.id))}
onCreateIn={fromDrawer(createIn)}
onRenameFolder={fromDrawer(setRenameFolder)}
onDeleteFolder={fromDrawer((folder: FileResource) => void onDeleteNode(folder.id, folder.name))}
onRevealRecent={fromDrawer((id: string) => void onRevealNode(id))}
onDownloadRecent={fromDrawer((id: string) => void onDownloadNode(id))}
onRemoveRecent={onRemoveRecent}
/>
);