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.


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.

@jdeichert jdeichert marked this pull request as ready for review January 16, 2026 20:19
@jdeichert jdeichert requested a review from a team as a code owner January 16, 2026 20:19
@github-actions
Copy link

github-actions bot commented Jan 16, 2026

Published Pre-release for 115d12f with versions:

  - @jobber/components-native@0.89.5-JOB-140606-115d12f.110+115d12f0b

To install the new version(s) for Mobile run:

npm install @jobber/components-native@0.89.5-JOB-140606-115d12f.110+115d12f0b

* deprecate legacy prop

* update props

* fully removed unused props
* uninstall modalize

* sync lockfile with npm i

* remove Modalize reference in override
* add ContentOverlayProvider, integrate with InputText to handle keyboard interactions

* avoid TS error, fix mock, add keyboard config props

* remove redundant test

* use interactive to prevent issues when no snap points

* prevent drag/pan in new way, always provide snap points to fix keyboard dismiss restoration

* add context for our single snap point entry

* use simpler callback for onClose

* add a couple tests

* handle large screen modal flow

* remove unnecessary ContentOverlay useEffect

* update draggable logic and comments

* replace provider in tests

* remove low value tests
export default meta;
type Story = StoryObj<typeof meta>;

const BasicTemplate = () => {
Copy link
Contributor

@jdeichert jdeichert Jan 19, 2026

Choose a reason for hiding this comment

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

In the docs site ContentOverlay config, need to adjust the storybook link to go to the new v9 mobile instance instead of the old v7:

Image

// While we no longer need to adhere to this somewhat awkward behavior, we will leave it as is until a larger refactor.
if (onBeforeExit) {
return false;
}
Copy link
Contributor

@jdeichert jdeichert Jan 19, 2026

Choose a reason for hiding this comment

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

Throwing this comment here as it's related.

When I supply onBeforeExit, the new ContentOverlay is not fullscreen and also is not dismissible at all (no dismiss button, no swipe down, no clickaway handling). I'm unsure whether the lack of fullscreen is a problem, but the lack of dismiss functionality seems odd. Actually, adding the fullScreen prop solves both of the problems above. But even without fullScreen, I'm pretty sure we might expect it to be at least dismissible with swipe down.

Is that expected or a bug?

Screen.Recording.2026-01-19.at.12.47.21.PM.mov

Here's my test case, note that InnerContent is just a few Text nodes.

<ContentOverlay
      ref={overlayRef}
      title="Welcome NEW!"
      onBeforeExit={() => {
        overlayRef.current?.close?.();
      }}
>
      <InnerContent />
</ContentOverlay>

Copy link
Contributor

Choose a reason for hiding this comment

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

good catch. one of those issues is from the draggable logic for sure, I can address that one pretty easily.

aside from that though, there's a whole mess to untangle here. I'm going to take a swing at making a testable module and ideally a small table/chart because there are too many permutations and weird combinations that I'm not entirely sure what is expected in each case.

Copy link
Contributor

Choose a reason for hiding this comment

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

I know you already know this, but just following up here for posterity - I have a separate PR to address this: #2884

since it was originally built against the legacy ContentOverlay, it is the blueprint for the logic/behavior we expect.

it should be approximately equivalent now with the new library consuming and implementing those abstracted behavior descriptions - though there are a couple things that might behave a little bit different. I know there are at least 2 bugs in the old version.

the deprecated version of the component uses both showDismiss and shouldShowDismiss allowing related code & functionality to get out of sync

and there was a strange pan gesture interaction I encountered with the default props but I can't seem to reproduce it now. maybe it was only happening on Android.

Copy link
Contributor

Choose a reason for hiding this comment

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

hmmm it's still misbehaving. I'll have to fix that.

I think I know what the problem is now though at least!

Copy link
Contributor

Choose a reason for hiding this comment

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

ok I get it now. the old one has a bunch of really invalid combinations.

onBeforeExit + adjustToContentHeight means you cannot close it at all

you must explicitly set showDismiss={true} because otherwise it will fail all the other conditions for shouldShowDismiss and you now have no way to dismiss the overlay since both dragging and background presses have been disabled.

this component's props API is a nightmare. I guess I will reproduce the existing behavior to avoid making breaking changes but none of this makes any sense.

Copy link
Contributor

@jdeichert jdeichert Jan 22, 2026

Choose a reason for hiding this comment

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

I also don't like the old behaviour.. so if it's worth breaking this logic here to make an improvement and then double checking all existing usages are fine (maybe during the integration ticket), then I'm fine that!

Also fine with matching the old behaviour even though it doesn't make sense. I think we both know how much this component's API needs to be adjusted... so that sounds like a future ticket.

EDIT: I see you made the change in the other PR 👍

updateFormAndState(removedIOSCharValue);
}

