@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
JavaScript
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