Skip to content

fix: maintain topmost modal non-inert#3206

Merged
MartinCupela merged 1 commit into
masterfrom
fix/remove-inert-from-topmost-modal
Jun 4, 2026
Merged

fix: maintain topmost modal non-inert#3206
MartinCupela merged 1 commit into
masterfrom
fix/remove-inert-from-topmost-modal

Conversation

@MartinCupela
Copy link
Copy Markdown
Contributor

@MartinCupela MartinCupela commented Jun 3, 2026

🎯 Goal

When topmost modal was removed the inert property was not updated on the new topmost modal. This PR fixes it.

Summary by CodeRabbit

  • Bug Fixes

    • Improved dialog state tracking for more accurate open/closed status in DialogManager
    • Fixed modal focus management and keyboard navigation in stacked modals
    • Enhanced modal closing behavior to properly synchronize with open prop changes
    • Corrected tab index accessibility for topmost and underlying modals
  • Tests

    • Added comprehensive coverage for modal stacking scenarios and focus restoration
    • Enhanced test coverage for dialog state transitions and removal handling

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f9b1c9a6-555a-4b9a-be95-e4406ce38bbb

📥 Commits

Reviewing files that changed from the base of the PR and between 4c934ae and 98bd5df.

📒 Files selected for processing (4)
  • src/components/Dialog/__tests__/DialogsManager.test.ts
  • src/components/Dialog/service/DialogManager.ts
  • src/components/Modal/GlobalModal.tsx
  • src/components/Modal/__tests__/GlobalModal.test.tsx

📝 Walkthrough

Walkthrough

DialogManager's openedDialogIds stack now accurately tracks dialog open/closed state during settings updates, removal marking, and removal cancellation. GlobalModal syncs its open prop directly to dialog state and manages focus via conditional tabIndex. Tests verify stack transitions and focus restoration in stacked modal scenarios.

Changes

Dialog Focus and Stack Management

Layer / File(s) Summary
DialogManager openedDialogIds state transitions
src/components/Dialog/service/DialogManager.ts
getOrCreate conditionally rebuilds openedDialogIds based on isOpen state during settings updates; markForRemoval immediately removes the dialog id; cancelPendingRemoval conditionally restores it based on isOpen.
DialogManager removal and cancellation tests
src/components/Dialog/__tests__/DialogsManager.test.ts
New tests verify that markForRemoval removes the dialog from openedDialogIds immediately, and that cancelPendingRemoval (via getOrCreate) restores it when the dialog is isOpen.
GlobalModal open prop sync and focus management
src/components/Modal/GlobalModal.tsx
useEffect now closes the dialog when open becomes false and returns early; dialog surface tabIndex is set to 0 when topmost, −1 otherwise, to manage focus and interactivity of stacked modals.
GlobalModal stacked modal and focus restoration tests
src/components/Modal/__tests__/GlobalModal.test.tsx
New test fixtures (RemovableChildModalFixture, CloseChildModalFixture) and test cases verify tabIndex behavior in stacked scenarios and that underlying modals restore inert, aria-modal, and tabindex when the topmost modal closes via Escape or open prop changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • GetStream/stream-chat-react#3203: Both PRs modify DialogManager's openedDialogIds stack handling and topmost modal behavior for dialog removal and cancellation.

Suggested reviewers

  • arnautov-anton
  • oliverlaz

Poem

🐰 Modals stacking high, now they know their place,
Focus flows smoothly through dialog space,
When the topmost fades away with grace,
The layer below shines bright—no lost trace!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description includes the Goal section explaining the issue (inert property not updated on new topmost modal), but lacks Implementation details and UI Changes sections from the template. Add Implementation details section explaining how the fix works (state transitions, effect changes, tabindex updates) and clarify if UI Changes section is needed for this fix.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main fix: ensuring the topmost modal maintains non-inert state, which is the core issue addressed by the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/remove-inert-from-topmost-modal

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

Size Change: +75 B (+0.01%)

Total Size: 656 kB

📦 View Changed
Filename Size Change
dist/cjs/emojis.js 2.54 kB +1 B (+0.04%)
dist/cjs/index.js 255 kB +10 B (0%)
dist/cjs/ReactPlayerWrapper.js 545 B -1 B (-0.18%)
dist/cjs/useNotificationApi.js 49.8 kB +30 B (+0.06%)
dist/es/emojis.mjs 2.47 kB -2 B (-0.08%)
dist/es/index.mjs 251 kB +9 B (0%)
dist/es/useNotificationApi.mjs 48.6 kB +28 B (+0.06%)
ℹ️ View Unchanged
Filename Size
dist/cjs/audioProcessing.js 1.74 kB
dist/cjs/mp3-encoder.js 814 B
dist/css/emoji-picker.css 178 B
dist/css/emoji-replacement.css 456 B
dist/css/index.css 39.7 kB
dist/es/audioProcessing.mjs 1.65 kB
dist/es/mp3-encoder.mjs 768 B
dist/es/ReactPlayerWrapper.mjs 485 B

compressed-size-action

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 3, 2026

Codecov Report

❌ Patch coverage is 88.88889% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 83.81%. Comparing base (4c934ae) to head (98bd5df).

Files with missing lines Patch % Lines
src/components/Dialog/service/DialogManager.ts 80.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3206      +/-   ##
==========================================
- Coverage   83.85%   83.81%   -0.05%     
==========================================
  Files         439      439              
  Lines       13203    13212       +9     
  Branches     4280     4286       +6     
==========================================
+ Hits        11071    11073       +2     
- Misses       2132     2139       +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@MartinCupela MartinCupela merged commit 7ad98fa into master Jun 4, 2026
11 checks passed
@MartinCupela MartinCupela deleted the fix/remove-inert-from-topmost-modal branch June 4, 2026 14:10
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