fix InputBox eating all pointer events (not just left button)

This commit is contained in:
Aran-Fey
2025-10-14 07:38:34 +02:00
parent 12d778ccaa
commit 6e4db8aad3
3 changed files with 86 additions and 6 deletions

View File

@@ -10,6 +10,18 @@ export function stopPropagation(event: Event): void {
event.stopPropagation();
}
export function markLeftButtonAsHandled(event: PointerEvent): void {
if (event.button === 0) {
markEventAsHandled(event);
}
}
export function stopLeftButtonPropagation(event: PointerEvent): void {
if (event.button === 0) {
event.stopPropagation();
}
}
export abstract class EventHandler {
component: ComponentBase;

View File

@@ -1,6 +1,11 @@
import { TextStyle } from "./dataModels";
import { applyTextStyleCss, textStyleToCss } from "./cssUtils";
import { markEventAsHandled, stopPropagation } from "./eventHandling";
import {
markEventAsHandled,
stopPropagation,
stopLeftButtonPropagation,
markLeftButtonAsHandled,
} from "./eventHandling";
export type InputBoxStyle = "underlined" | "rounded" | "pill";
@@ -139,16 +144,22 @@ export class InputBox {
// Consider any clicks on the input box as handled. This prevents e.g.
// drag events when trying to select something.
this.outerElement.addEventListener("pointerdown", stopPropagation);
this.outerElement.addEventListener("pointerup", stopPropagation);
this.outerElement.addEventListener(
"pointerdown",
stopLeftButtonPropagation
);
this.outerElement.addEventListener(
"pointerup",
stopLeftButtonPropagation
);
this.prefixTextElement.addEventListener(
"pointerdown",
markEventAsHandled
markLeftButtonAsHandled
);
this.suffixElementContainer.addEventListener(
"pointerdown",
markEventAsHandled
markLeftButtonAsHandled
);
// When clicked, focus the text element and move the cursor accordingly.
@@ -180,7 +191,10 @@ export class InputBox {
// Pointer down events select the input element and/or text in it (via
// dragging), so let them do their default behavior but then stop them
// from propagating to other elements
this._inputElement.addEventListener("pointerdown", stopPropagation);
this._inputElement.addEventListener(
"pointerdown",
stopLeftButtonPropagation
);
}
private _hasDefaultHandler(event: KeyboardEvent): boolean {

View File

@@ -103,3 +103,57 @@ async def test_specific_button_events(
else:
assert down_event is None
assert up_event is None
@pytest.mark.parametrize("pressed_button", ["left", "middle", "right"])
@pytest.mark.parametrize(
"build_child, child_eats_press_event, child_eats_pointer_events",
[
(rio.Spacer, False, []),
(rio.TextInput, True, ["left"]),
],
)
async def test_event_propagation(
pressed_button: t.Literal["left", "middle", "right"],
build_child: t.Callable[[], rio.Component],
child_eats_press_event: bool,
child_eats_pointer_events: t.Sequence[str],
) -> None:
press_event: rio.PointerEvent | None = None
down_event: rio.PointerEvent | None = None
up_event: rio.PointerEvent | None = None
def on_press(e: rio.PointerEvent):
nonlocal press_event
press_event = e
def on_pointer_down(e: rio.PointerEvent):
nonlocal down_event
down_event = e
def on_pointer_up(e: rio.PointerEvent):
nonlocal up_event
up_event = e
def build():
return rio.PointerEventListener(
build_child(),
on_press=on_press,
on_pointer_down=on_pointer_down,
on_pointer_up=on_pointer_up,
)
async with BrowserClient(build) as client:
await client.click(0.5, 0.5, button=pressed_button, sleep=0.5)
if pressed_button == "left" and not child_eats_press_event:
assert press_event is not None
else:
assert press_event is None
if pressed_button not in child_eats_pointer_events:
assert down_event is not None
assert up_event is not None
else:
assert down_event is None
assert up_event is None