From 7aba94cd31ebb539bf76deb5e4e30f5e79e5ed62 Mon Sep 17 00:00:00 2001 From: Truong Luu Date: Tue, 5 Jul 2022 08:25:54 +0700 Subject: [PATCH 1/3] Fix incompatible with react-native@0.69.x --- DoubleTapView.js | 4 ++-- PdfPageView.js | 4 ++-- PdfView.js | 4 ++-- PinchZoomView.js | 4 ++-- index.js | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/DoubleTapView.js b/DoubleTapView.js index 6fea4777..a1a73e99 100644 --- a/DoubleTapView.js +++ b/DoubleTapView.js @@ -13,11 +13,11 @@ import { PanResponder } from 'react-native'; import PropTypes from 'prop-types'; -import {ViewPropTypes} from 'deprecated-react-native-prop-types'; +import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes'; export default class DoubleTapView extends Component { static propTypes = { - ...ViewPropTypes, + ...ViewProps, delay: PropTypes.number, radius: PropTypes.number, onSingleTap: PropTypes.func, diff --git a/PdfPageView.js b/PdfPageView.js index 87bc4525..fe721db0 100644 --- a/PdfPageView.js +++ b/PdfPageView.js @@ -13,7 +13,7 @@ import PropTypes from 'prop-types'; import { requireNativeComponent, } from 'react-native'; -import {ViewPropTypes} from 'deprecated-react-native-prop-types'; +import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes'; export default class PdfPageView extends PureComponent { _getStylePropsProps = () => { const {width, height} = this.props; @@ -39,7 +39,7 @@ export default class PdfPageView extends PureComponent { } PdfPageView.propTypes = { - ...ViewPropTypes, + ...ViewProps, fileNo: PropTypes.number, page: PropTypes.number, width: PropTypes.number, diff --git a/PdfView.js b/PdfView.js index deae1a15..8e6be964 100644 --- a/PdfView.js +++ b/PdfView.js @@ -9,7 +9,7 @@ 'use strict'; import React, {Component} from 'react'; import {ScrollView, FlatList, View, StyleSheet} from 'react-native'; -import {ViewPropTypes} from 'deprecated-react-native-prop-types'; +import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes'; import PropTypes from 'prop-types'; import PdfManager from './PdfManager'; @@ -26,7 +26,7 @@ const VIEWABILITYCONFIG = {minimumViewTime: 500, itemVisiblePercentThreshold: 10 export default class PdfView extends Component { static propTypes = { - ...ViewPropTypes, + ...ViewProps, path: PropTypes.string, password: PropTypes.string, scale: PropTypes.number, diff --git a/PinchZoomView.js b/PinchZoomView.js index 536fc9ed..3d3890fc 100644 --- a/PinchZoomView.js +++ b/PinchZoomView.js @@ -14,11 +14,11 @@ import { StyleSheet, PanResponder } from 'react-native'; -import {ViewPropTypes} from 'deprecated-react-native-prop-types'; +import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes'; export default class PinchZoomView extends Component { static propTypes = { - ...ViewPropTypes, + ...ViewProps, scalable: PropTypes.bool, onScaleChanged: PropTypes.func, }; diff --git a/index.js b/index.js index 95520c11..8bcafcb6 100644 --- a/index.js +++ b/index.js @@ -19,14 +19,14 @@ import { } from 'react-native'; import ReactNativeBlobUtil from 'react-native-blob-util' -import {ViewPropTypes} from 'deprecated-react-native-prop-types'; +import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes'; const SHA1 = require('crypto-js/sha1'); import PdfView from './PdfView'; export default class Pdf extends Component { static propTypes = { - ...ViewPropTypes, + ...ViewProps, source: PropTypes.oneOfType([ PropTypes.shape({ uri: PropTypes.string, From 594266636e6ab36a59f37c0644bcac1e9e16e4ef Mon Sep 17 00:00:00 2001 From: Truong Luu Date: Tue, 5 Jul 2022 09:43:34 +0700 Subject: [PATCH 2/3] typescript version --- .gitignore | 1 + DoubleTapView.js => DoubleTapView.tsx | 60 ++++---- PdfManager.js => PdfManager.ts | 3 +- PdfPageView.js => PdfPageView.tsx | 25 +-- PdfView.js => PdfView.tsx | 138 +++++++---------- PdfViewFlatList.js => PdfViewFlatList.tsx | 4 +- PinchZoomView.js => PinchZoomView.tsx | 54 +++---- index.d.ts | 76 ++++++++-- index.js => index.tsx | 177 ++++++++-------------- package.json | 21 ++- tsconfig.json | 20 +++ 11 files changed, 269 insertions(+), 310 deletions(-) rename DoubleTapView.js => DoubleTapView.tsx (64%) rename PdfManager.js => PdfManager.ts (91%) rename PdfPageView.js => PdfPageView.tsx (62%) rename PdfView.js => PdfView.tsx (80%) rename PdfViewFlatList.js => PdfViewFlatList.tsx (93%) rename PinchZoomView.js => PinchZoomView.tsx (76%) rename index.js => index.tsx (75%) create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index 874d342d..7650425b 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,4 @@ yarn-error.log .gitattributes .watchmanconfig .history +dist/ \ No newline at end of file diff --git a/DoubleTapView.js b/DoubleTapView.tsx similarity index 64% rename from DoubleTapView.js rename to DoubleTapView.tsx index a1a73e99..bec9c881 100644 --- a/DoubleTapView.js +++ b/DoubleTapView.tsx @@ -10,38 +10,30 @@ import React, {Component} from 'react'; import { View, - PanResponder + PanResponder, + GestureResponderEvent, + PanResponderGestureState } from 'react-native'; -import PropTypes from 'prop-types'; -import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes'; -export default class DoubleTapView extends Component { - - static propTypes = { - ...ViewProps, - delay: PropTypes.number, - radius: PropTypes.number, - onSingleTap: PropTypes.func, - onDoubleTap: PropTypes.func, - }; +import { DoubleTapViewProps } from '.'; +export default class DoubleTapView extends Component { static defaultProps = { delay: 300, radius: 50, - onSingleTap: () => { - }, - onDoubleTap: () => { - }, }; + gestureHandlers: any; + prevTouchInfo: { prevTouchX: number; prevTouchY: number; prevTouchTimeStamp: number; }; + timer: any; - constructor() { - super(); + constructor(props: DoubleTapViewProps) { + super(props); this.gestureHandlers = PanResponder.create({ - onStartShouldSetPanResponder: (evt, gestureState) => (gestureState.numberActiveTouches === 1), - onStartShouldSetResponderCapture: (evt, gestureState) => (gestureState.numberActiveTouches === 1), - onMoveShouldSetPanResponder: (evt, gestureState) => (false), - onMoveShouldSetResponderCapture: (evt, gestureState) => (false), - onPanResponderTerminationRequest: (evt, gestureState) => false, + onStartShouldSetPanResponder: (_evt, gestureState) => (gestureState.numberActiveTouches === 1), + onStartShouldSetPanResponderCapture: (_evt, gestureState) => (gestureState.numberActiveTouches === 1), + onMoveShouldSetPanResponder: () => false, + onMoveShouldSetPanResponderCapture: () => false, + onPanResponderTerminationRequest: () => false, onPanResponderRelease: this.handlePanResponderRelease, }); @@ -53,39 +45,35 @@ export default class DoubleTapView extends Component { }; this.timer = null; - } - - distance = (x0, y0, x1, y1) => { - return Math.sqrt(Math.pow((x1 - x0), 2) + Math.pow((y1 - y0), 2)).toFixed(1); + distance = (x0: number, y0: number, x1: number, y1: number) => { + return Math.sqrt(Math.pow((x1 - x0), 2) + Math.pow((y1 - y0), 2)); }; - isDoubleTap = (currentTouchTimeStamp, {x0, y0}) => { + isDoubleTap = (currentTouchTimeStamp: number, gestureState: PanResponderGestureState) => { const {prevTouchX, prevTouchY, prevTouchTimeStamp} = this.prevTouchInfo; const dt = currentTouchTimeStamp - prevTouchTimeStamp; const {delay, radius} = this.props; - return (prevTouchTimeStamp > 0 && dt < delay && this.distance(prevTouchX, prevTouchY, x0, y0) < radius); + return (prevTouchTimeStamp > 0 && dt < delay && this.distance(prevTouchX, prevTouchY, gestureState.x0, gestureState.y0) < radius); }; - handlePanResponderRelease = (evt, gestureState) => { + handlePanResponderRelease = (evt: GestureResponderEvent, gestureState: PanResponderGestureState) => { const currentTouchTimeStamp = Date.now(); const x = evt.nativeEvent.locationX; const y = evt.nativeEvent.locationY; if (this.timer) { - if (this.isDoubleTap(currentTouchTimeStamp, gestureState)) { - clearTimeout(this.timer); this.timer = null; this.props.onDoubleTap(); } else { - const {prevTouchX, prevTouchY, prevTouchTimeStamp} = this.prevTouchInfo; + const {prevTouchX, prevTouchY} = this.prevTouchInfo; const {radius} = this.props; // if not in radius, it's a move @@ -115,6 +103,12 @@ export default class DoubleTapView extends Component { }; + componentWillUnmount() { + if (this.timer) { + clearTimeout(this.timer); + } + } + render() { return ( diff --git a/PdfManager.js b/PdfManager.ts similarity index 91% rename from PdfManager.js rename to PdfManager.ts index 9309e370..4f646bc1 100644 --- a/PdfManager.js +++ b/PdfManager.ts @@ -11,8 +11,7 @@ const PdfManagerNative = require('react-native').NativeModules.PdfManager; export default class PdfManager { - - static loadFile(path, password) { + static loadFile(path: string, password?: string) { if (typeof path !== 'string') { throw new TypeError('path must be a valid string.'); } diff --git a/PdfPageView.js b/PdfPageView.tsx similarity index 62% rename from PdfPageView.js rename to PdfPageView.tsx index fe721db0..22172afd 100644 --- a/PdfPageView.js +++ b/PdfPageView.tsx @@ -6,20 +6,21 @@ * LICENSE file in the root directory of this source tree. */ - 'use strict'; + import React, {PureComponent} from 'react'; -import PropTypes from 'prop-types'; import { requireNativeComponent, } from 'react-native'; -import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes'; -export default class PdfPageView extends PureComponent { +import { PdfPageViewProps } from '.'; + +export default class PdfPageView extends PureComponent { _getStylePropsProps = () => { const {width, height} = this.props; if (width || height) { return {width, height}; } + return {}; }; @@ -31,6 +32,7 @@ export default class PdfPageView extends PureComponent { return ( ); @@ -38,16 +40,5 @@ export default class PdfPageView extends PureComponent { } } -PdfPageView.propTypes = { - ...ViewProps, - fileNo: PropTypes.number, - page: PropTypes.number, - width: PropTypes.number, - height: PropTypes.number -}; - -PdfPageView.defaultProps = { - style: {} -}; - -let PdfPageViewCustom = requireNativeComponent('RCTPdfPageView', PdfPageView, {nativeOnly: {}}); +// @ts-ignore +const PdfPageViewCustom = requireNativeComponent('RCTPdfPageView', PdfPageView, {nativeOnly: {}}); diff --git a/PdfView.js b/PdfView.tsx similarity index 80% rename from PdfView.js rename to PdfView.tsx index 8e6be964..0004d77e 100644 --- a/PdfView.js +++ b/PdfView.tsx @@ -8,40 +8,21 @@ 'use strict'; import React, {Component} from 'react'; -import {ScrollView, FlatList, View, StyleSheet} from 'react-native'; -import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes'; -import PropTypes from 'prop-types'; +import {ScrollView, View, StyleSheet, LayoutChangeEvent} from 'react-native'; import PdfManager from './PdfManager'; import PdfPageView from './PdfPageView'; import DoubleTapView from './DoubleTapView'; import PinchZoomView from './PinchZoomView'; import PdfViewFlatList from './PdfViewFlatList'; +import { PdfViewProps, PdfViewState } from '.'; const MIN_SCALE = 1; const MAX_SCALE = 3; -const VIEWABILITYCONFIG = {minimumViewTime: 500, itemVisiblePercentThreshold: 10, waitForInteraction: false}; - -export default class PdfView extends Component { - - static propTypes = { - ...ViewProps, - path: PropTypes.string, - password: PropTypes.string, - scale: PropTypes.number, - minScale: PropTypes.number, - maxScale: PropTypes.number, - spacing: PropTypes.number, - fitPolicy: PropTypes.number, - horizontal: PropTypes.bool, - page: PropTypes.number, - currentPage: PropTypes.number, - singlePage: PropTypes.bool, - onPageSingleTap: PropTypes.func, - onScaleChanged: PropTypes.func, - }; +const VIEW_ABILITY_CONFIG = {minimumViewTime: 500, itemVisiblePercentThreshold: 10, waitForInteraction: false}; +export default class PdfView extends Component { static defaultProps = { path: "", password: "", @@ -57,15 +38,19 @@ export default class PdfView extends Component { currentPage: -1, enablePaging: false, singlePage: false, - onPageSingleTap: (page, x, y) => { - }, - onScaleChanged: (scale) => { - }, }; - constructor(props) { + private _flatList = React.createRef<{ + scrollToIndex: (config: {animated: boolean; index: number}) => void + scrollToXY: (x: number, y: number) => void + }>(); + private _scaleTimer: any = 0; + private _scrollTimer: any = 0; + private _mounted: boolean; + constructor(props: PdfViewProps) { super(props); + this.state = { pdfLoaded: false, fileNo: -1, @@ -75,22 +60,21 @@ export default class PdfView extends Component { pageAspectRate: 0.5, pdfPageSize: {width: 0, height: 0}, contentContainerSize: {width: 0, height: 0}, - scale: this.props.scale, + scale: this.props.scale ?? 1, contentOffset: {x: 0, y: 0}, newContentOffset: {x: 0, y: 0}, + centerContent: false, }; - this._flatList = null; this._scaleTimer = null; this._scrollTimer = null; this._mounted = false; - } componentDidMount() { this._mounted = true; PdfManager.loadFile(this.props.path, this.props.password) - .then((pdfInfo) => { + .then((pdfInfo: any) => { if (this._mounted) { const fileNo = pdfInfo[0]; const numberOfPages = pdfInfo[1]; @@ -110,22 +94,20 @@ export default class PdfView extends Component { this.props.onLoadComplete(numberOfPages, this.props.path, {width, height}); } } - }) - .catch((error) => { - this.props.onError(error); + .catch((error: any) => { + this.props.onError && this.props.onError(error); }); - clearTimeout(this._scrollTimer); + this._scrollTimer && clearTimeout(this._scrollTimer); this._scrollTimer = setTimeout(() => { - if (this._flatList) { - this._flatList.scrollToIndex({animated: false, index: this.props.page < 1 ? 0 : this.props.page - 1}); + if (this._flatList.current) { + this._flatList.current.scrollToIndex({animated: false, index: this.props.page < 1 ? 0 : this.props.page - 1}); } }, 200); } - componentDidUpdate(prevProps) { - + componentDidUpdate(prevProps: PdfViewProps) { if (this.props.scale !== this.state.scale) { this._onScaleChanged({ scale: this.props.scale / this.state.scale, @@ -138,10 +120,10 @@ export default class PdfView extends Component { let page = (this.props.page) < 1 ? 1 : this.props.page; page = page > this.state.numberOfPages ? this.state.numberOfPages : page; - if (this._flatList) { + if (this._flatList.current) { clearTimeout(this._scrollTimer); this._scrollTimer = setTimeout(() => { - this._flatList.scrollToIndex({animated: false, index: page - 1}); + this._flatList.current?.scrollToIndex({animated: false, index: page - 1}); }, 200); } } @@ -155,10 +137,9 @@ export default class PdfView extends Component { } - _keyExtractor = (item, index) => "pdf-page-" + index; + _keyExtractor = (_item: any, index: number) => "pdf-page-" + index; _getPageWidth = () => { - let fitPolicy = this.props.fitPolicy; // if only one page, show whole page in center @@ -166,7 +147,6 @@ export default class PdfView extends Component { fitPolicy = 2; } - switch (fitPolicy) { case 0: //fit width return this.state.contentContainerSize.width * this.state.scale; @@ -181,11 +161,9 @@ export default class PdfView extends Component { } } } - }; _getPageHeight = () => { - let fitPolicy = this.props.fitPolicy; // if only one page, show whole page in center @@ -220,14 +198,11 @@ export default class PdfView extends Component { }}/> ); - _onItemSingleTap = (index, x, y) => { - - this.props.onPageSingleTap(index + 1, x, y); - + _onItemSingleTap = (index: number, x: number, y: number) => { + this.props.onPageSingleTap && this.props.onPageSingleTap(index + 1, x, y); }; - _onItemDoubleTap = (index) => { - + _onItemDoubleTap = () => { if (this.state.scale >= this.props.maxScale) { this._onScaleChanged({ scale: 1 / this.state.scale, @@ -241,23 +216,22 @@ export default class PdfView extends Component { pageY: this.state.contentContainerSize.height / 2 }); } - }; - _onScaleChanged = (pinchInfo) => { - + _onScaleChanged = (pinchInfo: any) => { let newScale = pinchInfo.scale * this.state.scale; newScale = newScale > this.props.maxScale ? this.props.maxScale : newScale; newScale = newScale < this.props.minScale ? this.props.minScale : newScale; + let newContentOffset = { x: (this.state.contentOffset.x + pinchInfo.pageX) * (newScale / this.state.scale) - pinchInfo.pageX, y: (this.state.contentOffset.y + pinchInfo.pageY) * (newScale / this.state.scale) - pinchInfo.pageY } this.setState({scale: newScale, newContentOffset: newContentOffset}); - this.props.onScaleChanged(newScale); - + this.props.onScaleChanged && this.props.onScaleChanged(newScale); }; + // @ts-ignore _renderItem = ({item, index}) => { const pageView = ( { + onSingleTap={(x: number, y: number) => { this._onItemSingleTap(index, x, y); }} onDoubleTap={() => { - this._onItemDoubleTap(index); + this._onItemDoubleTap(); }} > {pageView} {(index !== this.state.numberOfPages - 1) && this._renderSeparator()} ); - }; - _onViewableItemsChanged = (viewableInfo) => { - + _onViewableItemsChanged = (viewableInfo: any) => { for (let i = 0; i < viewableInfo.viewableItems.length; i++) { this._onPageChanged(viewableInfo.viewableItems[i].index + 1, this.state.numberOfPages); if (viewableInfo.viewableItems.length + viewableInfo.viewableItems[0].index < this.state.numberOfPages) break; } - }; - _onPageChanged = (page, numberOfPages) => { + _onPageChanged = (page: number, numberOfPages: number) => { if (this.props.onPageChanged && this.state.currentPage !== page) { this.props.onPageChanged(page, numberOfPages); this.setState({currentPage: page}); } }; - - _getRef = (ref) => this._flatList = ref; - - _getItemLayout = (data, index) => ({ + _getItemLayout = (_data: any, index: number) => ({ length: this.props.horizontal ? this._getPageWidth() : this._getPageHeight(), offset: ((this.props.horizontal ? this._getPageWidth() : this._getPageHeight()) + this.props.spacing * this.state.scale) * index, index }); - _onScroll = (e) => { + _onScroll = (e: any) => { this.setState({contentOffset: e.nativeEvent.contentOffset, newContentOffset: e.nativeEvent.contentOffset}); }; - _onListContentSizeChange = (contentWidth, contentHeight) => { + _onListContentSizeChange = (contentWidth: number, contentHeight: number) => { if (this.state.contentOffset.x != this.state.newContentOffset.x || this.state.contentOffset.y != this.state.newContentOffset.y) { - this._flatList.scrollToXY(this.state.newContentOffset.x, this.state.newContentOffset.y); + this._flatList.current?.scrollToXY(this.state.newContentOffset.x, this.state.newContentOffset.y); } }; + _renderScroll = (props: any) => ( + + ) + _renderList = () => { let data = []; @@ -343,7 +319,8 @@ export default class PdfView extends Component { return ( } + renderScrollComponent={this._renderScroll} initialScrollIndex={this.props.page < 1 ? 0 : this.props.page - 1} onViewableItemsChanged={this._onViewableItemsChanged} - viewabilityConfig={VIEWABILITYCONFIG} + viewabilityConfig={VIEW_ABILITY_CONFIG} onScroll={this._onScroll} onContentSizeChange={this._onListContentSizeChange} scrollEnabled={!this.props.singlePage} /> ); - }; - _onLayout = (event) => { + _onLayout = (event: LayoutChangeEvent) => { this.setState({ contentContainerSize: { width: event.nativeEvent.layout.width, @@ -382,7 +354,6 @@ export default class PdfView extends Component { }); }; - render() { if (this.props.singlePage) { return ( @@ -406,11 +377,10 @@ export default class PdfView extends Component { ); } - } const styles = StyleSheet.create({ container: { flex: 1 } -}); \ No newline at end of file +}); diff --git a/PdfViewFlatList.js b/PdfViewFlatList.tsx similarity index 93% rename from PdfViewFlatList.js rename to PdfViewFlatList.tsx index 5fc491ec..462725da 100644 --- a/PdfViewFlatList.js +++ b/PdfViewFlatList.tsx @@ -24,8 +24,8 @@ export default class PdfViewFlatList extends FlatList { * the function also accepts separate arguments as an alternative to the options object. * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED. */ - scrollToXY = (x, y) => { + scrollToXY = (x: number, y: number) => { + // @ts-ignore this._listRef._scrollRef.scrollTo({x: x, y: y, animated: false}); } - } \ No newline at end of file diff --git a/PinchZoomView.js b/PinchZoomView.tsx similarity index 76% rename from PinchZoomView.js rename to PinchZoomView.tsx index 3d3890fc..7a645895 100644 --- a/PinchZoomView.js +++ b/PinchZoomView.tsx @@ -8,35 +8,32 @@ 'use strict'; import React, {Component} from 'react'; -import PropTypes from 'prop-types'; import { View, StyleSheet, - PanResponder + PanResponder, + GestureResponderEvent, + PanResponderGestureState } from 'react-native'; -import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes'; -export default class PinchZoomView extends Component { - - static propTypes = { - ...ViewProps, - scalable: PropTypes.bool, - onScaleChanged: PropTypes.func, - }; +import { PinchZoomViewProps } from '.'; +export default class PinchZoomView extends Component { static defaultProps = { scalable: true, - onScaleChanged: (scale) => { - }, }; - constructor(props) { + distant: number; + gestureHandlers: any; + constructor(props: PinchZoomViewProps) { super(props); this.state = {}; + this.distant = 0; + this.gestureHandlers = PanResponder.create({ onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder, - onMoveShouldSetResponderCapture: (evt, gestureState) => (true), + onMoveShouldSetPanResponderCapture: () => true, onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder, onPanResponderGrant: this._handlePanResponderGrant, onPanResponderMove: this._handlePanResponderMove, @@ -45,45 +42,34 @@ export default class PinchZoomView extends Component { onPanResponderTerminate: this._handlePanResponderTerminate, onShouldBlockNativeResponder: evt => true }); - } - _handleStartShouldSetPanResponder = (e, gestureState) => { - + _handleStartShouldSetPanResponder = () => { // don't respond to single touch to avoid shielding click on child components return false; - }; - _handleMoveShouldSetPanResponder = (e, gestureState) => { - + _handleMoveShouldSetPanResponder = (e: GestureResponderEvent, gestureState: PanResponderGestureState) => { return this.props.scalable && (e.nativeEvent.changedTouches.length >= 2 || gestureState.numberActiveTouches >= 2); - }; - _handlePanResponderGrant = (e, gestureState) => { - + _handlePanResponderGrant = (e: GestureResponderEvent, gestureState: PanResponderGestureState) => { if (e.nativeEvent.changedTouches.length >= 2 || gestureState.numberActiveTouches >= 2) { let dx = Math.abs(e.nativeEvent.touches[0].pageX - e.nativeEvent.touches[1].pageX); let dy = Math.abs(e.nativeEvent.touches[0].pageY - e.nativeEvent.touches[1].pageY); this.distant = Math.sqrt(dx * dx + dy * dy); } - }; - _handlePanResponderEnd = (e, gestureState) => { - + _handlePanResponderEnd = () => { this.distant = 0; - }; - _handlePanResponderTerminate = (e, gestureState) => { - + _handlePanResponderTerminate = () => { this.distant = 0; - }; - _handlePanResponderMove = (e, gestureState) => { + _handlePanResponderMove = (e: GestureResponderEvent, gestureState: PanResponderGestureState) => { if ((e.nativeEvent.changedTouches.length >= 2 || gestureState.numberActiveTouches >= 2) && this.distant > 100) { @@ -95,15 +81,12 @@ export default class PinchZoomView extends Component { let pageY = (e.nativeEvent.touches[0].pageY + e.nativeEvent.touches[1].pageY) / 2; let pinchInfo = {scale: scale, pageX: pageX, pageY: pageY}; - this.props.onScaleChanged(pinchInfo); + this.props.onScaleChanged && this.props.onScaleChanged(pinchInfo); this.distant = distant; - } - }; render() { - return ( ); - } } diff --git a/index.d.ts b/index.d.ts index c54c8ba7..093d05a5 100644 --- a/index.d.ts +++ b/index.d.ts @@ -25,10 +25,10 @@ export type Source = { cacheFileName?: string; expiration?: number; method?: string; + body?: any }; -interface Props { - style?: ReactNative.StyleProp, +export interface PdfProps extends ReactNative.ViewProps { source: Source | number, page?: number, scale?: number, @@ -37,25 +37,83 @@ interface Props { horizontal?: boolean, spacing?: number, password?: string, - renderActivityIndicator?: (progress: number) => React.ReactElement, + renderActivityIndicator: (progress: number) => React.ReactElement, enableAntialiasing?: boolean, + enableAnnotationRendering?: boolean, enablePaging?: boolean, enableRTL?: boolean, - enableAnnotationRendering?: boolean, fitPolicy?: number, trustAllCerts?: boolean, singlePage?: boolean, - onLoadProgress?: (percent: number,) => void, + onLoadProgress?: (percent: number) => void, onLoadComplete?: (numberOfPages: number, path: string, size: {height: number, width: number}, tableContents?: TableContent[]) => void, onPageChanged?: (page: number, numberOfPages: number) => void, - onError?: (error: object) => void, + onError?: (error: any) => void, onPageSingleTap?: (page: number, x: number, y: number) => void, onScaleChanged?: (scale: number) => void, onPressLink?: (url: string) => void, + setPage: (pageNumber: number) => void; + + usePDFKit?: boolean } -declare class Pdf extends React.Component { - setPage: (pageNumber: number) => void; +export type PdfState = { + path: string + isDownloaded: boolean + progress: number + isSupportPDFKit: number +} + +export interface PdfViewProps extends ReactNative.ViewProps { + path: string + password?: string + scale: number + minScale: number + maxScale: number + spacing: number + fitPolicy?: number + horizontal?: boolean + page: number + currentPage: number + singlePage: boolean + enablePaging: boolean + onPageSingleTap: PdfProps['onPageSingleTap'] + onScaleChanged: PdfProps['onScaleChanged'] + onLoadComplete: PdfProps['onLoadComplete'] + onError: PdfProps['onError'] + onPageChanged: PdfProps['onPageChanged'] } -export default Pdf; +export type PdfViewState = { + pdfLoaded: boolean + fileNo: number + numberOfPages:number + page: number + currentPage: number + pageAspectRate: number + pdfPageSize: {width: number, height: number} + contentContainerSize: {width: number, height: number} + scale: number + contentOffset: {x: number, y: number} + newContentOffset: {x: number, y: number} + centerContent: boolean +} + +export interface PdfPageViewProps extends ReactNative.ViewProps { + fileNo: number + page: number + width: number + height: number +} + +export interface PinchZoomViewProps extends ReactNative.ViewProps { + scalable: boolean + onScaleChanged: (scaled: {pageX: number; pageY: number; scale: number}) => void +} + +export interface DoubleTapViewProps extends ReactNative.ViewProps { + delay: number + radius: number + onSingleTap: PropTypes.func, + onDoubleTap: PropTypes.func, +} diff --git a/index.js b/index.tsx similarity index 75% rename from index.js rename to index.tsx index 8bcafcb6..fe746335 100644 --- a/index.js +++ b/index.tsx @@ -7,68 +7,24 @@ */ 'use strict'; + import React, {Component} from 'react'; -import PropTypes from 'prop-types'; import { requireNativeComponent, View, Platform, StyleSheet, Image, - Text + Text, } from 'react-native'; +// @ts-ignore import ReactNativeBlobUtil from 'react-native-blob-util' -import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes'; const SHA1 = require('crypto-js/sha1'); import PdfView from './PdfView'; +import type {PdfProps, PdfState, Source} from '.' -export default class Pdf extends Component { - - static propTypes = { - ...ViewProps, - source: PropTypes.oneOfType([ - PropTypes.shape({ - uri: PropTypes.string, - cache: PropTypes.bool, - cacheFileName: PropTypes.string, - expiration: PropTypes.number, - }), - // Opaque type returned by require('./test.pdf') - PropTypes.number, - ]).isRequired, - page: PropTypes.number, - scale: PropTypes.number, - minScale: PropTypes.number, - maxScale: PropTypes.number, - horizontal: PropTypes.bool, - spacing: PropTypes.number, - password: PropTypes.string, - renderActivityIndicator: PropTypes.func, - enableAntialiasing: PropTypes.bool, - enableAnnotationRendering: PropTypes.bool, - enablePaging: PropTypes.bool, - enableRTL: PropTypes.bool, - fitPolicy: PropTypes.number, - trustAllCerts: PropTypes.bool, - singlePage: PropTypes.bool, - onLoadComplete: PropTypes.func, - onPageChanged: PropTypes.func, - onError: PropTypes.func, - onPageSingleTap: PropTypes.func, - onScaleChanged: PropTypes.func, - onPressLink: PropTypes.func, - - // Props that are not available in the earlier react native version, added to prevent crashed on android - accessibilityLabel: PropTypes.string, - importantForAccessibility: PropTypes.string, - renderToHardwareTextureAndroid: PropTypes.string, - testID: PropTypes.string, - onLayout: PropTypes.bool, - accessibilityLiveRegion: PropTypes.string, - accessibilityComponentType: PropTypes.string, - }; - +export default class Pdf extends Component { static defaultProps = { password: "", scale: 1, @@ -85,45 +41,39 @@ export default class Pdf extends Component { trustAllCerts: true, usePDFKit: true, singlePage: false, - onLoadProgress: (percent) => { - }, - onLoadComplete: (numberOfPages, path) => { - }, - onPageChanged: (page, numberOfPages) => { - }, - onError: (error) => { - }, - onPageSingleTap: (page, x, y) => { - }, - onScaleChanged: (scale) => { - }, - onPressLink: (url) => { - }, }; - constructor(props) { + state: PdfState = { + path: '', + isDownloaded: false, + progress: 0, + isSupportPDFKit: -1 + } - super(props); - this.state = { - path: '', - isDownloaded: false, - progress: 0, - isSupportPDFKit: -1 - }; + private lastRNBFTask: any = null + private _mounted: boolean = false + private _root: any = React.createRef() - this.lastRNBFTask = null; + private _resolveAssetSource = (source: PdfProps['source']) => { + if (typeof source === 'number') { + return Image.resolveAssetSource(source) + } + return Image.resolveAssetSource({ + uri: source.uri, + headers: source.headers ?? undefined, + method: source.method ?? 'GET' + }) } - componentDidUpdate(prevProps) { - - const nextSource = Image.resolveAssetSource(this.props.source); - const curSource = Image.resolveAssetSource(prevProps.source); + componentDidUpdate(prevProps: PdfProps) { + const nextSource = this._resolveAssetSource(this.props.source); + const curSource = this._resolveAssetSource(prevProps.source); if ((nextSource.uri !== curSource.uri)) { // if has download task, then cancel it. if (this.lastRNBFTask) { - this.lastRNBFTask.cancel(err => { + this.lastRNBFTask.cancel(() => { this._loadFromSource(this.props.source); }); this.lastRNBFTask = null; @@ -137,7 +87,7 @@ export default class Pdf extends Component { this._mounted = true; if (Platform.OS === "ios") { const PdfViewManagerNative = require('react-native').NativeModules.PdfViewManager; - PdfViewManagerNative.supportPDFKit((isSupportPDFKit) => { + PdfViewManagerNative.supportPDFKit((isSupportPDFKit: boolean) => { if (this._mounted) { this.setState({isSupportPDFKit: isSupportPDFKit ? 1 : 0}); } @@ -149,30 +99,29 @@ export default class Pdf extends Component { componentWillUnmount() { this._mounted = false; if (this.lastRNBFTask) { - this.lastRNBFTask.cancel(err => { + this.lastRNBFTask.cancel(() => { }); this.lastRNBFTask = null; } - } - _loadFromSource = (newSource) => { - - const source = Image.resolveAssetSource(newSource) || {}; + _loadFromSource = (newSource: PdfProps['source']) => { + const source = this._resolveAssetSource(newSource) || {}; let uri = source.uri || ''; // first set to initial state if (this._mounted) { this.setState({isDownloaded: false, path: '', progress: 0}); } - const filename = source.cacheFileName || SHA1(uri) + '.pdf'; + + const filename = SHA1(uri) + '.pdf'; const cacheFile = ReactNativeBlobUtil.fs.dirs.CacheDir + '/' + filename; - if (source.cache) { + if (typeof newSource === 'object' && newSource.cache) { ReactNativeBlobUtil.fs .stat(cacheFile) - .then(stats => { - if (!Boolean(source.expiration) || (source.expiration * 1000 + stats.lastModified) > (new Date().getTime())) { + .then((stats: any) => { + if (!Boolean(newSource.expiration) || (newSource.expiration! * 1000 + stats.lastModified) > (new Date().getTime())) { if (this._mounted) { this.setState({path: cacheFile, isDownloaded: true}); } @@ -190,10 +139,9 @@ export default class Pdf extends Component { } }; - _prepareFile = async (source) => { - + _prepareFile = async (source: PdfProps['source']) => { try { - if (source.uri) { + if (typeof source === 'object' && source.uri) { let uri = source.uri || ''; const isNetwork = !!(uri && uri.match(/^https?:\/\//)); @@ -216,7 +164,7 @@ export default class Pdf extends Component { this.setState({path: cacheFile, isDownloaded: true, progress: 1}); } }) - .catch(async (error) => { + .catch(async (error: any) => { this._unlinkFile(cacheFile); this._onError(error); }) @@ -229,7 +177,7 @@ export default class Pdf extends Component { this.setState({path: cacheFile, isDownloaded: true, progress: 1}); } }) - .catch(async (error) => { + .catch(async (error: any) => { this._unlinkFile(cacheFile); this._onError(error) }); @@ -247,14 +195,12 @@ export default class Pdf extends Component { } catch (e) { this._onError(e) } - - }; - _downloadFile = async (source, cacheFile) => { + _downloadFile = async (source: Source, cacheFile: string) => { if (this.lastRNBFTask) { - this.lastRNBFTask.cancel(err => { + this.lastRNBFTask.cancel(() => { }); this.lastRNBFTask = null; } @@ -274,7 +220,7 @@ export default class Pdf extends Component { source.body ? source.body : "" ) // listen to download progress event - .progress((received, total) => { + .progress((received: number, total: number) => { this.props.onLoadProgress && this.props.onLoadProgress(received / total); if (this._mounted) { this.setState({progress: received / total}); @@ -282,7 +228,7 @@ export default class Pdf extends Component { }); this.lastRNBFTask - .then(async (res) => { + .then(async (res: any) => { this.lastRNBFTask = null; @@ -316,11 +262,11 @@ export default class Pdf extends Component { } this._unlinkFile(tempCacheFile); }) - .catch(async (error) => { + .catch(async (error: any) => { throw error; }); }) - .catch(async (error) => { + .catch(async (error: any) => { this._unlinkFile(tempCacheFile); this._unlinkFile(cacheFile); this._onError(error); @@ -328,7 +274,7 @@ export default class Pdf extends Component { }; - _unlinkFile = async (file) => { + _unlinkFile = async (file: any) => { try { await ReactNativeBlobUtil.fs.unlink(file); } catch (e) { @@ -336,23 +282,23 @@ export default class Pdf extends Component { } } - setNativeProps = nativeProps => { - if (this._root){ - this._root.setNativeProps(nativeProps); + setNativeProps = (nativeProps: any) => { + if (this._root.current) { + this._root.current.setNativeProps(nativeProps); } }; - setPage( pageNumber ) { + setPage(pageNumber: number) { if ( (pageNumber === null) || (isNaN(pageNumber)) ) { throw new Error('Specified pageNumber is not a number'); } + this.setNativeProps({ page: pageNumber }); } - _onChange = (event) => { - + _onChange = (event: any) => { let message = event.nativeEvent.message.split('|'); //__DEV__ && console.log("onChange: " + message); if (message.length > 0) { @@ -379,11 +325,8 @@ export default class Pdf extends Component { } }; - - _onError = (error) => { - + _onError = (error: any) => { this.props.onError && this.props.onError(error); - }; render() { @@ -400,8 +343,9 @@ export default class Pdf extends Component { ):( Platform.OS === "android" || Platform.OS === "windows"?( (this._root = component)} + ref={this._root} {...this.props} + // @ts-ignore style={[{flex:1,backgroundColor: '#EEE'}, this.props.style]} path={this.state.path} onChange={this._onChange} @@ -409,8 +353,9 @@ export default class Pdf extends Component { ):( this.props.usePDFKit && this.state.isSupportPDFKit === 1?( (this._root = component)} + ref={this._root} {...this.props} + // @ts-ignore style={[{backgroundColor: '#EEE',overflow: 'hidden'}, this.props.style]} path={this.state.path} onChange={this._onChange} @@ -424,7 +369,7 @@ export default class Pdf extends Component { onError={this._onError} onPageSingleTap={this.props.onPageSingleTap} onScaleChanged={this.props.onScaleChanged} - onPressLink={this.props.onPressLink} + // onPressLink={this.props.onPressLink} />) ) )} @@ -439,20 +384,22 @@ export default class Pdf extends Component { if (Platform.OS === "android") { + // @ts-ignore var PdfCustom = requireNativeComponent('RCTPdf', Pdf, { nativeOnly: {path: true, onChange: true}, }) } else if (Platform.OS === "ios") { + // @ts-ignore var PdfCustom = requireNativeComponent('RCTPdfView', Pdf, { nativeOnly: {path: true, onChange: true}, }) } else if (Platform.OS === "windows") { + // @ts-ignore var PdfCustom = requireNativeComponent('RCTPdf', Pdf, { nativeOnly: {path: true, onChange: true}, }) } - const styles = StyleSheet.create({ progressContainer: { flex: 1, diff --git a/package.json b/package.json index 11c41a4f..ef6ff338 100644 --- a/package.json +++ b/package.json @@ -28,24 +28,21 @@ "url": "https://github.com/wonday/react-native-pdf/issues" }, "dependencies": { - "crypto-js": "^3.2.0" + "crypto-js": "^3.2.0", + "typescript": "^4.7.4" }, "devDependencies": { - "prop-types": "^15.7.2" + "@types/react-native": "^0.68.0", + "react-native": "^0.68.0" }, "files": [ "android/", "ios/", "windows/", - "DoubleTapView.js", - "index.d.ts", - "index.js", - "index.js.flow", - "PdfManager.js", - "PdfPageView.js", - "PdfView.js", - "PdfViewFlatList.js", - "PinchZoomView.js", + "dist/", "react-native-pdf.podspec" - ] + ], + "scripts": { + "build": "rm -rf dist/ && tsc" + } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..de0fb6cc --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "jsx": "react-native", + "declaration": true, + "removeComments": false, + "strict": true, + "allowSyntheticDefaultImports": true, + "moduleResolution": "node", + "outDir": "./dist", + "rootDir": "./", + "lib": ["es6", "dom", "es2016", "es2017"], + "skipLibCheck": true + }, + "exclude": [ + "node_modules", + "example" + ] +} \ No newline at end of file From 60f04263afae11e01dbcac17ba93355d317c5b56 Mon Sep 17 00:00:00 2001 From: Truong Luu Date: Tue, 5 Jul 2022 10:02:35 +0700 Subject: [PATCH 3/3] fix mismatch main --- package.json | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ef6ff338..006c68d6 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,7 @@ "version": "6.5.0", "summary": "A react native PDF view component", "description": "A react native PDF view component, support ios and android platform", - "main": "index.js", - "typings": "./index.d.ts", + "main": "dist/index.js", "repository": { "type": "git", "url": "git+https://github.com/wonday/react-native-pdf.git" @@ -28,12 +27,12 @@ "url": "https://github.com/wonday/react-native-pdf/issues" }, "dependencies": { - "crypto-js": "^3.2.0", - "typescript": "^4.7.4" + "crypto-js": "^3.2.0" }, "devDependencies": { "@types/react-native": "^0.68.0", - "react-native": "^0.68.0" + "react-native": "^0.68.0", + "typescript": "^4.7.4" }, "files": [ "android/",