Skip to content

feat(joint-core): add paper eventSurface option - #3441

Open
kumilingus wants to merge 1 commit into
clientIO:devfrom
kumilingus:feat/event-surface-option
Open

feat(joint-core): add paper eventSurface option#3441
kumilingus wants to merge 1 commit into
clientIO:devfrom
kumilingus:feat/event-surface-option

Conversation

@kumilingus

@kumilingus kumilingus commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Independent of #3438 — one commit, joint-core only, based on dev.

The gap

DOM content rendered into paper.el — a ruler, a gutter, a toolbar — is only half interactive. A press on it opens a blank interaction, but every other handler runs the full guard(), which rejects a target that is not on the paper's event surface. So the same content gets blank:pointerdown and the drag that follows it, but no blank:pointerclick and no hover events.

The option

new dia.Paper({ eventSurface: '.ruler' })

eventSurface declares a DOM subtree part of the paper's interaction surface, and every handler then treats it as a blank area. It accepts:

  • a CSS selector — matched with closest, so it covers any number of subtrees
  • an element
  • an array of elements
  • a predicate (target) => boolean

How it composes

options.guard is consulted before the surface test, so the two hooks work in opposite directions and cover the whole space: eventSurface opens a subtree, guard still closes individual events within it. Surface a ruler, then veto wheel events on it — neither hook alone can express that.

Scope worth knowing: the option only ever widens. It cannot exclude anything — that is guard — and pointing it outside paper.el is inert, because the paper's handlers are delegated on paper.el and never see those events.

Tests

  • joint-core QUnit: 2082 pass, incl. the with/without-eventSurface gesture (hover and click appear only once surfaced), the drag through a surfaced subtree, all four option forms, and a non-element target
  • test:ts and lint clean

Relation to #3438

Independent — the two touch guard() in the same region, so whichever lands second needs a trivial rebase.

One follow-up belongs after both: joint-react's paper preset keeps portaled <Paper> children off the event surface (#3438), and should defer to this option so an overlay meant to drive the canvas can say so. That is a one-line change to the preset's guardExplicit override and is deliberately not in either PR, since it needs both.

🤖 Generated with Claude Code

DOM content rendered into `paper.el` - a ruler, a gutter, a toolbar - is only half
interactive. A press on it opens a blank interaction, but every other handler runs
`guard()`, which rejects a target that is not on the paper's event surface, so the
same content gets no `blank:pointerclick` and no hover events.

`eventSurface` declares such a subtree part of the surface, and every handler then
treats it as a blank area:

    new dia.Paper({ eventSurface: '.ruler' })

It takes a CSS selector (matched with `closest`, so it covers any number of
subtrees), an element, an array of elements, or a `function(target) { ... }`.

`guard` is consulted before the surface test, so the two compose in opposite
directions: `eventSurface` opens a subtree, `guard` still closes single events
within it - surface a ruler, then veto wheel events on it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@kumilingus
kumilingus force-pushed the feat/event-surface-option branch from 5ce7b9e to 24e4eb1 Compare July 29, 2026 08:40
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