Skip to content

Expo 54: Scrolling is broken on iOS/Android and positioning is off on Android #351

@rshettyawaken

Description

@rshettyawaken

Hi! 👋

Firstly, thanks for your work on this project! 🙂

As I have clarified in the title, there are scroll and positioning related issues when we use this package in a project built with Expo 54

Here is the diff that solved my problem:

diff --git a/node_modules/react-native-copilot/dist/index.js b/node_modules/react-native-copilot/dist/index.js
index 3aff2e2..ad074f8 100644
--- a/node_modules/react-native-copilot/dist/index.js
+++ b/node_modules/react-native-copilot/dist/index.js
@@ -893,7 +893,7 @@ var CopilotProvider = (_a) => {
   const copilotEvents = (0, import_react8.useRef)((0, import_mitt.default)()).current;
   const modal = (0, import_react8.useRef)(null);
   const [visible, setVisibility] = useStateWithAwait(false);
-  const [scrollView, setScrollView] = (0, import_react8.useState)(null);
+  const scrollViewRef = (0, import_react8.useRef)(null);
   const {
     currentStep,
     currentStepNumber,
@@ -927,20 +927,17 @@ var CopilotProvider = (_a) => {
   );
   const setCurrentStep = (0, import_react8.useCallback)(
     (step, move = true) => __async(void 0, null, function* () {
-      var _a2;
       setCurrentStepState(step);
       copilotEvents.emit("stepChange", step);
-      if (scrollView != null) {
-        const nodeHandle = (0, import_react_native7.findNodeHandle)(scrollView);
-        if (nodeHandle) {
-          (_a2 = step == null ? void 0 : step.wrapperRef.current) == null ? void 0 : _a2.measureLayout(
-            nodeHandle,
-            (_x, y, _w, h) => {
-              const yOffset = y > 0 ? y - h / 2 : 0;
-              scrollView.scrollTo({ y: yOffset, animated: false });
-            }
-          );
-        }
+      if (scrollViewRef.current != null && step?.wrapperRef.current) {
+        step.wrapperRef.current.measure((_x, _y, _w, h, _pageX, pageY) => {
+          if (pageY !== undefined && h !== undefined) {
+            // Scroll so element appears in upper portion of screen
+            // leaving room for tooltip below
+            const yOffset = Math.max(0, pageY - 150);
+            scrollViewRef.current.scrollTo({ y: yOffset, animated: false });
+          }
+        });
       }
       setTimeout(
         () => {
@@ -948,16 +945,17 @@ var CopilotProvider = (_a) => {
             void moveModalToStep(step);
           }
         },
-        scrollView != null ? 100 : 0
+        scrollViewRef.current != null ? 100 : 0
       );
     }),
-    [copilotEvents, moveModalToStep, scrollView, setCurrentStepState]
+    [copilotEvents, moveModalToStep, setCurrentStepState]
   );
   const start = (0, import_react8.useCallback)(
     (fromStep, suppliedScrollView = null) => __async(void 0, null, function* () {
-      if (scrollView == null) {
-        setScrollView(suppliedScrollView);
+      if (suppliedScrollView != null) {
+        scrollViewRef.current = suppliedScrollView;
       }
+      
       const currentStep2 = fromStep ? steps[fromStep] : getFirstStep();
       if (startTries.current > MAX_START_TRIES) {
         startTries.current = 0;
@@ -980,7 +978,6 @@ var CopilotProvider = (_a) => {
       copilotEvents,
       getFirstStep,
       moveModalToStep,
-      scrollView,
       setCurrentStep,
       setVisibility,
       steps
@@ -1071,6 +1068,7 @@ function walkthroughable(WrappedComponent) {
 
 // src/components/CopilotStep.tsx
 var import_react11 = __toESM(require("react"));
+var import_react_native9 = require("react-native");
 var CopilotStep = ({
   name,
   order,
@@ -1086,9 +1084,15 @@ var CopilotStep = ({
       const measure2 = () => {
         if (wrapperRef.current != null && "measure" in wrapperRef.current) {
           wrapperRef.current.measure((_ox, _oy, width, height, x, y) => {
+            // Adjust for Android status bar
+            let adjustedY = y;
+            if (import_react_native9.Platform.OS === 'android') {
+              const statusBarHeight = import_react_native9.StatusBar.currentHeight || 0;
+              adjustedY = y + statusBarHeight;
+            }
             resolve({
               x,
-              y,
+              y: adjustedY,
               width,
               height
             });

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions