Skip to content

refactor(events)!: empty-space clicks via canvas event.object — removing *Missed#76

Draft
bigmistqke wants to merge 2 commits into
solidjs-community:nextfrom
bigmistqke:feat/void-via-event-object
Draft

refactor(events)!: empty-space clicks via canvas event.object — removing *Missed#76
bigmistqke wants to merge 2 commits into
solidjs-community:nextfrom
bigmistqke:feat/void-via-event-object

Conversation

@bigmistqke

Copy link
Copy Markdown
Contributor

Alternative to #75. Where #75 adds a positive onVoid* family, this removes the *Missed handlers and leans on a single canvas-level check: event.object.

Summary

To react to a gesture that hit nothing, put the handler on the <Canvas> and read event.object — the nearest hit object, or undefined when the ray hit empty space.

<Canvas onClick={event => { if (!event.object) deselect() }}>
  <T.Mesh onClick={() => select()}></T.Mesh>
</Canvas>

This drops onClickMissed / onDoubleClickMissed / onContextMenuMissed.

Semantics

  • A canvas-level handler fires after the event has propagated through the scene, unless a handler called stopPropagation(). event.object is the nearest hit, or undefined on empty space.
  • Uniform across every discrete gesture — onClick, onDoubleClick, onContextMenu, onPointerDown, onPointerUp, onPointerMove, onWheel — all sharing one dispatch path (propagate()). click() folds into that path; the bespoke missed-tracking phases it used are gone.
  • onPointerEnter / onPointerLeave are unaffected: they mark the canvas boundary (enter on entry, leave on exit), not a per-event hit, so there's no empty-vs-hit distinction to read there.
  • A consumed event — one whose handler called stopPropagation() — never reaches the canvas, so it's neither a hit nor an empty click at that level.

Removed: per-object *Missed

*Missed also fired on individual objects ("the gesture didn't reach me, specifically"), and a total miss fired both the canvas handler and onClickMissed for the same empty click. That per-object inversion is gone; the canvas event.object check covers empty space directly.

Types

Canvas-level handlers type event.object as Object3D | undefined, so if (!event.object) type-checks as the empty-space test. Object-level handlers keep object: Object3D, since they only fire on a hit.

Tests

The canvas handler is asserted to fire with event.object undefined on a miss and set to the hit object on a hit, across all seven gestures.

Docs

Tour chapter, events reference, Canvas props, and the CONTEXT.md glossary migrated to the event.object pattern; the demo snippet renamed accordingly.

A void — a gesture that hit no object — is read from the canvas-level handler: the canvas always receives the event (unless a handler stopped it), with `event.object` undefined when the ray hit nothing. Removes the `onClickMissed` / `onDoubleClickMissed` / `onContextMenuMissed` handlers.

`click()` now delegates to the shared `propagate()` path that `onPointerDown` / `onPointerUp` / `onPointerMove` / `onWheel` already use, so every discrete gesture has one dispatch path and one void model. `PointerRaycaster.intersectObject`, used only by the dropped re-raycast phase, is removed from the type.

Canvas-level handlers type `event.object` as `Object3D | undefined` — object-level handlers keep `Object3D`, since they only fire on a hit — so `if (!event.object)` type-checks as the empty-space test.

Tests assert the canvas handler fires with `event.object` undefined on a miss and set to the hit object on a hit, across all seven gestures.
Replace the *Missed material with "Clicking empty space": a canvas-level handler receives every gesture, and `event.object` is undefined when the ray hit nothing — read `if (!event.object)`. Updates the tour chapter, the events reference, and the Canvas props; the glossary's "Missed event" entry becomes "Void".

Rename the demo snippet to 04-void-click.tsx and switch it to `onClick` with an `event.object` check.
@bigmistqke bigmistqke marked this pull request as draft June 8, 2026 14:50
@pkg-pr-new

pkg-pr-new Bot commented Jun 8, 2026

Copy link
Copy Markdown

commit: bf2ac35

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