mohebifar / mohebifar/react-native-copilot

The problem of the new React Native

Open
#349 11 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
2.4k
Forks
428
PR merge metrics
No merged PRs in 30d

Description

Current Behavior
auto scroll doesn't work when switching between blocks - ref.measureLayout must be called with a ref to a native component.

import React, { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ScrollView, Text, TouchableOpacity, View, SafeAreaView, RefreshControl } from 'react-native';
import { CopilotProvider, CopilotStep, useCopilot, walkthroughable } from 'react-native-copilot';
import getCopilotLabel from '../../../../src/utils/helpers/getCopilotLabel';
import styles from './styles';

const WalkthroughableTouchableOpacity = walkthroughable(TouchableOpacity);

const mockSettingsData = [
  { id: '1', title: 'Wi-Fi Settings', type: 'setting' },
  { id: '2', title: 'Notification Settings', type: 'setting' },
  { id: '3', title: 'Sound Settings', type: 'setting' },
  { id: '4', title: 'Display Settings', type: 'setting' },
  { id: '5', title: 'Privacy Settings', type: 'setting' },
  { id: '7', title: 'Delete Device', type: 'danger' },
  { id: '8', title: 'Sound Settings', type: 'setting' },
  { id: '9', title: 'Display Settings', type: 'setting' },
  { id: '10', title: 'Privacy Settings', type: 'setting' },
  { id: '11', title: 'Delete Device', type: 'danger' },
  { id: '12', title: 'Sound Settings', type: 'setting' },
  { id: '13', title: 'Sound Settings', type: 'setting' },
  { id: '14', title: 'Display Settings', type: 'setting' },
  { id: '15', title: 'Privacy Settings', type: 'setting' },
  { id: '16', title: 'Delete Device', type: 'danger' },
  { id: '17', title: 'Sound Settings', type: 'setting' },
  { id: '18', title: 'Display Settings', type: 'setting' },
  { id: '19', title: 'Privacy Settings', type: 'setting' },
  { id: '20', title: 'Delete Device', type: 'danger' },
];

const SettingsScreenMock = () => {
  const { start } = useCopilot();
  const scrollViewRef = useRef(null);
  const [refreshing, setRefreshing] = useState(false);

  const onRefresh = () => {
    setRefreshing(true);
    setTimeout(() => setRefreshing(false), 1000);
  };

  const startTutorial = () => {
    start(false, scrollViewRef.current);
  };

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <View style={{ padding: 16 }}>
        <TouchableOpacity onPress={startTutorial} style={{ padding: 10, backgroundColor: '#007AFF', borderRadius: 8, marginBottom: 16 }}>
          <Text style={{ color: 'white', textAlign: 'center' }}>Start Tutorial</Text>
        </TouchableOpacity>
      </View>

      <ScrollView ref={scrollViewRef} style={{ flex: 1 }} refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} tintColor='#007AFF' />}>
        {mockSettingsData.map((item, index) => (
          <CopilotStep key={item.id} name={`step-${index}`} order={index} text={`This is step ${index + 1}: ${item.title}`}>
            <WalkthroughableTouchableOpacity
              style={{
                padding: 16,
                borderBottomWidth: 1,
                marginBottom: 50,
                borderBottomColor: '#EEE',
                backgroundColor: item.type === 'danger' ? '#FFF0F0' : 'white',
              }}
            >
              <Text style={{ color: item.type === 'danger' ? '#FF3B30' : '#000' }}>{item.title}</Text>
            </WalkthroughableTouchableOpacity>
          </CopilotStep>
        ))}

        {/* Дополнительные элементы для прокрутки */}
        {Array.from({ length: 10 }).map((_, index) => (
          <View key={`extra-${index}`} style={{ padding: 20, backgroundColor: index % 2 === 0 ? '#F5F5F5' : 'white' }}>
            <Text>Additional item {index + 1}</Text>
          </View>
        ))}
      </ScrollView>
    </SafeAreaView>
  );
};

const SettingsContainer = () => {
  const { t } = useTranslation('guides');
  const labels = getCopilotLabel(t);

  return (
    <CopilotProvider tooltipStyle={styles.copilot} stopOnOutsideClick androidStatusBarVisible labels={labels}>
      <SettingsScreenMock />
    </CopilotProvider>
  );
};

export default SettingsContainer;

Environment

  • Device: [e.g. iPhone 8 Simulator]
  • OS: [e.g. iOS12]
  • react-native-copilot: 3.3.3
    "react-native": "^0.79.6",
    "react-native-svg": "15.12.x",

Possible Solution

It is necessary to change the logic of working with the ref, because it changed when connecting Fabric

Additional context/Screenshots

https://github.com/user-attachments/assets/17ae6d94-d22c-4273-b883-e2d36018246f

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the useCopilot().start entry point and trace how the supplied scrollViewRef reaches ref.measureLayout when running the provided SettingsScreenMock on React Native 0.79.6 with Fabric. Reproduce the auto-scroll failure while switching between steps, then verify that tutorial transitions scroll to each walkthroughable component without the native-ref error.

Written by the indexing model from the issue text.

Assessment

Tech stack
react-native
Domain
mobile-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.