slides: a right-click menu that belongs to the deck - #275
Open
iamgeo92 wants to merge 1 commit into
Open
Conversation
iamgeo92
force-pushed
the
context-menu
branch
2 times, most recently
from
August 10, 2026 02:28
e8a2911 to
686df85
Compare
The editor had no context menu at all, so a right-click on the canvas produced the browser's own — Back, Reload, View source — which is precisely the wrong set of verbs for a slide, and the one gesture every user of every other editor tries first. Three menus, chosen by what was actually clicked. An element offers Edit text, Cut, Copy, Duplicate, Bring to front, Send to back, Group / Ungroup and Delete. A slide thumbnail offers New slide, Duplicate slide and Delete slide. The canvas beside the slide offers Paste and the slide's own verbs. Aiming at something outside the selection selects it first, the way every editor does, so the verbs always describe what they are about to act on. The browser's menu is deliberately left where it is the better one: form fields, links, and text mid-edit, where the system carries spelling, dictation, look-up and a real paste. That last case needs the question asked on the PRESS — a right-click commits the edit before contextmenu is dispatched — and answered by geometry, because Moveable's control box sits on top of the caret and swallows the target. ctxmenu.ts renders and dismisses; it knows nothing about slides. Paste shares the text path with the paste EVENT rather than growing a second copy of it, which is why wirePaste is split.
Author
|
@nyblnet — this is the largest of the batch after #292, so it's the one I'd most value your read on. The editor has no context menu at all ( Two decisions I'd like checked:
Also adds 8 strings to all eight catalogs. #276 is stacked on this. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
The editor has no context menu at all.
grep -rn "contextmenu" slides/src kernel/srcreturns nothing. So the one gesture every user of every other editortries first produces the browser's menu — Back, Reload, View source, Save page
as — which is precisely the wrong set of verbs for a slide.
It also matters beyond the mouse: a long-press on a phone has nothing to open,
which is the follow-up PR this one exists to enable.
What this adds
Three menus, chosen by what was actually right-clicked.
Every verb routes to the code that already implements it —
duplicateSelection,panel.reorder,panel.group/ungroup,duplicateSlide,deleteSlide,openLayoutPicker. Nothing is reimplemented, so nothing can drift from thekeyboard shortcuts, whose accelerators are shown in the rows.
Right-clicking something outside the selection selects it first — the rule
every editor follows, and the only way the verbs can be honest about what they
are about to act on.
Groupgreys out below two elements; the menu flips toUngroupwhen the selection already is one.Two details worth reviewing
The browser's menu is deliberately preserved where it is better — form
fields, links, and text mid-edit, where the system menu carries spelling,
dictation, look-up and a real paste. Getting that last case right needed two
non-obvious things:
text edit (the press blurs the caret), and it does so before
contextmenuisdispatched — so asking the canvas at menu time always hears "not editing".
control box sits on top of the text being edited, so a press aimed squarely at
the caret is delivered to a resize handle and
node.contains(target)isfalse. Both were caught by tests, not by reading.ctxmenu.tsis deliberately dumb. It renders rows, positions itself anddismisses; it knows nothing about slides or elements. It flips rather than clamps
near a screen edge, so the pointer never ends up inside the menu it just
opened (a clamped menu slides under the cursor and the first thing that happens
is a mis-click).
Pasteshares the text path with the paste event rather than growing asecond copy — which is why
wirePasteis split into apasteFromText(text).A menu click carries no
clipboardData, so it has to read the clipboard itself,and being refused (Safari prompts; Firefox has no
readText) is a real answerthat gets a toast rather than silence.
Demo
Stills — the three menus
How this was verified
Dev server at 1280×820 with a real mouse right-click:
Groupis disabled for a single elementEscapecloses itRegression tests for the
wirePastesplit (the riskiest part of the diff):Gates:
i18n
Eight new strings, added to all eight catalogs (de · es · fr · it · ja · pt ·
zh-Hans · zh-Hant) at the top of each map per
docs/PARALLEL-WORK.md§3, withpacked.tsregenerated byscripts/build-i18n.mjs:Cut·Copy·Paste·Bring to front·Send to back·Ungroup·Edit text·Nothing to paste — use ⌘VThe rest reuse keys the catalogs already carry (
Duplicate,Delete,Group,New slide,Duplicate slide,Delete slide). Translations are machine-draftedto match the existing catalogs' own stated standard — native review welcome, as
the file headers invite.
No format change, no kernel change, nothing under
sync/.Follow-up: long-press opens this same menu on touch. Kept separate so this
one can be judged as a desktop feature on its own.
Changelog entry — not in the diff, on purpose
CHANGELOG.mdis 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 noCHANGELOG.mdchange 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.