[drawer] Prevent dismiss through swipe when the component is controlled#4133
[drawer] Prevent dismiss through swipe when the component is controlled#4133flaviendelangle wants to merge 6 commits intomui:masterfrom
Conversation
commit: |
Bundle size report
Check out the code infra dashboard for more information about this PR. |
✅ Deploy Preview for base-ui ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
| // In controlled mode, don't update internal state. | ||
| // The parent must update the `open` prop for the state to change. | ||
| // Cancel the event so callers (e.g. DrawerViewport.onDismiss) clean up properly. | ||
| if (this.state.openProp !== undefined) { | ||
| eventDetails.cancel(); | ||
| return; | ||
| } |
There was a problem hiding this comment.
This seems too broad and is likely to break other cases. Indeed that's what Codex found:
PR #4133 review findings (2 regressions)
Summary
This PR fixes controlled Drawer swipe-dismiss cleanup and adds a test, but introduces two controlled-mode regressions that should be addressed before merge.
Details
-
[P1] Controlled
Dialog/Drawerno longer emitopenchangeDialogStore.setOpennow cancels+returns in controlled mode beforeopenchangeemit.FloatingFocusManagerusesopenchangeto compute close interaction type and return-focus behavior.- Impact: controlled
finalFocus={(type) => ...}and outside-press focus return behavior can become stale/incorrect.
-
[P2] Controlled Drawer with snap points can restore previous snap point after swipe-close
- Forced cancel in controlled mode makes Drawer swipe dismiss always follow the canceled-cleanup branch.
- That branch restores the pending snap point, which can conflict with the default snap-point reset on close.
- Impact: if parent accepts close (
open=false), reopening may start at the old snap point instead of default.
There was a problem hiding this comment.
Aren't we doing to much magic with the controlled value here then ?
I would love to just have an internal state.open and if it's controlled then I don't update it and nothing changes 🤔
There was a problem hiding this comment.
In the current architecture state.open is still used by internal selectors/consumers beyond rendering.
If we stop updating state.open in controlled mode, we regress at least:
- trigger open state (
data-popup-openviaisOpenedByTrigger), and DialogHandle.isOpen(it readsstore.state.open).
For this PR, I would keep the Drawer swipe fix localized in DrawerViewport, similar to the "workaround" I posted in the issue
PR #4133 updated review findings (2 regressions)
Summary
The latest update fixes the earlier openchange emission issue, but introduces two new controlled-mode regressions.
Details
-
[P1] Controlled
Dialog/Drawertriggers lose open stateDialogStore.setOpennow avoids updating internalstate.openin controlled mode.- Trigger-open state is still computed from
state.open(isOpenedByTrigger), andDialogTriggeruses that to set triggeropen/data-popup-open. - Impact: in standard controlled usage (
open+onOpenChange={setOpen}), popup can be open while trigger appears closed (data-popup-openmissing).
-
[P2]
DialogHandle.isOpenbecomes stale in controlled modeDialogHandle.isOpenreturnsstore.state.open.- With the new controlled-mode behavior,
state.openmay no longer track effective open state. - Impact:
handle.isOpencan report incorrect values (commonlyfalsewhile actually open).
fcc36cb to
f4c64ff
Compare
|
Codex still found an issue with the latest change, but it resolved the broader issues with the DialogStore PR #4133 latest review findings (2 issues)SummaryThe latest update narrows the fix to Details
|
Fixes #4119
Before
After