fix(person-mention): respect modified-click and middle-click for new-tab nav
Felix #7: handleMentionClick unconditionally preventDefault'd and goto'd, breaking ctrl-click / cmd-click / shift-click / alt-click / middle-click — "open in new tab" is a real workflow for researchers comparing two persons. Add isPlainPrimaryClick() guard. Modified clicks fall through to the browser's default anchor handling (the <a href="/persons/{id}"> opens in the new tab as expected). Plain left-clicks still SPA-navigate via goto(). Three new tests assert ctrl-click, meta-click, and middle-click are not preventDefault'd. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -370,6 +370,38 @@ describe('TranscriptionReadView — person-mention rendering', () => {
|
||||
expect(card).toBeNull();
|
||||
});
|
||||
|
||||
it('lets ctrl-click and meta-click fall through so users can open in a new tab', async () => {
|
||||
render(TranscriptionReadView, {
|
||||
blocks: [mentionBlock],
|
||||
onParagraphClick: () => {}
|
||||
});
|
||||
|
||||
const link = document.querySelector('a.person-mention')! as HTMLAnchorElement;
|
||||
|
||||
// ctrl-click (Linux/Win "open in new tab")
|
||||
const ctrlClick = new MouseEvent('click', { bubbles: true, cancelable: true, ctrlKey: true });
|
||||
const ctrlPrevented = !link.dispatchEvent(ctrlClick);
|
||||
expect(ctrlPrevented).toBe(false);
|
||||
|
||||
// meta-click (macOS "open in new tab")
|
||||
const metaClick = new MouseEvent('click', { bubbles: true, cancelable: true, metaKey: true });
|
||||
const metaPrevented = !link.dispatchEvent(metaClick);
|
||||
expect(metaPrevented).toBe(false);
|
||||
});
|
||||
|
||||
it('lets middle-click fall through so users can open in a background tab', async () => {
|
||||
render(TranscriptionReadView, {
|
||||
blocks: [mentionBlock],
|
||||
onParagraphClick: () => {}
|
||||
});
|
||||
|
||||
const link = document.querySelector('a.person-mention')! as HTMLAnchorElement;
|
||||
// button === 1 is middle mouse button
|
||||
const middleClick = new MouseEvent('click', { bubbles: true, cancelable: true, button: 1 });
|
||||
const prevented = !link.dispatchEvent(middleClick);
|
||||
expect(prevented).toBe(false);
|
||||
});
|
||||
|
||||
it('degrades to plain unlinked text when the person fetch returns 404', async () => {
|
||||
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ status: 404, ok: false, json: vi.fn() }));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user