Skip to content

slides: an overlay on a phone can be dismissed by tapping away from it - #273

Open
iamgeo92 wants to merge 2 commits into
nyblnet:mainfrom
iamgeo92:phone-drawer-dismiss
Open

slides: an overlay on a phone can be dismissed by tapping away from it#273
iamgeo92 wants to merge 2 commits into
nyblnet:mainfrom
iamgeo92:phone-drawer-dismiss

Conversation

@iamgeo92

@iamgeo92 iamgeo92 commented Aug 10, 2026

Copy link
Copy Markdown

Stacked on #272. This branch contains that commit as its base so the two
do not fight over the same region of editor.ts. Merge #272 first and this
reduces to its own single commit; the changelog entries are separate blocks.

The problem

Four things open over the canvas on a phone, and every one of them had exactly
one way out — press the button that opened it again:

overlay outside-press dismissal before this PR
slide list drawer (☰) none
properties drawer (Format) none
+ insert menu none
⋯ more menu none

The last two are the interesting ones. Every other dropdown in the bar — Save
as, Share, Language, Shape, Media, the present pill — already wires up the same
three lines:

document.addEventListener('pointerdown', (ev) => {
  if (!wrap.contains(ev.target as Node)) wrap.classList.remove('open')
})

+ and ⋯ do not. And they are the only two dropdowns that exist exclusively on
a phone
(.ed-phone-only). So the menus that were hardest to escape were the
ones a thumb could not escape at all.

Measured on the dev server under an iPhone profile, tapping the canvas with each
overlay open:

after ☰ : slides drawer open  → tap canvas → still open
after Format : props drawer open → tap canvas → still open
after + : menu open → tap canvas → still open
after ⋯ : menu open → tap canvas → still open

The fix

Tapping the slide beside an overlay closes it.

Two conditions keep this from reaching anywhere it shouldn't:

  • Only while the panels are drawers (≤700px — the threshold the CSS and
    applyPhoneChrome already share). On a wide screen the panels are columns
    beside the canvas, and a click on the canvas is just a click on the canvas.
  • A press inside the topbar is exempt. This is the trap the obvious version
    falls into: ☰ is outside the drawer, so a naive handler closes the drawer on
    its pointerdown and the click that follows immediately reopens it — the
    button would never shut anything again. There is a regression test for exactly
    this (open → close → open).

The two phone menus get the same helper the rest of the bar open-codes. I left
the other five call sites alone deliberately: converting them is pure churn on a
file several branches touch, and it belongs in its own cleanup.

Before / after

Same gestures both sides: open +, tap the slide; open ☰, tap the slide.

overlay dismissal, before and after

before — the menu stays over the deck after — it gets out of the way

How this was verified

iPhone emulation (390×664, DPR 3, hasTouch) with real touch dispatch, plus a
1280×800 mouse context:

case result
☰ opens the slides drawer; tapping the canvas closes it pass
Format opens the properties drawer; tapping the canvas closes it pass
☰ still works as a toggle: open → close → open pass
tapping inside the properties drawer keeps it open pass
+ menu opens, then closes on an outside tap pass
⋯ menu opens, then closes on an outside tap pass
desktop: both columns start open pass
desktop: clicking the canvas leaves both columns open pass

Gates:

node_modules/.bin/tsc -b                                        clean
npm run build:single                                            ok (664KB shell)
node scripts/shell-gate.mjs …/Bento_Slides.bento.html           splice contract OK

No new user-facing strings, so no i18n catalog changes. No format or kernel
change; nothing under sync/.

Deliberately not in scope: dismissing with Escape. A phone has no Esc key,
and Escape already carries meaning on the canvas — bundling it in would make
this change harder to reason about, not easier.

Caveat: verified under Chromium's iPhone emulation, not on physical iOS
hardware. The logic is pointer-target and viewport-width based with no
WebKit-specific behaviour involved.


Changelog entry — not in the diff, on purpose

CHANGELOG.md is this repo's named conflict magnet (docs/PARALLEL-WORK.md §3). With several of these open at once, and [Unreleased] being emptied every time a release is cut, a changelog hunk made every one of them conflict on that file and nothing else — twice over. They carry no CHANGELOG.md change so they stay mergeable; here is the entry to drop in at release time, or I'll add it back in whatever form you prefer.

- **Picking a slide on a phone now shows you the slide.** Below 700px the slide
  list is not a column beside the canvas — it is a drawer laid over it. Tapping
  a thumbnail navigated correctly and then left the list sitting on top of the
  answer, so every slide change cost a second trip to the ☰ toggle to see what
  you had chosen. The drawer now steps aside when you pick from it. On a wide
  screen the list is a real column and rightly stays where it is, and the
  per-thumbnail Duplicate and Delete buttons leave it open on every width —
  those are edits to the list, not a choice of slide.

- **Overlays on a phone can be dismissed by tapping away from them.** The slide
  list, the properties panel and the two phone-only bar menus (+ and ⋯) all
  opened over the canvas and then had exactly one way out: press the same button
  again. On a drawer that covers the control that opened it, that is a hunt.
  Tapping the slide beside an overlay now closes it — the gesture every sheet on
  a phone answers to. The + and ⋯ menus were, in fact, the only dropdowns in the
  bar with no outside-press dismissal at all, and they are the two that exist
  only on a phone. Nothing changes on a wide screen, where the panels are
  columns beside the canvas rather than sheets on top of it, and the ☰ / Format
  buttons still work as plain toggles.

@iamgeo92
iamgeo92 force-pushed the phone-drawer-dismiss branch 2 times, most recently from ef80014 to b832901 Compare August 10, 2026 02:28
Below 700px the side panels are not columns — styles.css makes them
overlay drawers laid across the canvas, because a 188px column beside a
402px screen leaves the thing being edited as the smallest thing on it.

Tapping a thumbnail navigated correctly and then left the drawer covering
the slide it had just navigated to, so every slide change cost a second
trip to the toggle in the topbar to actually see the result.

Closing is scoped to the drawer width and to the thumbnail itself: on a
wide screen the list is a real column and stays put, and the Duplicate
and Delete buttons on a thumbnail already stop propagation, so editing
the list never dismisses it.
The slide list, the properties panel and the two phone-only bar menus all
open across the canvas, and every one of them had a single way out:
press the button that opened it. On a drawer wide enough to cover that
button, that is a hunt rather than a gesture.

Tapping the slide beside an overlay now closes it. Two conditions keep
this from reaching anywhere it should not: the drawer rule runs only
while the panels ARE drawers (on a wide screen they are columns, where a
click on the canvas is just a click on the canvas), and a press inside
the topbar is exempt so the toggles keep toggling — closing on their
pointerdown would let the click that follows reopen what it just closed.

The + and ... menus turn out to be the only dropdowns in the bar without
an outside-press dismissal, and they are the two that exist only on a
phone: the menus hardest to escape were the ones a thumb could not
escape at all. They now use the same helper.
@iamgeo92

Copy link
Copy Markdown
Author

@nyblnet — this one when you get a chance.

Four things open over the canvas on a phone and none of them could be dismissed by tapping away: both drawers and the +/⋯ menus. The last two turn out to be the only dropdowns in the bar without an outside-press dismissal, and they're the two that exist only on a phone — so the menus hardest to escape were the ones a thumb couldn't escape at all.

The interesting bit is the trap it had to avoid: ☰ is outside the drawer, so a naive handler closes on its pointerdown and the click reopens it, and the button never shuts anything again. There's a regression test for exactly that (open → close → open).

Stacked on #272 — merge that first and this reduces to one commit.

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