import * as React from 'react' ; import { ItemsSource , Pager as NativeScriptPager , PagerItem as NativeScriptPagerItem } from '../' ; import { registerElement } from 'react-nativescript' ; import { Orientation } from '../' ; registerElement ( 'pager' , ( ) => require ( '../' ) . Pager ) ; registerElement ( 'pagerItem' , ( ) => require ( '../' ) . PagerItem ) ; import { Template , Color } from '@nativescript/core' ; import { PercentLength } from '@nativescript/core' ; import { View , KeyedTemplate } from "@nativescript/core" ; import { render as RNSRender , unmountComponentAtNode , NSVRoot , NSVElement , ViewAttributes , NativeScriptProps , GridLayoutAttributes } from "react-nativescript" ; export declare type PagerAttributes = ViewAttributes & { items ? : any ; selectedIndex : number ; onItemLoading ? : ( args : any ) => void ; itemIdGenerator ? : ( item : any , index : number , items : any ) => number ; itemTemplate ? : string | Template ; itemTemplateSelector ? : string | ( ( item : any , index : number , items : any ) => string ) ; itemTemplates ? : string | KeyedTemplate [ ] ; canGoRight : boolean ; canGoLeft : boolean ; spacing : PercentLength | string ; peaking : PercentLength | string ; perPage : number ; orientation : Orientation ; transformers : string ; loadMoreCount : number ; disableSwipe : boolean ; indicator : any ; showIndicator : boolean ; indicatorColor : Color | string ; indicatorSelectedColor : Color | string ; ios ? : any ; android ? : any ; } ; export type CellViewContainer = View ; type CellFactory = ( item : any ) => React . ReactElement ; type OwnProps = { items : ItemsSource | any [ ] ; /** User may specify cellFactory for single-template or cellFactories for multi-template. */ cellFactory ? : CellFactory ; cellFactories ? : Map < string , { placeholderItem : any ; cellFactory : CellFactory ; } > ; onSelectedIndexChange ? ( args ) : void ; onSelectedIndexChanged ? ( args ) : void ; scroll ? ( args ) : void ; swipe ? ( args ) : void ; swipeStart ? ( args ) : void ; swipeOver ? ( args ) : void ; swipeEnd ? ( args ) : void ; onLoadMoreItems ? : ( args : any ) => void ; _debug ? : { logLevel : "debug" | "info" ; onCellFirstLoad ? : ( container : CellViewContainer ) => void ; onCellRecycle ? : ( container : CellViewContainer ) => void ; } ; } & Omit < PagerAttributes , "onItemLoading" > ; type Props = OwnProps & { forwardedRef ? : React . RefObject < NSVElement < NativeScriptPager > > ; } ; type NumberKey = number | string ; type RootKeyAndTNSView = { rootKey : string ; nativeView : View ; } ; interface State { nativeCells : Record < NumberKey , CellViewContainer > ; nativeCellToItemIndex : Map < CellViewContainer , NumberKey > ; itemIndexToNativeCell ? : Map < NumberKey , CellViewContainer > ; } export class _Pager extends React . Component < Props , State > { static readonly defaultProps = { _debug : { logLevel : "info" as "info" , onCellFirstLoad : undefined , onCellRecycle : undefined , } , } ; constructor ( props ) { super ( props ) ; this . state = { nativeCells : { } , nativeCellToItemIndex : new Map ( ) , itemIndexToNativeCell : props . _debug . logLevel === "debug" ? new Map ( ) : undefined , } ; } private readonly myRef = React . createRef < NSVElement < NativeScriptPager > > ( ) ; private readonly argsViewToRootKeyAndRef : Map < View , RootKeyAndTNSView > = new Map ( ) ; private roots : Set < string > = new Set ( ) ; private readonly defaultOnItemLoading : ( args : any ) => void = ( args ) => { const { logLevel , onCellRecycle , onCellFirstLoad } = this . props . _debug ; const { items , itemTemplateSelector } = this . props ; const item = _Pager . isItemsSource ( items ) ? items . getItem ( args . index ) : items [ args . index ] ; const template = itemTemplateSelector ? typeof itemTemplateSelector === "string" ? itemTemplateSelector : ( itemTemplateSelector as ( ( item : any , index : number , items : any ) => string ) ) ( item , args . index , items ) : null ; const cellFactory = template === null ? this . props . cellFactory : this . props . cellFactories ? this . props . cellFactories . get ( template ) . cellFactory : this . props . cellFactory ; if ( typeof cellFactory === "undefined" ) { console . warn ( `Pager: No cell factory found, given template ${ template }!` ) ; return ; } let view = args . view ; if ( ! view ) { const rootKeyAndRef = this . renderNewRoot ( item , cellFactory ) ; args . view = rootKeyAndRef . nativeView ; this . argsViewToRootKeyAndRef . set ( args . view , rootKeyAndRef ) ; if ( onCellFirstLoad ) onCellFirstLoad ( rootKeyAndRef . nativeView ) ; } else { console . log ( `[Pager] existing view: ` , view ) ; if ( onCellRecycle ) onCellRecycle ( view as CellViewContainer ) ; const { rootKey , nativeView } = this . argsViewToRootKeyAndRef . get ( view ) ; if ( typeof rootKey === "undefined" ) { console . error ( `Unable to find root key that args.view corresponds to!` , view ) ; return ; } if ( ! nativeView ) { console . error ( `Unable to find ref that args.view corresponds to!` , view ) ; return ; } RNSRender ( cellFactory ( item ) , null , ( ) => { } , rootKey ) ; } } ; protected getNativeView ( ) { const ref = ( this . props . forwardedRef || this . myRef ) ; return ref . current ? ref . current . nativeView : null ; } private readonly renderNewRoot = ( item , cellFactory ) : RootKeyAndTNSView => { const node = this . getNativeView ( ) ; if ( ! node ) { throw new Error ( "Unable to get ref to Pager" ) ; } console . log ( `[Pager] no existing view.` ) ; const rootKey = `Pager-${ node . _domId }-${ this . roots . size . toString ( ) }` ; const root = new NSVRoot < View > ( ) ; RNSRender ( cellFactory ( item ) , root , ( ) => { } , rootKey ) ; this . roots . add ( rootKey ) ; return { rootKey , nativeView : root . baseRef . nativeView } ; } ; componentDidMount ( ) { const node = this . getNativeView ( ) ; if ( ! node ) { console . warn ( `React ref to NativeScript View lost, so unable to set item templates.` ) ; return ; } if ( this . props . cellFactories ) { const itemTemplates = [ ] ; this . props . cellFactories . forEach ( ( info , key ) => { const { placeholderItem , cellFactory } = info ; itemTemplates . push ( { key , createView : ( ) => { console . log ( `[Pager] item template "${ key }"` ) ; const rootKeyAndRef = this . renderNewRoot ( placeholderItem , cellFactory ) ; this . argsViewToRootKeyAndRef . set ( rootKeyAndRef . nativeView , rootKeyAndRef ) ; return rootKeyAndRef . nativeView ; } , } ) ; } ) ; node . itemTemplates = itemTemplates ; } } componentWillUnmount ( ) { this . roots . forEach ( root => unmountComponentAtNode ( root ) ) ; } public static isItemsSource ( arr ) { return typeof ( arr as ItemsSource ) . getItem === "function" ; } render ( ) { console . log ( `Pager's render()` ) ; const { forwardedRef , children , _debug , cellFactories , cellFactory , ... rest } = this . props ; return ( < pager { ... rest } onItemLoading = { this . defaultOnItemLoading } ref = { forwardedRef || this . myRef } children = { children } / > ) ; } } export type PagerItemAttributes = GridLayoutAttributes & { forwardedRef ? : React . RefObject < any > ; } ; export class _PagerItem extends React . Component < PagerItemAttributes , { } > { private readonly myRef = React . createRef < NSVElement < NativeScriptPagerItem > > ( ) ; private readonly item = new NativeScriptPagerItem ( ) ; componentDidMount ( ) { const { forwardedRef } = this . props ; const view = ( forwardedRef || this . myRef ) . current ! . nativeView ; const parent = view && view . parent ? view . parent : null ; if ( parent ) { parent . _removeView ( view ) ; this . item . addChild ( view ) ; parent . _addChildFromBuilder ( 'PagerItem' , this . item ) ; } } render ( ) { const { forwardedRef , onPropertyChange , children , ... rest } = this . props ; return React . createElement ( 'pagerItem' , { ... rest , ref : forwardedRef || this . myRef , } , children ) ; } } export const Pager = React . forwardRef < NSVElement < NativeScriptPager > , OwnProps > ( ( props , ref ) => { return < _Pager { ... props } forwardedRef = { ref } / > ; } ) ; export const PagerItem = React . forwardRef < NSVElement < NativeScriptPagerItem > , PagerItemAttributes > ( ( props , ref ) => { return < _PagerItem { ... props } forwardedRef = { ref } / > ; } ) ; declare global { module JSX { interface IntrinsicElements { pager : NativeScriptProps < PagerAttributes , NativeScriptPager > ; pagerItem : NativeScriptProps < PagerItemAttributes , NativeScriptPagerItem > ; } } }