UNPKG

@nativescript-community/ui-pager

Version:

A NativeScript Pager / Carousel component that allows the user to swipe left and right through pages of data.

172 lines 7.37 kB
import * as React from 'react'; import { NSVRoot, render as RNSRender, registerElement, unmountComponentAtNode } from 'react-nativescript'; import { PagerItem as NativeScriptPagerItem } from '..'; registerElement('pager', () => require('../').Pager); registerElement('pagerItem', () => require('../').PagerItem); export class _Pager extends React.Component { constructor(props) { super(props); this.myRef = React.createRef(); this.argsViewToRootKeyAndRef = new Map(); this.roots = new Set(); this.defaultOnItemLoading = (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(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; } const view = args.view; if (!view) { const rootKeyAndRef = this.renderNewRoot(item, cellFactory); args.view = rootKeyAndRef.nativeView; /* Here we're re-using the ref - I assume this is best practice. If not, we can make a new one on each update instead. */ this.argsViewToRootKeyAndRef.set(args.view, rootKeyAndRef); if (onCellFirstLoad) onCellFirstLoad(rootKeyAndRef.nativeView); } else { console.log('[Pager] existing view: ', view); if (onCellRecycle) onCellRecycle(view); 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; } // args.view = null; RNSRender(cellFactory(item), null, () => { // console.log(`Rendered into cell! detachedRootRef:`); }, rootKey); } }; this.renderNewRoot = (item, cellFactory) => { 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(); RNSRender(cellFactory(item), root, () => { // console.log(`Rendered into cell! ref:`); }, rootKey); this.roots.add(rootKey); return { rootKey, nativeView: root.baseRef.nativeView }; }; this.state = { nativeCells: {}, nativeCellToItemIndex: new Map(), itemIndexToNativeCell: props._debug.logLevel === 'debug' ? new Map() : undefined }; } getNativeView() { const ref = this.props.forwardedRef || this.myRef; return ref.current ? ref.current.nativeView : null; } componentDidMount() { const node = this.getNativeView(); if (!node) { console.warn('React ref to NativeScript View lost, so unable to set item templates.'); return; } /* NOTE: does not support updating of this.props.cellFactories upon Props update. */ 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)); } static isItemsSource(arr) { // Same implementation as: https://github.com/NativeScript/NativeScript/blob/b436ecde3605b695a0ffa1757e38cc094e2fe311/tns-core-modules/ui/list-picker/list-picker-common.ts#L74 return typeof arr.getItem === 'function'; } render() { console.log("Pager's render()"); const { // Only used by the class component; not the JSX element. forwardedRef, //@ts-ignore children, _debug, cellFactories, cellFactory, ...rest } = this.props; return ( // React.createElement('pager',{ // className: 'pager-group', // ...rest, // ref: forwardedRef || this.myRef, // onItemLoading: this.defaultOnItemLoading // }, children) React.createElement("pager", { ...rest, onItemLoading: this.defaultOnItemLoading, ref: forwardedRef || this.myRef, children: children })); } } _Pager.defaultProps = { _debug: { logLevel: 'info', onCellFirstLoad: undefined, onCellRecycle: undefined } }; export class _PagerItem extends React.Component { constructor() { super(...arguments); this.myRef = React.createRef(); this.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) { // remove parent parent._removeView(view); // add to item; this.item.addChild(view); // @ts-ignore parent._addChildFromBuilder('PagerItem', this.item); } } render() { const { forwardedRef, //@ts-ignore children, // view, /* We disallow this at the typings level. */ ...rest } = this.props; return React.createElement('pagerItem', { ...rest, ref: forwardedRef || this.myRef }, children); } } //@ts-ignore export const Pager = React.forwardRef((props, ref) => React.createElement(_Pager, { ...props, forwardedRef: ref })); export const PagerItem = React.forwardRef((props, ref) => ( //@ts-ignore React.createElement(_PagerItem, { ...props, forwardedRef: ref }))); //# sourceMappingURL=index.js.map