Skip to content

Add exclusive groups for dialogs - #1

Merged
enaboapps merged 1 commit into
mainfrom
exclusive-groups
Oct 9, 2026
Merged

enaboapps merged 1 commit into
mainfrom
exclusive-groups

Conversation

@enaboapps

Copy link
Copy Markdown
Contributor

Lets an open dialog confine scanning to itself. Switchify Remote needs this for its selector and PC switcher dialogs.

  • registerGroup(id, { exclusive: true }): while the group is registered, the scan tree starts at it. The most recently registered exclusive group wins, so nested dialogs work, and removing it returns to the page.
  • useScanGroup and <ScanGroup> accept exclusive.
  • Version bumped to 0.2.0.

Validation

  • npm test: 60 tests pass, including a new nested-dialog test.
  • npm run lint and npm run build are clean.

🤖 Generated with Claude Code

- While an exclusive group is registered, scanning is confined to it; the most recently registered one wins, and closing it returns to the page

- Pass exclusive through useScanGroup and ScanGroup, document it, and bump to 0.2.0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[Medium impact] Adds dialog scoping to the scanning navigation system.

Not safe to merge until the dialog-priority defect is fixed: updating an older dialog can activate its controls while a newer dialog remains open. The entered-state defect is non-blocking.

Findings

  1. P1 Older dialog steals scanning ▶
  2. P2 Dialog reports wrong entered state ▶
Fix with agent prompt
### Issue 1
src/react/index.tsx:235-236
Changing `order` on an older exclusive `ScanGroup` takes scanning away from a newer, still-open dialog. The registration effect cleans up the older group, deleting its exclusive priority, then registers it with a higher priority. The next Select activates a control in the older dialog even though the newer dialog remains mounted and exclusive.

Preserve exclusive priority across option updates and add a regression test for an older dialog updating while a newer one remains open. This must be fixed before merging.

### Issue 2
src/core/controller.ts:410
The exclusive group's ID disappears from `ScanSnapshot.path` because the new tree starts at its children. `useScanGroup` therefore reports `entered: false` even while scanning highlights and successfully activates an item inside that group. This is a non-blocking state-reporting defect: callers using `entered` for styling or feedback do not show that scanning is inside the dialog.

Include the exclusive scope in the reported path without adding a way to escape it.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

T-Rex evidence

Evidence from the check

  • The executed test mounts two exclusive groups and compares stable-order and changed-order rerenders against actual source, proving the candidate through snapshots and handler calls.

Command output from the check

  • The baseline command captures snapshots and actual selections before and after an unchanged-order rerender, showing that the newer dialog retains priority.

Command output from the check

  • The update command captures real effect cleanup and re-registration followed by snapshots and actual selections, showing that the older dialog steals priority.

Evidence from the check

  • This executed test mounts the real React scanning hooks, highlights and selects a group item, and checks snapshot and rendered state, demonstrating the exclusive-group reporting defect.

Command output from the check

  • The same test ran against isolated PR base source and passed both cases after entering the group and activating its item, establishing the pre-change comparison.

Command output from the check

  • The test ran against actual HEAD source and passed the normal baseline but failed the exclusive entered assertion after successful child activation, confirming candidate 1.

Evidence from the check

  • The executed test mounts two exclusive groups and compares stable-order and changed-order rerenders against actual source, proving the candidate through snapshots and handler calls.

Command output from the check

  • The baseline command captures snapshots and actual selections before and after an unchanged-order rerender, showing that the newer dialog retains priority.

Command output from the check

  • The update command captures real effect cleanup and re-registration followed by snapshots and actual selections, showing that the older dialog steals priority.

Evidence from the check

  • This executed test mounts the real React scanning hooks, highlights and selects a group item, and checks snapshot and rendered state, demonstrating the exclusive-group reporting defect.

Command output from the check

  • The same test ran against isolated PR base source and passed both cases after entering the group and activating its item, establishing the pre-change comparison.

Command output from the check

  • The test ran against actual HEAD source and passed the normal baseline but failed the exclusive entered assertion after successful child activation, confirming candidate 1.

View artifacts

Summary

Adds exclusive groups so an open dialog can limit scanning to its own controls.

  • Scanning stays inside the newest exclusive group and returns when it closes.

Reviews (1) · Last reviewed commit: "Add exclusive groups for dialogs" · Reviewed by Greptile

Comment thread src/react/index.tsx
Comment on lines +235 to +236
() => controller.registerGroup(id, { parentId: scope.id, order, exclusive }, anchor),
[controller, id, scope.id, order, exclusive, anchor],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Older dialog steals scanning

Changing order on an older exclusive ScanGroup takes scanning away from a newer, still-open dialog. The registration effect cleans up the older group, deleting its exclusive priority, then registers it with a higher priority. The next Select activates a control in the older dialog even though the newer dialog remains mounted and exclusive.

Preserve exclusive priority across option updates and add a regression test for an older dialog updating while a newer one remains open. This must be fixed before merging.

Artifacts

Evidence from the check

  • The executed test mounts two exclusive groups and compares stable-order and changed-order rerenders against actual source, proving the candidate through snapshots and handler calls.

Command output from the check

  • The baseline command captures snapshots and actual selections before and after an unchanged-order rerender, showing that the newer dialog retains priority.

Command output from the check

  • The update command captures real effect cleanup and re-registration followed by snapshots and actual selections, showing that the older dialog steals priority.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/react/index.tsx
Line: 235-236

Comment:
**Older dialog steals scanning**

Changing `order` on an older exclusive `ScanGroup` takes scanning away from a newer, still-open dialog. The registration effect cleans up the older group, deleting its exclusive priority, then registers it with a higher priority. The next Select activates a control in the older dialog even though the newer dialog remains mounted and exclusive.

Preserve exclusive priority across option updates and add a regression test for an older dialog updating while a newer one remains open. This must be fixed before merging.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment thread src/core/controller.ts
latest = order;
}
}
return build(scope, scope === undefined ? new Set() : new Set([scope]));

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 Dialog reports wrong entered state

The exclusive group's ID disappears from ScanSnapshot.path because the new tree starts at its children. useScanGroup therefore reports entered: false even while scanning highlights and successfully activates an item inside that group. This is a non-blocking state-reporting defect: callers using entered for styling or feedback do not show that scanning is inside the dialog.

Include the exclusive scope in the reported path without adding a way to escape it.

Artifacts

Evidence from the check

  • This executed test mounts the real React scanning hooks, highlights and selects a group item, and checks snapshot and rendered state, demonstrating the exclusive-group reporting defect.

Command output from the check

  • The same test ran against isolated PR base source and passed both cases after entering the group and activating its item, establishing the pre-change comparison.

Command output from the check

  • The test ran against actual HEAD source and passed the normal baseline but failed the exclusive entered assertion after successful child activation, confirming candidate 1.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/core/controller.ts
Line: 410

Comment:
**Dialog reports wrong entered state**

The exclusive group's ID disappears from `ScanSnapshot.path` because the new tree starts at its children. `useScanGroup` therefore reports `entered: false` even while scanning highlights and successfully activates an item inside that group. This is a non-blocking state-reporting defect: callers using `entered` for styling or feedback do not show that scanning is inside the dialog.

Include the exclusive scope in the reported path without adding a way to escape it.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

@enaboapps
enaboapps merged commit d89cadb into main Oct 9, 2026
2 checks passed
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.

2 participants