Skip to content

feat(ui): right-click context bundle (SD-2945)#3169

Merged
caio-pizzol merged 2 commits intomainfrom
caio/SD-2945-right-click-context
May 5, 2026
Merged

feat(ui): right-click context bundle (SD-2945)#3169
caio-pizzol merged 2 commits intomainfrom
caio/SD-2945-right-click-context

Conversation

@caio-pizzol
Copy link
Copy Markdown
Contributor

Lifts the small bundle every right-click consumer keeps reassembling onto the controller. ui.viewport.contextAt({ x, y }) returns the full shape:

```ts
{ point, entities, position, selection, insideSelection }
```

`insideSelection` is an AABB hit-test against the live selection rects, so predicates can distinguish 'right-clicked the selection' from 'right-clicked elsewhere' without re-running geometry.

`getContextMenuItems(input)` accepts the full bundle (or the legacy `{ entities }` shape). Bundle inputs make `point` / `position` / `insideSelection` available on `ContextMenuContribution.when`, and each returned item carries an `invoke()` closure that fires `execute({ context })` with the bundle bound. Direct `ui.commands.execute` and `commands.get(id).execute()` calls still pass `context: undefined`, so handlers that don't care about clicks keep working unchanged.

Closes the gap consumers hit on every register site: today they thread the same shape (entity + point + position + selection containment) by hand and unpack it inside the handler. The bundle removes the boilerplate and keeps predicate filtering and execute dispatch on the same shape, so 'Paste here' / 'Comment here' / 'Accept this change' stop being stale-selection hazards.

Out of scope: the demo update consuming this surface lives in PR #3152 (will rebase once this lands).

Verified: `pnpm exec vitest run src/ui` -> 276 passed (17 files, +15 new); `pnpm exec tsc -b tsconfig.references.json` -> clean.

Adds ui.viewport.contextAt({ x, y }) returning the full
{ point, entities, position, selection, insideSelection } bundle every
right-click consumer ends up assembling by hand. insideSelection is an
AABB hit-test against the current selection rects so predicates can
distinguish "right-clicked the selection" from "right-clicked elsewhere"
without re-running geometry.

Widens ContextMenuWhenInput with optional point / position /
insideSelection (additive, old { entities, selection } predicates keep
working). getContextMenuItems(input) now accepts a ViewportContext OR
the legacy { entities } shape; bundle inputs make the same context
available on ContextMenuItem.invoke() and pass it into the registered
execute({ context }) so handlers act on the click target without
threading payloads. Direct ui.commands.execute / commands.get(id).execute
calls leave context undefined.

Tests cover the AABB helper boundaries, contextAt composition,
predicate input shape for both call styles, invoke() forwarding to
execute, and the legacy path keeping invoke absent.
@caio-pizzol caio-pizzol requested a review from a team as a code owner May 5, 2026 17:47
@linear
Copy link
Copy Markdown

linear Bot commented May 5, 2026

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 48d983d38c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

const whenInput = context
? {
entities,
selection: state.selection,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use bundled selection when evaluating context-menu predicates

When getContextMenuItems is called with a ViewportContext bundle, the predicate input still uses state.selection instead of context.selection. This means predicates can be evaluated against one selection while item.invoke() later executes with a different selection snapshot from the bound bundle, so menu visibility and command behavior can diverge if callers cache/forward a bundle (the exact stale-selection hazard this API is trying to avoid).

Useful? React with 👍 / 👎.

@caio-pizzol caio-pizzol self-assigned this May 5, 2026
… (SD-2945)

isViewportContextBundle is the single guard both the controller proxy
and the registry route through, so the two layers can't disagree on
ambiguous inputs ({ point: null }, undefined, partial bundles). Closes
the typeof-null trap in the proxy and the !Array.isArray-on-undefined
trap in the registry.

ContextMenuItem.invoke() now mirrors the captured-handle pattern at
buildHandle.execute: a closure captures the entry that produced the
menu item and refuses to dispatch when a later register({ id }) has
replaced it. A stale menu item returns false instead of firing the
new owner's handler with the old item's label/predicate/bundle.

Weakens the contextAt JSDoc claim about deterministic empty-bundle
defaults: non-numeric coords coerce to (0, 0), which is itself a
valid viewport point.

Three regression tests: invoke-after-replacement, partial-input
legacy routing ({ entities, point: null }), and isViewportContextBundle
boundaries (null point, missing x/y, non-object).
@codecov-commenter
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@caio-pizzol caio-pizzol merged commit 97e3526 into main May 5, 2026
69 checks passed
@caio-pizzol caio-pizzol deleted the caio/SD-2945-right-click-context branch May 5, 2026 18:55
@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 5, 2026

🎉 This PR is included in @superdoc-dev/react v1.2.0-next.99

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 5, 2026

🎉 This PR is included in vscode-ext v2.3.0-next.101

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 5, 2026

🎉 This PR is included in @superdoc-dev/mcp v0.3.0-next.57

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 5, 2026

🎉 This PR is included in superdoc v1.30.0-next.57

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 5, 2026

🎉 This PR is included in superdoc-cli v0.8.0-next.74

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 5, 2026

🎉 This PR is included in superdoc-sdk v1.8.0-next.57

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants