Conversation
…r region Fix at the trigger level rather than checking modal state, so it applies universally to any overlay (modals, dialogs, command palette, etc.).
There was a problem hiding this comment.
We already have a regionMustBeElement option? Is that option still necessary? I remember getting the triggers to work correctly in all scenarios was pretty tricky and it took me a while to get right, so I'm a bit concerned that this will unexpectedly break triggers in places where we don't expect.
Just double check and make sure you're confident that this fix is the right one and is sustainable, and if regionMustBeElement is necessary.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## rc #2287 +/- ##
==========================================
- Coverage 64.25% 64.23% -0.02%
==========================================
Files 2178 2178
Lines 110433 110435 +2
Branches 8298 8291 -7
==========================================
- Hits 70956 70939 -17
- Misses 33407 33424 +17
- Partials 6070 6072 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Issue Pull Request
Linear Issue
SY-4145
Description
Suppress keyboard triggers when target is outside the trigger region.
Fixed at the trigger level rather than checking modal state, so it applies universally to any overlay (modals, dialogs, command palette, etc.).
Basic Readiness
Greptile Summary
This PR fixes keyboard trigger leakage in the Schematic by adding a DOM-containment check to
filterInRegion: in addition to the existing cursor bounding-box test, the new code requires the keyboard event's target to be either inside the region or an ancestor of it (e.g.document.body), blocking triggers whose target lives in a sibling subtree such as a modal input or command palette.Confidence Score: 4/5
Safe to merge with the minor caveat that spurious "end" events can fire without a prior "start" in the blocked-target scenario.
Only P2 findings — the core logic is correct and the new test adequately covers the fixed behaviour. The "end-without-start" issue is a pre-existing pattern that this PR makes newly reachable for the sibling case, but existing callers handle it gracefully.
pluto/src/triggers/hooks.ts — the unfiltered
removedpath at lines 69-77Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Keyboard event fires] --> B{region prop set?} B -- No --> Z[Pass trigger through] B -- Yes --> C{region.current null?} C -- Yes --> Y[Block all triggers] C -- No --> D{regionMustBeElement\nor Mouse trigger?} D -- Yes --> E{cursor in bbox\nAND target === region.current?} E -- Yes --> Z E -- No --> Y D -- No --> F{cursor in bbox?} F -- No --> Y F -- Yes --> G{"region.current.contains(target)\nOR target.contains(region.current)?"} G -- Yes --> Z G -- No --> Y[Block trigger — sibling subtree] style G fill:#d4edda,stroke:#28a745 style Y fill:#f8d7da,stroke:#dc3545 style Z fill:#d1ecf1,stroke:#17a2b8Comments Outside Diff (1)
pluto/src/triggers/hooks.ts, line 69-77 (link)"end"events without a preceding"start"With this change, a keyboard trigger's
"start"is now suppressed when the event target is in a sibling subtree (correct), but theremoveddiff is never passed throughfilterInRegion. That means when the keys are released after a blocked start, the callback is still called withstage: "end"even thoughstage: "start"was never fired.For callers like
useHeldRef, a spurious"end"is benign (purgeon an empty list is a no-op). But any caller that treats"start"and"end"as a matched pair (e.g. setting a loading state to true on start and false on end) could enter an inconsistent state here.Consider applying the same target-containment guard to
removed:Reviews (1): Last reviewed commit: "SY-4145: Suppress keyboard triggers when..." | Re-trigger Greptile