function handleBottomSheetFocus(event?: FocusEvent) {
Copy link
Contributor

@jdeichert jdeichert Jan 19, 2026

Choose a reason for hiding this comment

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

Looks like Android's keyboard handling is behaving a bit weird.. shows a large blank space that takes up the scroll view container. Not sure if this is related to focus/blur handling here, or something configurable on the BottomSheetScrollView itself.

Screen.Recording.2026-01-19.at.1.58.41.PM.mov

Here's the code I used for testing... just throw some Texts and inputs in there for testing.

<ContentOverlay
  title="Welcome NEW!"
  scrollEnabled
>
  <InnerContent />
</ContentOverlay>

Copy link
Contributor

Choose a reason for hiding this comment

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

that was an issue I had at one point, however from my testing I have not seen it since I applied a fix so that's odd it's happening again for you.

would you mind sharing the specs of the emulator you're running it on?

Copy link
Contributor

Choose a reason for hiding this comment

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

DM'd but also posting here, my emulator is Pixel_3a_API_34_extension_level_7_arm64-v8

}));
}

function handleBottomSheetBlur(event?: FocusEvent) {
Copy link
Contributor

@jdeichert jdeichert Jan 19, 2026

Choose a reason for hiding this comment

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

Throwing this comment here, though not sure if it's related to this code.

Seeing some weird behaviour on a physical iOS device.. however it's an iPod Touch and on a really old iOS 15. So I'm not sure if we need to worry about this case, unless someone can repro on a more modern device.

When dismissing the keyboard with Done on the keyboard, it mostly seems to work fine. However, when dismissing the keyboard by tapping the ContentOverlay, the keyboard hides and leaves a blank white container taking up space.

ipod.ios.15.MP4

Copy link
Contributor

Choose a reason for hiding this comment

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

same as the other weird blank space keyboard thing you mentioned, I also saw this at one point but not since some fixes were applied.

notably this does happen on the OLD ContentOverlay with certain props. is there any chance this is rendering an instance of that?

if not, I'll have to try some other devices/iOS versions because neither my physical iOS device nor my simulators are exhibiting that behavior.

Copy link
Contributor

Choose a reason for hiding this comment

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

notably this does happen on the OLD ContentOverlay with certain props. is there any chance this is rendering an instance of that?

nope, definitely the new ContentOverlay! I DM'd you my QA branch for JM.

If we can't repro this on something more modern, we can resolve this thread 👍

ZakaryH and others added 4 commits January 21, 2026 11:56
…rity (#2884)

* add behavior computation module with tests, implement in ContentOverlay

* clean up tests

* update spelling for consistency

* update logic to mirror existing

* revert back to position for top logic
{renderHeader()}
<View testID="ATL-Overlay-Children">{children}</View>
</BottomSheetScrollView>
<BottomSheetView style={{ height: windowHeight }}>
Copy link
Contributor

Choose a reason for hiding this comment

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

Wow, that was it? Nice!

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm hoping so! it seems to have fixed it for me, fingers crossed that holds true.

I found this solution and one other one where someone was saying that a lack of a fixed height dimension on the parent was the issue. their fix was to apply a height to the entire app, but I was curious if you could do it for the scrollview parent instead.

https://stackoverflow.com/questions/75873878/react-native-gorhom-bottom-sheet-collapses-opens-when-keyboard-dismiss-or-input

…oller (#2889)

* add RNKC, use to fix SV issues in ContentOverlay

* prevent ts errors in mocks

* provide override for RNKC package

* add additional mocks for site

* add aliases for RN packages to avoid vite failures

* revert aliases, use exernal instead

* surgically correct package-lock state

* update package-lock dep locations
Copy link
Contributor

@jdeichert jdeichert left a comment

Choose a reason for hiding this comment

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

Approved 🎉

Refreshed the Blocked label as we're not planning on merging this until we do the integration work in JM.

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

Development

Successfully merging this pull request may close these issues.

4 participants