Skip to content

Backdrops close on a click pressed and released on them, not a drag out of the dialog - #146

Merged
rdrake merged 3 commits into
evilnet:developfrom
rdrake:fix/backdrop-press
Oct 31, 2026
Merged

rdrake merged 3 commits into
evilnet:developfrom
rdrake:fix/backdrop-press

Conversation

@rdrake

@rdrake rdrake commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator

Selecting text in a modal and letting go past its edge closed the modal, along with anything typed in it.

Why

When the mouse button goes down on one element and up on another, the browser fires the click on their nearest common ancestor. For anything inside a modal, that ancestor is the backdrop. @click.self can't tell such a click from a real one on the backdrop. Two cases closed the modal:

  • a drag that started inside the dialog and was released over the backdrop;
  • a press on the backdrop that was released inside the dialog.

The worst cases are the ban dialog and the alert builder, where the text the user typed is lost. The script editor, Mentions, the context menu and every settings-style window behaved the same way. Touch isn't affected, because a touch drag fires no click.

What

  • v-backdrop directive (client/js/helpers/backdrop.ts, registered in vue.ts). It counts a click only when the pointer went down and came up on the backdrop itself, which is how a native <dialog>'s light dismiss behaves.
    • It replaces every @click.self on an overlay, and the click half of Mentions' and the context menu's own handlers.
    • Their remaining right-click-to-close is now @contextmenu.self.
    • test/tests/backdrop.ts fails if @click.self comes back.
  • Not native <dialog>: closedby isn't supported on iOS Safari, and moving to <dialog> would break the escape-layer ordering and the overlays' z-index scheme.
  • Scenario helper: scenarios now close a backdrop with clickBackdrop (tools/scenarios/lib/backdrop.mjs), a real mouse press and release. A bare element.click() from script no longer closes anything, so help-modal, inbox and native-shell-chrome were updated.

Testing

  • test/helpers/backdrop.ts covers the directive's rules. The full mocha suite passes.
  • New browser check tools/scenarios/backdrop-drag.mjs passes 7/7. On the old code the drag-out and press-in cases fail.
  • help-modal and inbox pass. native-shell-chrome fails one check ("the page is itself again with the shell off"), which fails the same way on develop.
  • Headless Chrome makes no text selection from scripted mouse events, so the drag check confirms the drag's click lands on the backdrop rather than checking a selection.

Mouse and trackpad only, so no phone testing is needed for the fix itself. The second commit is the review round; squash on merge if you prefer.

…ut of the dialog

A click whose press and release land on different elements is fired on
their common ancestor, which for anything inside a modal is its
backdrop. `@click.self` cannot tell, so selecting text in a dialog and
letting go past its edge closed it, typed text and all (the ban dialog,
the alert builder, the script editor, Mentions, the context menu, every
settings-style window), and so did a press on the backdrop let go
inside the dialog.

The `v-backdrop` directive (helpers/backdrop.ts, registered in vue.ts)
counts a click only when the pointer went down and came up on the
backdrop itself, as a native <dialog>'s light dismiss does. It replaces
every `@click.self` on an overlay and the click half of Mentions' and
the context menu's own handlers; test/tests/backdrop.ts fails a new
`@click.self`. The scenarios that closed an overlay with a bare
`element.click()` now press it first.

Tests: test/helpers/backdrop.ts; browser check
tools/scenarios/backdrop-drag.mjs (fails on the old code).
After review. The directive keeps its two flags in closures and drops
the update hook (every call site binds a stable function). Mentions'
and the context menu's leftover handlers only closed on a right-click
on the backdrop itself, which is `@contextmenu.self`. The static test is
one assertion over every component. Scenarios close a backdrop with
`clickBackdrop` (tools/scenarios/lib/backdrop.mjs), a real mouse press
and release on a point where the backdrop is topmost, instead of three
pasted synthetic-event snippets; backdrop-drag.mjs uses it and drops
its reopen step.
@rdrake
rdrake merged commit 545dca0 into evilnet:develop Oct 31, 2026
2 of 4 checks passed
@rdrake
rdrake deleted the fix/backdrop-press branch October 31, 2026 19:44

This branch was successfully deployed

1 active deployment
github-pages — 31436abc Deployed Oct 31, 2026 by rdrake via deploy #377
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant