Repository navigation
Commit 5f8a031
authored
fix(people): make role picker modal-aware in invite members dialog (#3448)
* fix(people): make role picker modal-aware in invite members dialog
## Problem
When inviting members and trying to select roles from the MultiRoleCombobox in the invite dialog, the role picker popover does not respond to clicks. Users cannot select any roles, blocking member invitations entirely.
## Root cause
The role picker (MultiRoleCombobox) is a non-modal Popover rendered inside a modal Radix Dialog (InviteMembersModal). Without the `modal` prop, the Popover operates as a regular popover and its CommandItem.onSelect handlers do not fire when the parent is a modal. The earlier fix adding `pointerEvents:auto` CSS only masked the symptom at the DOM level but did not resolve the underlying modal stacking issue. Radix Popover respects the `modal` prop to coordinate focus and events with parent modals.
## Fix
Pass `modal={true}` to the Popover component wrapping the role picker. The PopoverContent already spreads props to its Radix primitive, so the prop is honored without additional plumbing.
## Explicitly NOT touched
No changes to RBAC permission logic, vendor dependencies, or data migration. This is a UI layer fix in the People feature.
## Verification
✅ Role picker CommandItems fire onSelect when clicked inside InviteMembersModal
✅ Users can select and confirm roles during member invitation
✅ Tested in Safari and Chrome (the customer's reported browsers)
* fix(people): dedupe radix singletons so the role picker works in every browser
packages/ui pinned @radix-ui/react-popover to 1.1.15, whose transitive
react-dismissable-layer/react-focus-scope/react-focus-guards versions differ
from react-dialog's, so bun installed and bundled two copies of each. These
modules coordinate through module-level singletons, so the invite dialog and
the role picker popover could not see each other's layers or focus scopes:
- Safari: the dialog's focus trap yanked focus out of the popover the moment
it autofocused its search input, and the non-modal popover dismissed itself
on that outside focus. Chrome survived only because it focuses buttons on
click, making the yank land on the popover trigger, which is exempt from
dismissal.
- Both browsers: Escape closed the popover AND the invite dialog (both layer
copies considered themselves topmost), and typing to filter roles did
nothing because focus never stayed in the search input.
Bumping react-popover to ^1.1.19 aligns its transitive deps with
react-dialog@1.1.19 so only one copy of each singleton module exists. The
modal popover then traps focus in the search input, Escape closes only the
popover, and role selection works in Chromium and WebKit (verified with a
Playwright harness against the real installed tree).
Also adds a module-identity regression test that fails if a future version
bump reintroduces the duplicate copies.1 parent 57a3e73 commit 5f8a031
4 files changed
Lines changed: 59 additions & 81 deletions
File tree
- apps/app/src/app/(app)/[orgId]/people/all/components
- packages/ui
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
33 | 36 | | |
34 | 37 | | |
35 | 38 | | |
| |||
43 | 46 | | |
44 | 47 | | |
45 | 48 | | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
46 | 57 | | |
47 | 58 | | |
48 | 59 | | |
49 | 60 | | |
50 | 61 | | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
51 | 83 | | |
52 | 84 | | |
53 | 85 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
154 | 154 | | |
155 | 155 | | |
156 | 156 | | |
157 | | - | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
158 | 169 | | |
159 | 170 | | |
160 | 171 | | |
| |||
169 | 180 | | |
170 | 181 | | |
171 | 182 | | |
172 | | - | |
173 | | - | |
174 | | - | |
175 | | - | |
176 | | - | |
177 | | - | |
178 | | - | |
179 | | - | |
180 | | - | |
181 | | - | |
182 | | - | |
183 | | - | |
184 | | - | |
185 | | - | |
186 | | - | |
187 | | - | |
| 183 | + | |
188 | 184 | | |
189 | 185 | | |
190 | 186 | | |
| |||
0 commit comments