Skip to content

Commit a1eb85b

Browse files
fix(interface): keep middle-click target platform agnostic
1 parent bcad6ae commit a1eb85b

4 files changed

Lines changed: 55 additions & 13 deletions

File tree

apps/tauri/src/platform.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,17 @@ export const platform: Platform = {
2525
platform: 'tauri',
2626

2727
getMiddleClickNavigationGuardEnvironment() {
28-
return {userAgent: navigator.userAgent, eventTarget: document};
28+
return {
29+
userAgent: navigator.userAgent,
30+
eventTarget: {
31+
addEventListener(type, listener, options) {
32+
document.addEventListener(type, listener, options);
33+
},
34+
removeEventListener(type, listener) {
35+
document.removeEventListener(type, listener);
36+
}
37+
}
38+
};
2939
},
3040

3141
async openDirectoryPickerDialog(opts) {

packages/interface/src/contexts/PlatformContext.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { createContext, useContext, PropsWithChildren } from "react";
22

3+
import type { MiddleClickNavigationGuardTarget } from "../util/middleClickNavigation";
4+
35
/**
46
* Platform abstraction layer
57
*
@@ -13,7 +15,7 @@ export type Platform = {
1315
/** Provide browser event access for the Windows Tauri middle-click guard. */
1416
getMiddleClickNavigationGuardEnvironment?(): {
1517
userAgent: string;
16-
eventTarget: EventTarget;
18+
eventTarget: MiddleClickNavigationGuardTarget;
1719
};
1820

1921
/** Open native directory picker dialog (Tauri only) */

packages/interface/src/util/middleClickNavigation.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
export type MiddleClickNavigationEvent = {
2+
button: number;
3+
preventDefault(): void;
4+
};
5+
6+
export type MiddleClickNavigationGuardTarget = {
7+
addEventListener(
8+
type: 'auxclick',
9+
listener: (event: MiddleClickNavigationEvent) => void,
10+
options: {passive: false}
11+
): void;
12+
removeEventListener(
13+
type: 'auxclick',
14+
listener: (event: MiddleClickNavigationEvent) => void
15+
): void;
16+
};
17+
118
export function shouldInstallMiddleClickNavigationGuard(
219
platform: 'web' | 'tauri',
320
userAgent: string
@@ -6,12 +23,10 @@ export function shouldInstallMiddleClickNavigationGuard(
623
}
724

825
export function installMiddleClickNavigationGuard(
9-
target: EventTarget
26+
target: MiddleClickNavigationGuardTarget
1027
): () => void {
11-
const preventMiddleClickNavigation = (event: Event) => {
12-
const mouseEvent = event as MouseEvent;
13-
14-
if (mouseEvent.button === 1) mouseEvent.preventDefault();
28+
const preventMiddleClickNavigation = (event: MiddleClickNavigationEvent) => {
29+
if (event.button === 1) event.preventDefault();
1530
};
1631

1732
target.addEventListener('auxclick', preventMiddleClickNavigation, {
@@ -24,7 +39,10 @@ export function installMiddleClickNavigationGuard(
2439

2540
export function installMiddleClickNavigationGuardForPlatform(
2641
platform: 'web' | 'tauri',
27-
environment?: {userAgent: string; eventTarget: EventTarget}
42+
environment?: {
43+
userAgent: string;
44+
eventTarget: MiddleClickNavigationGuardTarget;
45+
}
2846
): (() => void) | undefined {
2947
if (
3048
!environment ||

packages/interface/tests/middleClickNavigation.test.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {describe, expect, it} from 'bun:test';
22
import {
33
installMiddleClickNavigationGuard,
44
installMiddleClickNavigationGuardForPlatform,
5+
type MiddleClickNavigationGuardTarget,
56
shouldInstallMiddleClickNavigationGuard
67
} from '../src/util/middleClickNavigation';
78

@@ -11,6 +12,17 @@ function mouseEvent(type: string, button: number) {
1112
return event;
1213
}
1314

15+
function guardTarget(target: EventTarget): MiddleClickNavigationGuardTarget {
16+
return {
17+
addEventListener(type, listener, options) {
18+
target.addEventListener(type, listener as EventListener, options);
19+
},
20+
removeEventListener(type, listener) {
21+
target.removeEventListener(type, listener as EventListener);
22+
}
23+
};
24+
}
25+
1426
describe('middle-click navigation guard', () => {
1527
it('is enabled only for the Windows desktop app', () => {
1628
expect(
@@ -26,7 +38,7 @@ describe('middle-click navigation guard', () => {
2638

2739
it('prevents middle-button auxiliary clicks', () => {
2840
const target = new EventTarget();
29-
installMiddleClickNavigationGuard(target);
41+
installMiddleClickNavigationGuard(guardTarget(target));
3042
const event = mouseEvent('auxclick', 1);
3143

3244
target.dispatchEvent(event);
@@ -36,7 +48,7 @@ describe('middle-click navigation guard', () => {
3648

3749
it.each([0, 2])('does not prevent mouse button %i', (button) => {
3850
const target = new EventTarget();
39-
installMiddleClickNavigationGuard(target);
51+
installMiddleClickNavigationGuard(guardTarget(target));
4052
const event = mouseEvent('auxclick', button);
4153

4254
target.dispatchEvent(event);
@@ -46,7 +58,7 @@ describe('middle-click navigation guard', () => {
4658

4759
it('does not prevent the middle-button press that starts autoscroll', () => {
4860
const target = new EventTarget();
49-
installMiddleClickNavigationGuard(target);
61+
installMiddleClickNavigationGuard(guardTarget(target));
5062
const event = mouseEvent('mousedown', 1);
5163

5264
target.dispatchEvent(event);
@@ -56,7 +68,7 @@ describe('middle-click navigation guard', () => {
5668

5769
it('removes the guard during cleanup', () => {
5870
const target = new EventTarget();
59-
const cleanup = installMiddleClickNavigationGuard(target);
71+
const cleanup = installMiddleClickNavigationGuard(guardTarget(target));
6072
cleanup();
6173
const event = mouseEvent('auxclick', 1);
6274

@@ -74,7 +86,7 @@ describe('middle-click navigation guard', () => {
7486
const eventTarget = new EventTarget();
7587
const cleanup = installMiddleClickNavigationGuardForPlatform('tauri', {
7688
userAgent: 'Windows NT 10.0',
77-
eventTarget
89+
eventTarget: guardTarget(eventTarget)
7890
});
7991
const guardedEvent = mouseEvent('auxclick', 1);
8092

0 commit comments

Comments
 (0)