Skip to content

Conversation

@edison-cy-yang
Copy link
Contributor

@edison-cy-yang edison-cy-yang commented Nov 19, 2025

Remaining tasks

  • keyboardAvoidingBehavior prop not implemented
  • avoidKeyboardLikeIOS prop not implemented
  • modalForLargeScreens style not applied
  • Mock BottomSheetModal and BottomSheetScrollView in MockBottomSheet
  • Make sure this builds for the doc site
  • Unit test, should be able to reuse existing test with minimal modifications
  • Copy all the changes to ContentOverlay, there should be no rebuilt.

We also need to go through existing ContentOverlay usages and find out what kind of inputs are currently being used. I realized BottomSheet.InputText may not be the only wrapper input component we need. To recap, BottomSheet.InputText is a wrapper around InputText that implements onFocus and onBlur to properly position keyboard against these inputs. If we do indeed need more wrapper inputs, we will need to follow the pattern in BottomSheet.InputText for every input component, and replace each existing instance 🥲

This PR targets #2803, but does not depend on it.

Motivations

Changes

Added

Changed

Deprecated

Removed

Fixed

Security

Testing

ContentOverlay.rebuilt.tsx is created for the sake of testing the old version and compare against the new one in simulator. This should not be a rebuilt and should completely replace ContentOverlay.tsx

To test with live linking:

  • Export these from the ContentOverlay barrel
export { ContentOverlayRebuilt } from "./ContentOverlay.rebuilt";
export type { ContentOverlayRebuiltRef } from "./types";
  • Add ContentOverlayRebuilt to meta.json
  • Follow the mobile Atlantis live linking guide, so you can have ContentOverlay and ContentOverlayRebuilt side by side

Changes can be
tested via Pre-release


In Atlantis we use Github's built in pull request reviews.

Very buggy problem with the scrollview. If the modal is at the top/fullscreen, and you drag it downwards then upwards, it rapidly fluctuates nativeEvent.contentOffset.y as if you're scrolling... but you're not.. the modal is just moving its position back to the top.

My previous commit attempted to reduce this flicker, but it wasn't working great.

RN offers scrollTop on ScrollView (https://reactnative.dev/docs/element-nodes#web-compatible-api) and BottomSheetScrollView wraps ScrollView, so we have access to it.

Accessing scrollTop appears to be way more reliable than nativeEvent.contentOffset.y which is constantly fluctuating as you're moving the modal upwards.
style: (isOpen ? undefined : { display: "none" }) as any,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
...(props as any),
style: isOpen ? undefined : { display: "none" },
Copy link
Contributor

Choose a reason for hiding this comment

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

Noticed a bunch of any casting and props passing appeared to be unnecessary, so removed until we determine a need for that.

Comment on lines +127 to +129
const handleOnScroll = () => {
const scrollTop = scrollViewRef.current?.scrollTop || 0;
setShowHeaderShadow(scrollTop > 0);
Copy link
Contributor

Choose a reason for hiding this comment

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

The old code (further down below) was using this:

setShowHeaderShadow(nativeEvent.contentOffset.y > 0);

However, with the new modal library.. that value was constantly fluctuating in the case shown below. For some reason, it triggers this scroll event when you're moving the modal upwards:

Screen.Recording.2025-12-04.at.2.39.58.PM.mov

After a bit of digging, I found that RN supports scrollTop on the native ScrollView which is what BottomSheetScrollView uses internally. This allows us to use a much more stable/reliable value which seems to work great:

Screen.Recording.2025-12-04.at.2.34.45.PM.mov

@jdeichert jdeichert force-pushed the JOB-140606-implement-it-in-content-overlay branch from f7128c0 to 6a9a82d Compare December 5, 2025 16:55
jdeichert and others added 11 commits December 5, 2025 08:59
…bottom-sheet-and-replace-react-native-modalize' into JOB-140606-implement-it-in-content-overlay
No longer needed
…bottom-sheet-and-replace-react-native-modalize' into JOB-140606-implement-it-in-content-overlay
Historically we've mocked these libraries, but that doesn't seem required anymore?

https://docs.swmansion.com/react-native-reanimated/docs/3.x/guides/testing/

The only case we need to mock is isFabricInstalled because of a current bug in @gorhom/bottom-sheet
…bottom-sheet-and-replace-react-native-modalize' into JOB-140606-implement-it-in-content-overlay
Base automatically changed from JOB-140604-install-react-native-bottom-sheet-and-replace-react-native-modalize to master December 8, 2025 21:31
We realized this file is actually exported as part of our package, so that's why reanimated's mock was duplicated between this file and __mocks.ts.

Restored that and moved `require("react-native-reanimated").setUpTests()` to our __mocks.ts file.
Comment on lines +124 to +127
if (reactTag) {
AccessibilityInfo.setAccessibilityFocus(reactTag);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Just something from my todo list, we should double check this logic works, maybe add a test if possible.

Comment on lines +143 to +145
// TODO: Add large screen styles?
// windowWidth > 640 ? styles.modalForLargeScreens : undefined,
{ backgroundColor: getModalBackgroundColor(modalBackgroundColor, tokens) },
Copy link
Contributor

Choose a reason for hiding this comment

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

TODO: handle large screen modals. We have a "modalForLargeScreens" subtask for this.

@ZakaryH ZakaryH force-pushed the JOB-140606-implement-it-in-content-overlay branch from 2ac1ab3 to d21849e Compare January 7, 2026 19:32

const draggable = onBeforeExit ? false : isDraggable;
// Prevent the Overlay from being flush with the top of the screen, even if we are "100%" or "fullscreen"
const topInset = insets.top || tokens["space-larger"];
Copy link
Contributor

@ZakaryH ZakaryH Jan 8, 2026

Choose a reason for hiding this comment

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

on Android the top inset is coming back as 0, resulting in the overlay being flush against the top bar of the device

it seems we always want a gap, even if it's "fullscreen" and while this works for iOS we need to provide a value for Android.

the alternative is to set snap points that are NOT 100%, which would do the same thing but it makes the code a little more complicated since iOS would have both the insets and the reduced snap point.

we could remove the insets altogether if we want, and strictly use snappoints... though that will likely get interesting with the dynamic sizing because we don't use snap points there so this might be the best given our goal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants