fix: render grab controls in the resolved owner's window - #15
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #14.
The problem
The control bar was always rendered by
ReactNativeGrabRoot, as a sibling of the root selection owner, wrapped inFullScreenOverlay. That wrapper isFullWindowOverlayon iOS andFragmenteverywhere else, so on Android the bar was just an absolutely positionedViewinside the main window's React tree. A sheet is presented in its own window, which stacks above the activity's content view regardless of anyzIndexinside it, so the bar was painted underneath it and there was no way to start a selection in the sheet from the controls. The same applied on iOS wheneverreact-native-screensis not installed and therequirefalls through toFragment.The change
The controls now belong to whichever owner resolves selection, so they render in the same native window as the content they act on.
GrabSelectionOwnerViewmounts them for the resolved owner and nothing else, which means a surface that owns selection hosts its own control bar inside the sheet's window.Three details came with it:
ReactNativeGrabRootnow callsuseDevMenu(toggleGrabMenu)directly andgrab-root-controls.tsxis replaced bygrab-controls.tsx.Dimensions.get("window"). Whenever a surface owns selection that container is a sheet rather than the whole screen, so the initial position and the drag clamping are derived fromonLayoutand re-clamped when the container resizes. The measured node sits insideFullScreenOverlay, so on iOS it is still window-sized and placement is unchanged there.gap-spaced flex container — the sheet playground's surfaces are — and absolutely positioned children are not flex items, so mounting the controls cannot disturb the owner's layout or the height anautodetent measures.FullScreenOverlayis deliberately kept. On iOS the bar continues to float above every window throughFullWindowOverlay, so that platform's behaviour is unchanged; Android simply gets a bar that is in the right window to begin with.Verification
npm run lint,npm run format:check,npm run build, and the 15 unit tests pass.Not yet verified on device. This is a UI change and it needs a pass on both platforms before merging: on Android that the bar shows over a presented TrueSheet and that Select there starts a session in the sheet, and on iOS that placement, dragging, and the sheet playground's
autodetent heights are unchanged.