import React, { ReactElement } from 'react'; import { StyleSheet } from 'react-native'; import { TSEventEmitter } from '@dominicstop/ts-event-emitter'; import type { NavigationObject } from '../types/NavigationObject'; import type { RouteOptions } from '../types/RouteOptions'; import type { RenderNavItem, RenderRouteContent } from '../types/NavTypes'; import type { OnRoutePopEvent, OnRoutePushEvent, OnPressNavBarItemEvent, OnRouteFocusEvent, OnRouteBlurEvent, OnUpdateSearchResultsEvent, OnSearchBarCancelButtonClickedEvent, OnSearchBarSearchButtonClickedEvent, OnWillDismissSearchControllerEvent, OnDidDismissSearchControllerEvent, OnWillPresentSearchControllerEvent, OnDidPresentSearchControllerEvent } from '../types/RNINavigatorRouteViewEvents'; import type { RouteTransitionConfig } from '../types/NavigationCommands'; import type { Nullish } from '../types/UtilityTypes'; import type { RouteSearchControllerState } from '../types/RouteSearchControllerState'; import { NavigatorRouteViewEventEmitter, NavigatorRouteViewEvents } from '../types/NavigatorRouteViewEventEmitter'; import type { NavigatorView } from './NavigatorView'; import type { RouteViewPortal } from './RouteViewPortal'; import { RouteComponentsWrapper } from '../wrapper_components/RouteComponentsWrapper'; import { NavigatorRouteContentWrapper } from '../wrapper_components/NavigatorRouteContentWrapper'; import { RouteHeaderWrapper } from '../wrapper_components/RouteHeaderWrapper'; import { RNINavigatorRouteView, RNINavigatorRouteViewProps } from '../native_components/RNINavigatorRouteView'; import { RNINavigatorRouteViewModule } from '../native_modules/RNINavigatorRouteViewModule'; import * as Helpers from '../functions/Helpers'; import { CompareRouteTransitionPopConfig, CompareRouteTransitionPushConfig } from '../functions/CompareRouteOptions'; import { CompareUtilities } from '../functions/CompareUtilities'; import { CompareRouteOptions } from '../functions/CompareRouteOptions'; import { NavigatorError, NavigatorErrorCodes } from '../functions/NavigatorError'; import { NavigationContext } from '../context/NavigationContext'; import { NavigatorUIConstantsContext } from '../context/NavigatorUIConstantsContext'; import { NativeIDKeys } from '../constants/LibraryConstants'; import { LIB_ENV } from '../constants/LibEnv'; //#region - Type Definitions export interface RouteContentProps { navigation?: NavigationObject; }; enum RouteStatus { INIT = "INIT" , ROUTE_PUSHING = "ROUTE_PUSHING" , ROUTE_PUSHED = "ROUTE_PUSHED" , ROUTE_POPPING = "ROUTE_POPPING" , ROUTE_POPPED = "ROUTE_POPPED" , ROUTE_BLURRING = "ROUTE_BLURRING", ROUTE_BLURRED = "ROUTE_BLURRED" , ROUTE_FOCUSING = "ROUTE_FOCUSING", ROUTE_FOCUSED = "ROUTE_FOCUSED" , UNMOUNTED = "UNMOUNTED" , }; export type NavigatorRouteViewProps = Pick & { navigatorID: number; routeProps: object | null; routeOptionsDefault : RouteOptions | null; isInFocus: boolean; transitionConfigPushOverride: Nullish; transitionConfigPopOverride : Nullish; getRefToNavigator: () => NavigatorView; renderRouteContent: RenderRouteContent; // render nav bar items renderNavBarLeftItem : RenderNavItem | null; renderNavBarRightItem: RenderNavItem | null; renderNavBarTitleItem: RenderNavItem | null; renderRouteHeader?: RenderNavItem; }; /** `NavigatorView` comp. state */ type NavigatorRouteViewState = { updateIndex: number; routeOptionsOverride: Nullish; routeOptionsPortal: Nullish; hasRoutePortal: boolean; }; //#endregion export class NavigatorRouteView extends React.Component { //#region - Property Declarations routeStatus: RouteStatus; /** is incremented whenever `props.routeProps` changes */ private routePropsUpdateIndex = 0; private isPushed = false; // references private _emitter: NavigatorRouteViewEventEmitter; private _navigatorRef : NavigatorView; private _nativeRef ?: React.Component; private _routeViewPortalRef?: RouteViewPortal; private _routeContentRef = React.createRef(); private _routeHeaderWrapperRef = React.createRef(); private _routeComponentsWrapperRef = React.createRef();; //#endregion constructor(props: NavigatorRouteViewProps){ super(props); this.routeStatus = RouteStatus.INIT; this._emitter = new TSEventEmitter(); this._navigatorRef = props.getRefToNavigator(); this.state = { updateIndex: 0, hasRoutePortal: false, routeOptionsOverride: null, routeOptionsPortal: null, }; }; shouldComponentUpdate(nextProps: NavigatorRouteViewProps, nextState: NavigatorRouteViewState){ const prevProps = this.props; const prevState = this.state; const didRoutePropsChange = !CompareUtilities.unwrapAndShallowCompareObject( prevProps.routeProps, nextProps.routeProps ); if(didRoutePropsChange) this.routePropsUpdateIndex++; // note: short-circuit eval so: // * value types first // * complex/nested objects last return ( didRoutePropsChange // props: compare `routeIndex` - routes were re-arranged/sorted || (prevProps.routeIndex !== nextProps.routeIndex) // props: compare focus change || (prevProps.isInFocus !== nextProps.isInFocus) // state: compare `hasRoutePortal` - portal comp. added/removed || (prevState.hasRoutePortal !== nextState.hasRoutePortal) // state: compare `updateIndex` - force an update || (prevState.updateIndex !== nextState.updateIndex) // props: compare "push transition config" || !CompareRouteTransitionPushConfig.unwrapAndCompare( prevProps.transitionConfigPushOverride, nextProps.transitionConfigPushOverride ) // props: compare "pop transition config" || !CompareRouteTransitionPopConfig.unwrapAndCompare( prevProps.transitionConfigPopOverride, nextProps.transitionConfigPopOverride ) // props: compare "default route options" || !CompareRouteOptions.unwrapAndCompare( prevProps.routeOptionsDefault , nextProps.routeOptionsDefault ) ); }; componentWillUnmount(){ //#region - 🐞 DEBUG 🐛 LIB_ENV.debugLog && console.log( `LOG/JS - NavigatorRouteView, componentWillUnmount` + ` - routeID: ${this.props.routeID}` + ` - routeIndex: ${this.props.routeIndex}` + ` - routeKey: ${this.props.routeKey}` ); //#endregion this.routeStatus = RouteStatus.UNMOUNTED; }; updateRouteComponents(){ // don't allow update until it's pushed if(!this.isPushed) return; this._routeHeaderWrapperRef .current?.requestUpdate(); this._routeComponentsWrapperRef.current?.requestUpdate(); }; //#region - "get ref" Functions public getRefToNavigator = () => { return this.props.getRefToNavigator(); }; public getRouteRef = () => { return this; }; public getEmitterRef = () => { return this._emitter; }; public getPortalRef = () => { return this._routeViewPortalRef; }; //#endregion //#region - Public Functions /** Combines all the route configs into one */ public getRouteOptions = (): RouteOptions => { const props = this.props; const state = this.state; const routeOptionsDefault = props.routeOptionsDefault ; const routeOptionsPortal = state.routeOptionsPortal; const routeOptionsOverride = state.routeOptionsOverride; const portalProps = this._routeViewPortalRef?.props; // check if portal has custom nav bar items const hasNavBarLeftItem = (portalProps?.renderNavBarLeftItem != null); const hasNavBarRightItem = (portalProps?.renderNavBarRightItem != null); return { // ------------------------------------------------------ // Technically, this whole thing could be done like this: // `{...foo, ...bar, ...baz}` // but it's less clear/explicit, idk refactor this later. // ------------------------------------------------------ statusBarStyle: ( routeOptionsOverride?.statusBarStyle ?? routeOptionsPortal ?.statusBarStyle ?? routeOptionsDefault ?.statusBarStyle ), routeContainerStyle: ( routeOptionsOverride?.routeContainerStyle ?? routeOptionsPortal ?.routeContainerStyle ?? routeOptionsDefault ?.routeContainerStyle ), automaticallyAddHorizontalSafeAreaInsets: ( routeOptionsOverride?.automaticallyAddHorizontalSafeAreaInsets ?? routeOptionsPortal ?.automaticallyAddHorizontalSafeAreaInsets ?? routeOptionsDefault ?.automaticallyAddHorizontalSafeAreaInsets ?? true ), // #region - Transition Config | // ----------------------------* transitionConfigPush: ( props.transitionConfigPushOverride ?? routeOptionsOverride?.transitionConfigPush ?? routeOptionsPortal ?.transitionConfigPush ?? routeOptionsDefault ?.transitionConfigPush ), transitionConfigPop: ( props.transitionConfigPopOverride ?? routeOptionsOverride?.transitionConfigPop ?? routeOptionsPortal ?.transitionConfigPop ?? routeOptionsDefault ?.transitionConfigPop ), // #endregion -------------* // #region - Navbar Config | // ------------------------* routeTitle: ( routeOptionsOverride?.routeTitle ?? routeOptionsPortal ?.routeTitle ?? routeOptionsDefault ?.routeTitle ?? props.routeKey ), prompt: ( routeOptionsOverride?.prompt ?? routeOptionsPortal ?.prompt ?? routeOptionsDefault ?.prompt ), largeTitleDisplayMode: ( routeOptionsOverride?.largeTitleDisplayMode ?? routeOptionsPortal ?.largeTitleDisplayMode ?? routeOptionsDefault ?.largeTitleDisplayMode ), searchBarConfig: ( routeOptionsOverride?.searchBarConfig ?? routeOptionsPortal ?.searchBarConfig ?? routeOptionsDefault ?.searchBarConfig ), // #endregion ----------------------------------* // #region - `NavigationConfigOverride`-related | // ---------------------------------------------* navBarAppearanceOverride: ( routeOptionsOverride?.navBarAppearanceOverride ?? routeOptionsPortal ?.navBarAppearanceOverride ?? routeOptionsDefault ?.navBarAppearanceOverride ), navigationBarVisibility: ( routeOptionsOverride?.navigationBarVisibility ?? routeOptionsPortal ?.navigationBarVisibility ?? routeOptionsDefault ?.navigationBarVisibility ), allowTouchEventsToPassThroughNavigationBar: ( routeOptionsOverride?.allowTouchEventsToPassThroughNavigationBar ?? routeOptionsPortal ?.allowTouchEventsToPassThroughNavigationBar ?? routeOptionsDefault ?.allowTouchEventsToPassThroughNavigationBar ?? false ), // #endregion ------------------* // #region - Navbar Item Config | // -----------------------------* navBarButtonBackItemConfig: ( routeOptionsOverride?.navBarButtonBackItemConfig ?? routeOptionsPortal ?.navBarButtonBackItemConfig ?? routeOptionsDefault ?.navBarButtonBackItemConfig ), navBarButtonLeftItemsConfig: ( routeOptionsOverride?.navBarButtonLeftItemsConfig ?? routeOptionsPortal ?.navBarButtonLeftItemsConfig ?? routeOptionsDefault ?.navBarButtonLeftItemsConfig ?? // custom left bar item was set, so we implicitly/automatically // create a `type: CUSTOM` nav bar item config... (hasNavBarLeftItem? [{ type: 'CUSTOM' }] : undefined) ), navBarButtonRightItemsConfig: ( routeOptionsOverride?.navBarButtonRightItemsConfig ?? routeOptionsPortal ?.navBarButtonRightItemsConfig ?? routeOptionsDefault ?.navBarButtonRightItemsConfig ?? // custom right bar item was set, so we implicitly/automatically // create a `type: CUSTOM` nav bar item config... (hasNavBarRightItem? [{ type: 'CUSTOM' }] : undefined) ), // #endregion ------------------------------* // #region - Navbar back button item config | // -----------------------------------------* leftItemsSupplementBackButton: ( routeOptionsOverride?.leftItemsSupplementBackButton ?? routeOptionsPortal ?.leftItemsSupplementBackButton ?? routeOptionsDefault ?.leftItemsSupplementBackButton ), backButtonTitle: ( routeOptionsOverride?.backButtonTitle ?? routeOptionsPortal ?.backButtonTitle ?? routeOptionsDefault ?.backButtonTitle ), backButtonDisplayMode: ( routeOptionsOverride?.backButtonDisplayMode ?? routeOptionsPortal ?.backButtonDisplayMode ?? routeOptionsDefault ?.backButtonDisplayMode ), hidesBackButton: ( routeOptionsOverride?.hidesBackButton ?? routeOptionsPortal ?.hidesBackButton ?? routeOptionsDefault ?.hidesBackButton ), applyBackButtonConfigToCurrentRoute: ( routeOptionsOverride?.applyBackButtonConfigToCurrentRoute ?? routeOptionsPortal ?.applyBackButtonConfigToCurrentRoute ?? routeOptionsDefault ?.applyBackButtonConfigToCurrentRoute ), // #endregion }; }; public getRouteNavigationObject = (): NavigationObject => { const props = this.props; const routeOptions = this.getRouteOptions(); return { routeOptions, // pass down route details/data routeID : props.routeID, routeKey : props.routeKey, routeIndex: props.routeIndex, routeProps: props.routeProps, // pass down navigator commands push : this._navigatorRef.push, pop : this._navigatorRef.pop, popToRoot : this._navigatorRef.popToRoot, removeRoute : this._navigatorRef.removeRoute, removeRoutes: this._navigatorRef.removeRoutes, replaceRoute: this._navigatorRef.replaceRoute, insertRoute : this._navigatorRef.insertRoute, setRoutes : this._navigatorRef.setRoutes, setNavigationBarHidden: this._navigatorRef.setNavigationBarHidden, // pass down misc. navigator commands sendCustomCommandToNative : this._navigatorRef.sendCustomCommandToNative, getNavigatorConstants : this._navigatorRef.getNavigatorConstants, getActiveRoutes : this._navigatorRef.getActiveRoutes, dismissModal : this._navigatorRef.dismissModal, getMatchingRouteStackItem : this._navigatorRef.getMatchingRouteStackItem, getNavigationObjectForRoute: this._navigatorRef.getNavigationObjectForRoute, // pass down convenience navigator commands replacePreviousRoute: this._navigatorRef.replacePreviousRoute, replaceCurrentRoute : this._navigatorRef.replaceCurrentRoute, removePreviousRoute : this._navigatorRef.removePreviousRoute, removeAllPrevRoutes : this._navigatorRef.removeAllPrevRoutes, // pass down misc. convenience navigation commands getRouteStackItemForCurrentRoute : this._navigatorRef.getRouteStackItemForCurrentRoute, getRouteStackItemForPreviousRoute : this._navigatorRef.getRouteStackItemForPreviousRoute, getNavigationObjectForCurrentRoute : this._navigatorRef.getNavigationObjectForCurrentRoute, getNavigationObjectForPreviousRoute: this._navigatorRef.getNavigationObjectForPreviousRoute, setRouteOptionsForRoute : this._navigatorRef.setRouteOptionsForRoute, getRouteOptionsForRoute : this._navigatorRef.getRouteOptionsForRoute, setRouteOptionsForCurrentRoute : this._navigatorRef.setRouteOptionsForCurrentRoute, getRouteOptionsForCurrentRoute : this._navigatorRef.getRouteOptionsForCurrentRoute, setRouteOptionsForPreviousRoute: this._navigatorRef.setRouteOptionsForPreviousRoute, getRouteOptionsForPreviousRoute: this._navigatorRef.getRouteOptionsForPreviousRoute, // navigator route commands getRouteOptions : this.getRouteOptions, setRouteOptions : this.setRouteOptions, setHidesBackButton : this.setHidesBackButton, getRouteConstants : this.getRouteConstants, getRouteSearchControllerState: this.getRouteSearchControllerState, setRouteSearchControllerState: this.setRouteSearchControllerState, // pass down 'get ref' functions getRefToRoute : this._handleGetRefToRoute, getRefToNavigator : props.getRefToNavigator, getRefToNavRouteEmitter: this._handleGetRefToNavRouteEmitter, }; }; public setRouteOptions = async ( routeOptionsOverride: Nullish> ) => { await Helpers.setStateAsync(this, (prevState) => ({ ...prevState, routeOptionsOverride, updateIndex: (prevState.updateIndex + 1), })); }; public setPortalRouteOptions = async ( routeOptionsPortal: Nullish> ) => { await Helpers.setStateAsync(this, (prevState) => ({ ...prevState, routeOptionsPortal, updateIndex: (prevState.updateIndex + 1), })); }; public setRouteViewPortalRef = (ref: RouteViewPortal) => { this._routeViewPortalRef = ref; this._routeHeaderWrapperRef .current?.setPortalRef(ref); this._routeComponentsWrapperRef.current?.setPortalRef(ref); this.setState({hasRoutePortal: true}); }; // Module Commands // --------------- public setHidesBackButton = async (isHidden: boolean, animated: boolean) => { try { if(!RouteViewUtils.isRouteReady(this.routeStatus)){ throw new NavigatorError({ code: NavigatorErrorCodes.libraryError, message: "'NavigatorRouteView' is not mounted" }); }; if(this._nativeRef == null){ throw new NavigatorError({ code: NavigatorErrorCodes.libraryError, message: "'this._nativeRef' is not set" }); }; await Helpers.promiseWithTimeout(1000, RNINavigatorRouteViewModule.setHidesBackButton( Helpers.getNativeNodeHandle(this._nativeRef), isHidden, animated ) ); } catch(e){ throw new NavigatorError(e); }; }; public getRouteConstants = async () => { try { if(!RouteViewUtils.isRouteReady(this.routeStatus)){ throw new NavigatorError({ code: NavigatorErrorCodes.libraryError, message: "'NavigatorRouteView' is not mounted" }); }; if(this._nativeRef == null){ throw new NavigatorError({ code: NavigatorErrorCodes.libraryError, message: "'this._nativeRef' is not set" }); }; const result = await Helpers.promiseWithTimeout(1000, RNINavigatorRouteViewModule.getRouteConstants( Helpers.getNativeNodeHandle(this._nativeRef) ) ); return result; } catch(e){ throw new NavigatorError(e); }; }; public getRouteSearchControllerState = async () => { try { if(!RouteViewUtils.isRouteReady(this.routeStatus)){ throw new NavigatorError({ code: NavigatorErrorCodes.libraryError, message: "'NavigatorRouteView' is not mounted" }); }; if(this._nativeRef == null){ throw new NavigatorError({ code: NavigatorErrorCodes.libraryError, message: "'this._nativeRef' is not set" }); }; const result = await Helpers.promiseWithTimeout(1000, RNINavigatorRouteViewModule.getRouteSearchControllerState( Helpers.getNativeNodeHandle(this._nativeRef) ) ); return result; } catch(e){ throw new NavigatorError(e); }; }; public setRouteSearchControllerState = async ( state: Partial ) => { try { if(!RouteViewUtils.isRouteReady(this.routeStatus)){ throw new NavigatorError({ code: NavigatorErrorCodes.libraryError, message: "'NavigatorRouteView' is not mounted" }); }; if(this._nativeRef == null){ throw new NavigatorError({ code: NavigatorErrorCodes.libraryError, message: "'this._nativeRef' is not set" }); }; const result = await Helpers.promiseWithTimeout(1000, RNINavigatorRouteViewModule.setRouteSearchControllerState( Helpers.getNativeNodeHandle(this._nativeRef), state ) ); return result; } catch(e){ throw new NavigatorError(e); }; }; // #endregion // #region - Handlers private _handleGetRefToRoute = () => { return this; }; private _handleGetRefToNavRouteEmitter = () => { return this._emitter; }; // #endregion // #region - Native Event Handlers // Native Event Handlers for `RNINavigatorRouteView` private _handleOnRouteWillPop: OnRoutePopEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onRouteWillPop, event); this.routeStatus = RouteStatus.ROUTE_POPPING; }; private _handleOnRouteDidPop: OnRoutePopEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onRouteDidPop, event); this.routeStatus = RouteStatus.ROUTE_POPPED; }; private _handleOnRouteWillPush: OnRoutePushEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onRouteWillPush, event); this.routeStatus = RouteStatus.ROUTE_PUSHING; }; private _handleOnRouteDidPush: OnRoutePushEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onRouteDidPush, event); this.routeStatus = RouteStatus.ROUTE_PUSHED; }; private _handleOnPressNavBarLeftItem: OnPressNavBarItemEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onPressNavBarLeftItem, event); }; private _handleOnPressNavBarRightItem: OnPressNavBarItemEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onPressNavBarRightItem, event); }; private _handleOnRouteWillFocus: OnRouteFocusEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onRouteWillFocus, event); this.routeStatus = RouteStatus.ROUTE_FOCUSING; }; private _handleOnRouteDidFocus: OnRouteFocusEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onRouteDidFocus, event); this.routeStatus = RouteStatus.ROUTE_FOCUSED; this.isPushed = true; }; private _handleOnRouteWillBlur: OnRouteBlurEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onRouteWillBlur, event); this.routeStatus = RouteStatus.ROUTE_BLURRING; }; private _handleOnRouteDidBlur: OnRouteBlurEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onRouteDidBlur, event); this.routeStatus = RouteStatus.ROUTE_BLURRED; }; private _handleOnUpdateSearchResults: OnUpdateSearchResultsEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onUpdateSearchResults, event); }; private _handleOnSearchBarCancelButtonClicked: OnSearchBarCancelButtonClickedEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onSearchBarCancelButtonClicked, event); }; private _handleOnSearchBarSearchButtonClicked: OnSearchBarSearchButtonClickedEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onSearchBarSearchButtonClicked, event); }; private _handleOnWillDismissSearchController: OnWillDismissSearchControllerEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onWillDismissSearchController, event); }; private _handleOnDidDismissSearchController: OnDidDismissSearchControllerEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onDidDismissSearchController, event); }; private _handleOnWillPresentSearchController: OnWillPresentSearchControllerEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onWillPresentSearchController, event); }; private _handleOnDidPresentSearchController: OnDidPresentSearchControllerEvent = (event) => { if(this.props.routeID !== event.nativeEvent.routeID) return; this._emitter.emit(NavigatorRouteViewEvents.onDidPresentSearchController, event); }; //#endregion private _renderRouteContents = (navigation: NavigationObject) => { const props = this.props; const routeOptions = navigation.routeOptions; const routeContent = props.renderRouteContent(); const routeContentWithProps = React.cloneElement(routeContent, { navigation, // store a ref to this element ...(Helpers.isClassComponent(routeContent) && { ref: this._routeContentRef, }), }); const portalProps = this._routeViewPortalRef?.props; const hasRouteHeader = ( portalProps?.renderRouteHeader != null || props .renderRouteHeader != null ); return ( {(context) => ( {routeContentWithProps} )} ); }; render(){ const props = this.props; const navigation = this.getRouteNavigationObject(); const routeOptions = navigation.routeOptions; //#region - 🐞 DEBUG 🐛 LIB_ENV.debugLogRender && console.log( `LOG/JS - NavigatorRouteView, render` + ` - routeID: ${props.routeID}` + ` - routeKey: ${props.routeKey}` + ` - routeKey: ${props.routeIndex}` ); //#endregion return( { this._nativeRef = r! }} routeID={props.routeID} nativeID={NativeIDKeys.NavRouteItem} routeKey={props.routeKey} routeIndex={props.routeIndex} // Route Native Events: Push/Pop Events onRouteWillPop={this._handleOnRouteWillPop} onRouteDidPop={this._handleOnRouteDidPop} onRouteWillPush={this._handleOnRouteWillPush} onRouteDidPush={this._handleOnRouteDidPush} // Route Native Events: Focus/Blur onRouteWillFocus={this._handleOnRouteWillFocus} onRouteDidFocus={this._handleOnRouteDidFocus} onRouteWillBlur={this._handleOnRouteWillBlur} onRouteDidBlur={this._handleOnRouteDidBlur} // Route Native Events: Navbar Item `onPress` onPressNavBarLeftItem={this._handleOnPressNavBarLeftItem} onPressNavBarRightItem={this._handleOnPressNavBarRightItem} // Route Native Events: Search onUpdateSearchResults={this._handleOnUpdateSearchResults} onSearchBarCancelButtonClicked={this._handleOnSearchBarCancelButtonClicked} onSearchBarSearchButtonClicked={this._handleOnSearchBarSearchButtonClicked} onWillDismissSearchController={this._handleOnWillDismissSearchController} onDidDismissSearchController={this._handleOnDidDismissSearchController} onWillPresentSearchController={this._handleOnWillPresentSearchController} onDidPresentSearchController={this._handleOnDidPresentSearchController} // pass down navbar item config, back button item config, etc. {...routeOptions} > {this._renderRouteContents(navigation)} ); }; }; class RouteViewUtils { static isRouteReady(routeStatus: RouteStatus){ return ( routeStatus !== RouteStatus.INIT && routeStatus !== RouteStatus.UNMOUNTED ); }; static isRouteFocusingOrFocused(routeStatus: RouteStatus){ return ( routeStatus === RouteStatus.ROUTE_PUSHING || routeStatus === RouteStatus.ROUTE_PUSHED || routeStatus === RouteStatus.ROUTE_FOCUSING || routeStatus === RouteStatus.ROUTE_FOCUSED ); }; }; const styles = StyleSheet.create({ navigatorRouteView: { ...StyleSheet.absoluteFillObject, // don't show opacity: 0, }, });