UNPKG

react-native-wishlist

Version:
244 lines (238 loc) 7.99 kB
import React, { createContext, useContext, useImperativeHandle, useMemo, useRef } from 'react'; import { StyleSheet, useWindowDimensions, View } from 'react-native'; import { ForEach } from './Components/ForEach'; import { IF } from './Components/IF'; import { Pressable } from './Components/Pressable'; import { Case, Switch } from './Components/Switch'; import { WishlistImage } from './Components/WishlistImage'; import { WishlistText } from './Components/WishlistText'; import { WishlistView } from './Components/WishlistView'; import { initEventHandler } from './EventHandler'; import InflatorRepository from './InflatorRepository'; import NativeTemplateContainer from './NativeViews/NativeTemplateContainer'; import NativeTemplateInterceptor from './NativeViews/NativeTemplateInterceptor'; import NativeWishList, { Commands as WishlistCommands } from './NativeViews/WishlistNativeComponent'; import { TemplateContext } from './TemplateContext'; import { generateId } from './Utils'; import { useWishlistContext, WishlistContext } from './WishlistContext'; import { useInternalWishlistData } from './WishlistData'; import { createRunInJsFn, createRunInWishlistFn } from './WishlistJsRuntime'; const OffsetComponent = '__offsetComponent'; const TemplatesRegistryContext = /*#__PURE__*/createContext(null); function getTemplatesFromChildren(children, width) { const nextTemplates = { [OffsetComponent]: /*#__PURE__*/React.createElement(View, { style: [styles.offsetView, { width }] }) }; React.Children.forEach(children, c => { if (c.type.displayName === 'WishListTemplate') { const templateElement = c; nextTemplates[templateElement.props.type] = templateElement; } }); return nextTemplates; } function ComponentBase(_ref, ref) { let { children, style, initialData, ...rest } = _ref; const nativeWishlist = useRef(null); // TODO type it properly const wishlistId = useRef(null); if (!wishlistId.current) { wishlistId.current = generateId(); } const data = useInternalWishlistData(wishlistId.current, initialData); useImperativeHandle(ref, () => ({ scrollToItem: (index, animated) => { if (nativeWishlist.current != null) { console.log('scrollTo', index); WishlistCommands.scrollToItem(nativeWishlist.current, index, animated ?? true); } }, scrollToTop: () => { if (nativeWishlist.current != null) { WishlistCommands.scrollToItem(nativeWishlist.current, 0, true); } }, update: async updateJob => { return new Promise((resolve, _reject) => { const resolveJs = createRunInJsFn(resolve); createRunInWishlistFn(() => { 'worklet'; // we have to do sth here to get rid of frozen objs // otherwise data can't be modified data().update(updateJob, resolveJs); })(); }); } })); const { width } = useWindowDimensions(); useMemo(() => initEventHandler(), []); // Template registration and tracking const childrenTemplates = useMemo(() => getTemplatesFromChildren(children, width), [children, width]); const templatesRegistry = useMemo(() => ({ templates: {}, registerTemplate(type, component) { if (this.templates[type]) { return; } this.templates[type] = component; } }), []); // Resolve inflator - either use the provided callback or use the mapping const resolvedInflater = useMemo(() => { return (index, pool) => { 'worklet'; const value = data().at(index); if (!value) { return undefined; } console.log('returned', value, 'for index', index, 'data len', data().length()); const item = pool.getComponent(value.type); if (!item) { return undefined; } if (value.key == null) { throw new Error('Every data cell has to contain unique key prop!'); } // We set the key of the item here so that // viewportObserver knows what's the key and is able to rerender it later on item.key = value.key; return [item, value]; }; }, [data]); const inflatorIdRef = useRef(null); const prevInflatorRef = useRef(); // Inflator registration and tracking const inflatorId = useMemo(() => { if (prevInflatorRef.current !== resolvedInflater) { // Unregister? if (inflatorIdRef.current) { InflatorRepository.unregister(inflatorIdRef.current); } // Register inflatorIdRef.current = generateId(); InflatorRepository.register(inflatorIdRef.current, resolvedInflater); } return inflatorIdRef.current; }, [resolvedInflater]); const wishlistContext = useMemo(() => ({ id: wishlistId.current, inflatorId, data }), [inflatorId, data]); return /*#__PURE__*/React.createElement(WishlistContext.Provider, { value: wishlistContext }, /*#__PURE__*/React.createElement(TemplatesRegistryContext.Provider, { value: templatesRegistry }, /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(View, { style: styles.noDisplay }, Object.keys(childrenTemplates).map(c => /*#__PURE__*/React.createElement(View, { key: c + 'prerender' }, /*#__PURE__*/React.createElement(TemplateContext.Provider, { value: { templateType: c, renderChildren: true } }, childrenTemplates[c])))), /*#__PURE__*/React.createElement(InnerComponent, { inflatorId: inflatorId, style: style, nativeWishlist: nativeWishlist, rest: rest, templates: childrenTemplates, nestedTemplates: templatesRegistry.templates })))); } const Component = /*#__PURE__*/React.forwardRef(ComponentBase); function InnerComponent(_ref2) { let { inflatorId, style, nativeWishlist, rest, templates, nestedTemplates } = _ref2; const combinedTemplates = { ...templates, ...nestedTemplates }; const { id } = useWishlistContext(); const keys = Object.keys(combinedTemplates); // console.log('@@@ Render WishList', inflatorId, keys.join(', ')); return /*#__PURE__*/React.createElement(NativeTemplateInterceptor, { inflatorId: inflatorId, style: style, collapsable: false, removeClippedSubviews: false }, /*#__PURE__*/React.createElement(NativeWishList, { style: styles.flex, ref: nativeWishlist, removeClippedSubviews: false, inflatorId: inflatorId, onEndReached: rest === null || rest === void 0 ? void 0 : rest.onEndReached, onStartReached: rest === null || rest === void 0 ? void 0 : rest.onStartReached, initialIndex: rest.initialIndex ?? 0 }), /*#__PURE__*/React.createElement(NativeTemplateContainer, { names: keys, inflatorId: inflatorId, wishlistId: id, key: Math.random().toString(), collapsable: false }, Object.keys(combinedTemplates).map(c => /*#__PURE__*/React.createElement(View, { key: c }, /*#__PURE__*/React.createElement(TemplateContext.Provider, { value: { templateType: c } }, combinedTemplates[c]))))); } function Template(_ref3) { let { children, type } = _ref3; const registry = useContext(TemplatesRegistryContext); const templates = useContext(TemplateContext); registry === null || registry === void 0 ? void 0 : registry.registerTemplate(type, children); return templates !== null && templates !== void 0 && templates.renderChildren ? children : null; } Template.displayName = 'WishListTemplate'; export const Wishlist = { Component, Template, Pressable, View: WishlistView, Image: WishlistImage, Text: WishlistText, IF, Switch, Case, /** * TODO(Szymon) It's just a prototype we have to think about matching new and old children * TODO(Szymon) implement setChildren */ ForEach }; const styles = StyleSheet.create({ flex: { flex: 1 }, noDisplay: { display: 'none' }, offsetView: { height: 0 } }); //# sourceMappingURL=Wishlist.js.map