diff --git a/packages/compat/src/CompatScreen.tsx b/packages/compat/src/CompatScreen.tsx index 91d5cc4a..5e31c379 100644 --- a/packages/compat/src/CompatScreen.tsx +++ b/packages/compat/src/CompatScreen.tsx @@ -7,15 +7,18 @@ import { import ScreenPropsContext from './ScreenPropsContext'; import createCompatNavigationProp from './createCompatNavigationProp'; -type Props = { - navigation: NavigationProp; - route: RouteProp; +type Props = { + navigation: NavigationProp; + route: RouteProp; component: React.ComponentType; }; -function ScreenComponent(props: Props) { +function ScreenComponent( + props: Props +) { const navigation = React.useMemo( - () => createCompatNavigationProp(props.navigation, props.route), + () => + createCompatNavigationProp(props.navigation as any, props.route as any), [props.navigation, props.route] ); diff --git a/packages/compat/src/createCompatNavigationProp.tsx b/packages/compat/src/createCompatNavigationProp.tsx index f77a9ad3..545b3689 100644 --- a/packages/compat/src/createCompatNavigationProp.tsx +++ b/packages/compat/src/createCompatNavigationProp.tsx @@ -6,6 +6,7 @@ import { RouteProp, } from '@react-navigation/core'; import * as helpers from './helpers'; +import { CompatNavigationProp } from './types'; type EventName = 'willFocus' | 'willBlur' | 'didFocus' | 'didBlur' | 'refocus'; @@ -14,16 +15,21 @@ const blurSubscriptions = new WeakMap<() => void, () => void>(); const refocusSubscriptions = new WeakMap<() => void, () => void>(); export default function createCompatNavigationProp< - ParamList extends ParamListBase + NavigationPropType extends NavigationProp, + ParamList extends ParamListBase = NavigationPropType extends NavigationProp< + infer P + > + ? P + : ParamListBase >( - navigation: NavigationProp, + navigation: NavigationPropType, state: | (RouteProp & { state?: NavigationState | PartialState; }) | NavigationState | PartialState -) { +): CompatNavigationProp { return { ...navigation, ...Object.entries(helpers).reduce<{ @@ -179,5 +185,5 @@ export default function createCompatNavigationProp< return undefined; }, - }; + } as any; } diff --git a/packages/compat/src/createCompatNavigatorFactory.tsx b/packages/compat/src/createCompatNavigatorFactory.tsx index 1672bdc2..3084ed84 100644 --- a/packages/compat/src/createCompatNavigatorFactory.tsx +++ b/packages/compat/src/createCompatNavigatorFactory.tsx @@ -80,7 +80,7 @@ export default function createCompatNavigatorFactory< navigation, route, }: { - navigation: NavigationProp; + navigation: NavigationPropType; route: RouteProp & { state?: NavigationState | PartialState; }; @@ -101,10 +101,9 @@ export default function createCompatNavigatorFactory< typeof routeNavigationOptions === 'function' || typeof screenNavigationOptions === 'function' ? { - navigation: createCompatNavigationProp( - navigation, - route - ), + navigation: createCompatNavigationProp< + NavigationPropType + >(navigation, route), navigationOptions: defaultNavigationOptions || {}, screenProps, } diff --git a/packages/compat/src/index.tsx b/packages/compat/src/index.tsx index 350c65ad..2442b188 100644 --- a/packages/compat/src/index.tsx +++ b/packages/compat/src/index.tsx @@ -9,4 +9,12 @@ export { default as createCompatNavigatorFactory, } from './createCompatNavigatorFactory'; +export { + default as createCompatNavigationProp, +} from './createCompatNavigationProp'; + +export { default as useCompatNavigation } from './useCompatNavigation'; +export { default as withNavigation } from './withNavigation'; +export { default as withNavigationFocus } from './withNavigationFocus'; + export * from './types'; diff --git a/packages/compat/src/useCompatNavigation.tsx b/packages/compat/src/useCompatNavigation.tsx new file mode 100644 index 00000000..a932b54c --- /dev/null +++ b/packages/compat/src/useCompatNavigation.tsx @@ -0,0 +1,25 @@ +import * as React from 'react'; +import { + useNavigation, + useRoute, + NavigationProp, + ParamListBase, +} from '@react-navigation/core'; +import createCompatNavigationProp from './createCompatNavigationProp'; +import { CompatNavigationProp } from './types'; + +export default function useCompatNavigation< + T extends NavigationProp +>() { + const navigation = useNavigation(); + const route = useRoute(); + + return React.useMemo( + () => + createCompatNavigationProp( + navigation, + route as any + ) as CompatNavigationProp, + [navigation, route] + ); +} diff --git a/packages/compat/src/withNavigation.tsx b/packages/compat/src/withNavigation.tsx new file mode 100644 index 00000000..07220ee8 --- /dev/null +++ b/packages/compat/src/withNavigation.tsx @@ -0,0 +1,33 @@ +import * as React from 'react'; +import { NavigationProp, ParamListBase } from '@react-navigation/core'; +import useCompatNavigation from './useCompatNavigation'; +import { CompatNavigationProp } from './types'; + +type InjectedProps> = { + navigation: CompatNavigationProp; +}; + +export default function withNavigation< + T extends NavigationProp, + P extends InjectedProps, + C extends React.ComponentType

+>(Comp: C) { + const WrappedComponent = ({ + onRef, + ...rest + }: Exclude> & { + onRef?: C extends React.ComponentClass + ? React.Ref> + : never; + }): React.ReactElement => { + const navigation = useCompatNavigation(); + + // @ts-ignore + return ; + }; + + WrappedComponent.displayName = `withNavigation(${Comp.displayName || + Comp.name})`; + + return WrappedComponent; +} diff --git a/packages/compat/src/withNavigationFocus.tsx b/packages/compat/src/withNavigationFocus.tsx new file mode 100644 index 00000000..c52377aa --- /dev/null +++ b/packages/compat/src/withNavigationFocus.tsx @@ -0,0 +1,30 @@ +import * as React from 'react'; +import { useIsFocused } from '@react-navigation/core'; + +type InjectedProps = { + isFocused: boolean; +}; + +export default function withNavigationFocus< + P extends InjectedProps, + C extends React.ComponentType

+>(Comp: C) { + const WrappedComponent = ({ + onRef, + ...rest + }: Exclude & { + onRef?: C extends React.ComponentClass + ? React.Ref> + : never; + }): React.ReactElement => { + const isFocused = useIsFocused(); + + // @ts-ignore + return ; + }; + + WrappedComponent.displayName = `withNavigationFocus(${Comp.displayName || + Comp.name})`; + + return WrappedComponent; +}