PedroBern / react-native-collapsible-tab-view

A cross-platform Collapsible Tab View component for React Native
MIT License
830 stars 161 forks source link

Kindly Update to react-navigation v6 #223

Closed siddharth-kt closed 2 years ago

siddharth-kt commented 2 years ago

Feature request

Hi @andreialecu @PedroBern, Kindly update https://github.com/PedroBern/react-native-collapsible-tab-view/tree/v2 to react-navigation version 6 and also add new updates/features to this (version 2.0.2) (if any) from latest version https://github.com/PedroBern/react-native-collapsible-tab-view. (4.4.0)

Current behavior

Currently it works on react-navigation version 5, but most people already shifted to react-navigation version 6.

Thanks

hirbod commented 2 years ago

Deleted old comment - I see you asked for a backport.

andreialecu commented 2 years ago

The current version (4+) does not have an official binding for react navigation but it works fine with RN6.

Here's how I'm using it, if this helps:

createCollapsibleTabNavigator.tsx:

import {
  createNavigatorFactory,
  DefaultNavigatorOptions,
  ParamListBase,
  TabActionHelpers,
  TabNavigationState,
  TabRouter,
  TabRouterOptions,
  useNavigationBuilder,
} from '@react-navigation/native';
import * as React from 'react';
import {useRef} from 'react';
import {StyleSheet, View} from 'react-native';
import {CollapsibleRef, Tabs} from 'react-native-collapsible-tab-view';
import {TabName} from 'react-native-collapsible-tab-view/lib/typescript/types';

// Props accepted by the view
export type TabNavigationConfig = {
  collapsibleOptions: Omit<
    React.ComponentPropsWithoutRef<typeof Tabs['Container']>,
    'children'
  >;
};

// Supported screen options
type TabNavigationOptions = {
  title?: string;
};

// Map of event name and the type of data (in event.data)
//
// canPreventDefault: true adds the defaultPrevented property to the
// emitted events.
type TabNavigationEventMap = {
  tabPress: {
    data: {isAlreadyFocused: boolean};
    canPreventDefault?: true;
  };
};

// The props accepted by the component is a combination of 3 things
type Props = DefaultNavigatorOptions<any, any, any, any> &
  TabRouterOptions &
  TabNavigationConfig;

function CollapsibleTabNavigator({
  initialRouteName,
  children,
  screenOptions,
  collapsibleOptions,
}: Props) {
  const {state, navigation, descriptors} = useNavigationBuilder<
    TabNavigationState<ParamListBase>,
    TabRouterOptions,
    TabActionHelpers<ParamListBase>,
    TabNavigationOptions,
    TabNavigationEventMap
  >(TabRouter, {
    children,
    screenOptions,
    initialRouteName,
  });
  const ref = useRef<CollapsibleRef<TabName>>();

  const onTabChange = React.useCallback(
    ({tabName}) => {
      navigation.emit({
        type: 'tabPress',
        target: tabName.toString(),
        data: {
          isAlreadyFocused:
            tabName.toString() === state.routes[state.index].name,
        },
      });
    },
    [navigation, state.index, state.routes],
  );

  return (
      <Tabs.Container
        ref={ref}
        {...collapsibleOptions}
        initialTabName={state.routeNames[state.index]}
        onTabChange={onTabChange}
      >
        {state.routes.map((route) => (
          <Tabs.Tab
            name={route.name}
            key={route.key}
            label={descriptors[route.key].options.title}
          >
            {descriptors[route.key].render()}
          </Tabs.Tab>
        ))}
      </Tabs.Container>
  );
}

export default createNavigatorFactory<
  TabNavigationState<ParamListBase>,
  TabNavigationOptions,
  TabNavigationEventMap,
  typeof CollapsibleTabNavigator
>(CollapsibleTabNavigator);

Used like:

const Tab = createCollapsibleNavigator();

...

          <Tab.Navigator collapsibleOptions={collapsibleOptions}>
             <Tab.Screen name="screen1" options={{ title: "Screen1 }}>
                {() => <Screen props={props} />}
Hannes-Endare commented 2 years ago
useEffect(() => {
    ref.current?.jumpToTab(state.routeNames[state.index]);
}, [state.index]);

@andreialecu you should also add this to make navigation to the tabs work

siddharth-kt commented 2 years ago

The current version (4+) does not have an official binding for react navigation but it works fine with RN6.

Here's how I'm using it, if this helps:

createCollapsibleTabNavigator.tsx:

import {
  createNavigatorFactory,
  DefaultNavigatorOptions,
  ParamListBase,
  TabActionHelpers,
  TabNavigationState,
  TabRouter,
  TabRouterOptions,
  useNavigationBuilder,
} from '@react-navigation/native';
import * as React from 'react';
import {useRef} from 'react';
import {StyleSheet, View} from 'react-native';
import {CollapsibleRef, Tabs} from 'react-native-collapsible-tab-view';
import {TabName} from 'react-native-collapsible-tab-view/lib/typescript/types';

// Props accepted by the view
export type TabNavigationConfig = {
  collapsibleOptions: Omit<
    React.ComponentPropsWithoutRef<typeof Tabs['Container']>,
    'children'
  >;
};

// Supported screen options
type TabNavigationOptions = {
  title?: string;
};

// Map of event name and the type of data (in event.data)
//
// canPreventDefault: true adds the defaultPrevented property to the
// emitted events.
type TabNavigationEventMap = {
  tabPress: {
    data: {isAlreadyFocused: boolean};
    canPreventDefault?: true;
  };
};

// The props accepted by the component is a combination of 3 things
type Props = DefaultNavigatorOptions<any, any, any, any> &
  TabRouterOptions &
  TabNavigationConfig;

function CollapsibleTabNavigator({
  initialRouteName,
  children,
  screenOptions,
  collapsibleOptions,
}: Props) {
  const {state, navigation, descriptors} = useNavigationBuilder<
    TabNavigationState<ParamListBase>,
    TabRouterOptions,
    TabActionHelpers<ParamListBase>,
    TabNavigationOptions,
    TabNavigationEventMap
  >(TabRouter, {
    children,
    screenOptions,
    initialRouteName,
  });
  const ref = useRef<CollapsibleRef<TabName>>();

  const onTabChange = React.useCallback(
    ({tabName}) => {
      navigation.emit({
        type: 'tabPress',
        target: tabName.toString(),
        data: {
          isAlreadyFocused:
            tabName.toString() === state.routes[state.index].name,
        },
      });
    },
    [navigation, state.index, state.routes],
  );

  return (
      <Tabs.Container
        ref={ref}
        {...collapsibleOptions}
        initialTabName={state.routeNames[state.index]}
        onTabChange={onTabChange}
      >
        {state.routes.map((route) => (
          <Tabs.Tab
            name={route.name}
            key={route.key}
            label={descriptors[route.key].options.title}
          >
            {descriptors[route.key].render()}
          </Tabs.Tab>
        ))}
      </Tabs.Container>
  );
}

export default createNavigatorFactory<
  TabNavigationState<ParamListBase>,
  TabNavigationOptions,
  TabNavigationEventMap,
  typeof CollapsibleTabNavigator
>(CollapsibleTabNavigator);

Used like:

const Tab = createCollapsibleNavigator();

...

          <Tab.Navigator collapsibleOptions={collapsibleOptions}>
             <Tab.Screen name="screen1" options={{ title: "Screen1 }}>
                {() => <Screen props={props} />}

ok then 👍