From 80f3867a83c71fd89e4b61160a6a7233bfd54291 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 10 Jan 2024 11:59:16 +0700 Subject: [PATCH 01/11] fix: Migrate ImageView to ts --- src/components/ImageView/index.native.js | 52 ------------ src/components/ImageView/index.native.tsx | 39 +++++++++ .../ImageView/{index.js => index.tsx} | 83 +++++++------------ src/components/ImageView/propTypes.js | 46 ---------- src/components/ImageView/types.ts | 50 +++++++++++ src/components/Lightbox.js | 2 +- src/components/MultiGestureCanvas/types.ts | 6 ++ 7 files changed, 124 insertions(+), 154 deletions(-) delete mode 100644 src/components/ImageView/index.native.js create mode 100644 src/components/ImageView/index.native.tsx rename src/components/ImageView/{index.js => index.tsx} (80%) delete mode 100644 src/components/ImageView/propTypes.js create mode 100644 src/components/ImageView/types.ts create mode 100644 src/components/MultiGestureCanvas/types.ts diff --git a/src/components/ImageView/index.native.js b/src/components/ImageView/index.native.js deleted file mode 100644 index 98349b213aa5..000000000000 --- a/src/components/ImageView/index.native.js +++ /dev/null @@ -1,52 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import Lightbox from '@components/Lightbox'; -import {zoomRangeDefaultProps, zoomRangePropTypes} from '@components/MultiGestureCanvas/propTypes'; -import {imageViewDefaultProps, imageViewPropTypes} from './propTypes'; - -/** - * On the native layer, we use a image library to handle zoom functionality - */ -const propTypes = { - ...imageViewPropTypes, - ...zoomRangePropTypes, - - /** Function for handle on press */ - onPress: PropTypes.func, - - /** Additional styles to add to the component */ - style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), -}; - -const defaultProps = { - ...imageViewDefaultProps, - ...zoomRangeDefaultProps, - - onPress: () => {}, - style: {}, -}; - -function ImageView({isAuthTokenRequired, url, onScaleChanged, onPress, style, zoomRange, onError, isUsedInCarousel, isSingleCarouselItem, carouselItemIndex, carouselActiveItemIndex}) { - const hasSiblingCarouselItems = isUsedInCarousel && !isSingleCarouselItem; - - return ( - - ); -} - -ImageView.propTypes = propTypes; -ImageView.defaultProps = defaultProps; -ImageView.displayName = 'ImageView'; - -export default ImageView; diff --git a/src/components/ImageView/index.native.tsx b/src/components/ImageView/index.native.tsx new file mode 100644 index 000000000000..74db0869f9e1 --- /dev/null +++ b/src/components/ImageView/index.native.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import Lightbox from '@components/Lightbox'; +import {zoomRangeDefaultProps} from '@components/MultiGestureCanvas/propTypes'; +import type * as ImageViewTypes from './types'; + +function ImageView({ + isAuthTokenRequired, + url, + onScaleChanged, + onPress = () => {}, + style = {}, + zoomRange = zoomRangeDefaultProps.zoomRange, + onError, + isUsedInCarousel, + isSingleCarouselItem, + carouselItemIndex, + carouselActiveItemIndex, +}: ImageViewTypes.ImageViewProps) { + const hasSiblingCarouselItems = isUsedInCarousel && !isSingleCarouselItem; + + return ( + + ); +} + +ImageView.displayName = 'ImageView'; + +export default ImageView; diff --git a/src/components/ImageView/index.js b/src/components/ImageView/index.tsx similarity index 80% rename from src/components/ImageView/index.js rename to src/components/ImageView/index.tsx index f16b37f328f5..b0bc2faed9fc 100644 --- a/src/components/ImageView/index.js +++ b/src/components/ImageView/index.tsx @@ -1,15 +1,18 @@ import React, {useCallback, useEffect, useRef, useState} from 'react'; -import {View} from 'react-native'; +import type {LayoutChangeEvent,GestureResponderEvent} from 'react-native'; +import { View} from 'react-native'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import Image from '@components/Image'; +import RESIZE_MODES from '@components/Image/resizeModes'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import CONST from '@src/CONST'; -import {imageViewDefaultProps, imageViewPropTypes} from './propTypes'; +import viewRef from '@src/types/utils/viewRef'; +import type * as ImageViewTypes from './types'; -function ImageView({isAuthTokenRequired, url, fileName, onError}) { +function ImageView({isAuthTokenRequired = false, url, fileName, onError = () => {}}: ImageViewTypes.ImageViewProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const [isLoading, setIsLoading] = useState(true); @@ -27,16 +30,10 @@ function ImageView({isAuthTokenRequired, url, fileName, onError}) { const [zoomScale, setZoomScale] = useState(0); const [zoomDelta, setZoomDelta] = useState({offsetX: 0, offsetY: 0}); - const scrollableRef = useRef(null); + const scrollableRef = useRef(null); const canUseTouchScreen = DeviceCapabilities.canUseTouchScreen(); - /** - * @param {Number} newContainerWidth - * @param {Number} newContainerHeight - * @param {Number} newImageWidth - * @param {Number} newImageHeight - */ - const setScale = (newContainerWidth, newContainerHeight, newImageWidth, newImageHeight) => { + const setScale = (newContainerWidth: number, newContainerHeight: number, newImageWidth: number, newImageHeight: number) => { if (!newContainerWidth || !newImageWidth || !newContainerHeight || !newImageHeight) { return; } @@ -44,10 +41,7 @@ function ImageView({isAuthTokenRequired, url, fileName, onError}) { setZoomScale(newZoomScale); }; - /** - * @param {SyntheticEvent} e - */ - const onContainerLayoutChanged = (e) => { + const onContainerLayoutChanged = (e: LayoutChangeEvent) => { const {width, height} = e.nativeEvent.layout; setScale(width, height, imgWidth, imgHeight); @@ -55,12 +49,7 @@ function ImageView({isAuthTokenRequired, url, fileName, onError}) { setContainerWidth(width); }; - /** - * When open image, set image width, height. - * @param {Number} imageWidth - * @param {Number} imageHeight - */ - const setImageRegion = (imageWidth, imageHeight) => { + const setImageRegion = (imageWidth: number, imageHeight: number) => { if (imageHeight <= 0) { return; } @@ -78,32 +67,23 @@ function ImageView({isAuthTokenRequired, url, fileName, onError}) { setIsZoomed(false); }; - const imageLoad = ({nativeEvent}) => { + const imageLoad = ({nativeEvent}: {nativeEvent: ImageViewTypes.ImageLoadNativeEventData}) => { setImageRegion(nativeEvent.width, nativeEvent.height); setIsLoading(false); }; - /** - * @param {SyntheticEvent} e - */ - const onContainerPressIn = (e) => { + const onContainerPressIn = (e: GestureResponderEvent) => { const {pageX, pageY} = e.nativeEvent; setIsMouseDown(true); setInitialX(pageX); setInitialY(pageY); - setInitialScrollLeft(scrollableRef.current.scrollLeft); - setInitialScrollTop(scrollableRef.current.scrollTop); + setInitialScrollLeft(scrollableRef.current?.scrollLeft ?? 0); + setInitialScrollTop(scrollableRef.current?.scrollTop ?? 0); }; - /** - * Convert touch point to zoomed point - * @param {Boolean} x x point when click zoom - * @param {Boolean} y y point when click zoom - * @returns {Object} converted touch point - */ - const getScrollOffset = (x, y) => { - let offsetX; - let offsetY; + const getScrollOffset = (x: number, y: number) => { + let offsetX = 0; + let offsetY = 0; // Container size bigger than clicked position offset if (x <= containerWidth / 2) { @@ -121,10 +101,8 @@ function ImageView({isAuthTokenRequired, url, fileName, onError}) { return {offsetX, offsetY}; }; - /** - * @param {SyntheticEvent} e - */ - const onContainerPress = (e) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const onContainerPress = (e: any) => { if (!isZoomed && !isDragging) { if (e.nativeEvent) { const {offsetX, offsetY} = e.nativeEvent; @@ -148,13 +126,10 @@ function ImageView({isAuthTokenRequired, url, fileName, onError}) { } }; - /** - * @param {SyntheticEvent} e - */ const trackPointerPosition = useCallback( - (e) => { + (e: MouseEvent) => { // Whether the pointer is released inside the ImageView - const isInsideImageView = scrollableRef.current.contains(e.nativeEvent.target); + const isInsideImageView = scrollableRef.current?.contains(e.target as Node); if (!isInsideImageView && isZoomed && isDragging && isMouseDown) { setIsDragging(false); @@ -165,14 +140,14 @@ function ImageView({isAuthTokenRequired, url, fileName, onError}) { ); const trackMovement = useCallback( - (e) => { + (e: MouseEvent) => { if (!isZoomed) { return; } - if (isDragging && isMouseDown) { - const x = e.nativeEvent.x; - const y = e.nativeEvent.y; + if (isDragging && isMouseDown && scrollableRef.current) { + const x = e.x; + const y = e.y; const moveX = initialX - x; const moveY = initialY - y; scrollableRef.current.scrollLeft = initialScrollLeft + moveX; @@ -218,7 +193,7 @@ function ImageView({isAuthTokenRequired, url, fileName, onError}) { style={isLoading || zoomScale === 0 ? undefined : [styles.w100, styles.h100]} // When Image dimensions are lower than the container boundary(zoomscale <= 1), use `contain` to render the image with natural dimensions. // Both `center` and `contain` keeps the image centered on both x and y axis. - resizeMode={zoomScale > 1 ? Image.resizeMode.center : Image.resizeMode.contain} + resizeMode={zoomScale > 1 ? RESIZE_MODES.center : RESIZE_MODES.contain} onLoadStart={imageLoadingStart} onLoad={imageLoad} onError={onError} @@ -229,7 +204,7 @@ function ImageView({isAuthTokenRequired, url, fileName, onError}) { } return ( @@ -249,7 +224,7 @@ function ImageView({isAuthTokenRequired, url, fileName, onError}) { source={{uri: url}} isAuthTokenRequired={isAuthTokenRequired} style={[styles.h100, styles.w100]} - resizeMode={Image.resizeMode.contain} + resizeMode={RESIZE_MODES.contain} onLoadStart={imageLoadingStart} onLoad={imageLoad} onError={onError} @@ -261,8 +236,6 @@ function ImageView({isAuthTokenRequired, url, fileName, onError}) { ); } -ImageView.propTypes = imageViewPropTypes; -ImageView.defaultProps = imageViewDefaultProps; ImageView.displayName = 'ImageView'; export default ImageView; diff --git a/src/components/ImageView/propTypes.js b/src/components/ImageView/propTypes.js deleted file mode 100644 index 3809d9aed043..000000000000 --- a/src/components/ImageView/propTypes.js +++ /dev/null @@ -1,46 +0,0 @@ -import PropTypes from 'prop-types'; - -const imageViewPropTypes = { - /** Whether source url requires authentication */ - isAuthTokenRequired: PropTypes.bool, - - /** Handles scale changed event in image zoom component. Used on native only */ - // eslint-disable-next-line react/no-unused-prop-types - onScaleChanged: PropTypes.func.isRequired, - - /** URL to full-sized image */ - url: PropTypes.string.isRequired, - - /** image file name */ - fileName: PropTypes.string.isRequired, - - /** Handles errors while displaying the image */ - onError: PropTypes.func, - - /** Whether this view is the active screen */ - isFocused: PropTypes.bool, - - /** Whether this AttachmentView is shown as part of a AttachmentCarousel */ - isUsedInCarousel: PropTypes.bool, - - /** When "isUsedInCarousel" is set to true, determines whether there is only one item in the carousel */ - isSingleCarouselItem: PropTypes.bool, - - /** The index of the carousel item */ - carouselItemIndex: PropTypes.number, - - /** The index of the currently active carousel item */ - carouselActiveItemIndex: PropTypes.number, -}; - -const imageViewDefaultProps = { - isAuthTokenRequired: false, - onError: () => {}, - isFocused: true, - isUsedInCarousel: false, - isSingleCarouselItem: false, - carouselItemIndex: 0, - carouselActiveItemIndex: 0, -}; - -export {imageViewPropTypes, imageViewDefaultProps}; diff --git a/src/components/ImageView/types.ts b/src/components/ImageView/types.ts new file mode 100644 index 000000000000..9bb3584955d4 --- /dev/null +++ b/src/components/ImageView/types.ts @@ -0,0 +1,50 @@ +import type ZoomRange from '@components/MultiGestureCanvas/types'; +import type {StyleProp, ViewStyle} from 'react-native'; + +type ImageViewProps = { + /** Whether source url requires authentication */ + isAuthTokenRequired?: boolean; + + /** Handles scale changed event in image zoom component. Used on native only */ + // eslint-disable-next-line react/no-unused-prop-types + onScaleChanged: (scale: number) => void; + + /** URL to full-sized image */ + url: string; + + /** image file name */ + fileName: string; + + /** Handles errors while displaying the image */ + onError?: () => void; + + /** Whether this view is the active screen */ + isFocused?: boolean; + + /** Whether this AttachmentView is shown as part of a AttachmentCarousel */ + isUsedInCarousel?: boolean; + + /** When "isUsedInCarousel" is set to true, determines whether there is only one item in the carousel */ + isSingleCarouselItem?: boolean; + + /** The index of the carousel item */ + carouselItemIndex?: number; + + /** The index of the currently active carousel item */ + carouselActiveItemIndex?: number; + + /** Function for handle on press */ + onPress?: () => void; + + /** Additional styles to add to the component */ + style?: StyleProp; + + /** Range of zoom that can be applied to the content by pinching or double tapping. */ + zoomRange?: ZoomRange; +}; + +type ImageLoadNativeEventData = { + width: number; + height: number; +}; +export type {ImageViewProps, ImageLoadNativeEventData}; diff --git a/src/components/Lightbox.js b/src/components/Lightbox.js index 45326edb4610..a941d23a5f16 100644 --- a/src/components/Lightbox.js +++ b/src/components/Lightbox.js @@ -44,7 +44,7 @@ const propTypes = { activeIndex: PropTypes.number, /** Additional styles to add to the component */ - style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), + style: PropTypes.oneOfType([PropTypes.bool, PropTypes.arrayOf(PropTypes.object), PropTypes.object]), }; const defaultProps = { diff --git a/src/components/MultiGestureCanvas/types.ts b/src/components/MultiGestureCanvas/types.ts new file mode 100644 index 000000000000..0242f045feef --- /dev/null +++ b/src/components/MultiGestureCanvas/types.ts @@ -0,0 +1,6 @@ +type ZoomRange = { + min: number; + max: number; +}; + +export default ZoomRange; From 5ffd8e7ad8fcd470a5820af21cae165552828af5 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 10 Jan 2024 12:27:15 +0700 Subject: [PATCH 02/11] lint fix --- src/components/ImageView/index.tsx | 4 ++-- src/components/ImageView/types.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ImageView/index.tsx b/src/components/ImageView/index.tsx index b0bc2faed9fc..f0d43121f9ef 100644 --- a/src/components/ImageView/index.tsx +++ b/src/components/ImageView/index.tsx @@ -1,6 +1,6 @@ import React, {useCallback, useEffect, useRef, useState} from 'react'; -import type {LayoutChangeEvent,GestureResponderEvent} from 'react-native'; -import { View} from 'react-native'; +import type {GestureResponderEvent, LayoutChangeEvent} from 'react-native'; +import {View} from 'react-native'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import Image from '@components/Image'; import RESIZE_MODES from '@components/Image/resizeModes'; diff --git a/src/components/ImageView/types.ts b/src/components/ImageView/types.ts index 9bb3584955d4..80fabed0ee58 100644 --- a/src/components/ImageView/types.ts +++ b/src/components/ImageView/types.ts @@ -1,5 +1,5 @@ -import type ZoomRange from '@components/MultiGestureCanvas/types'; import type {StyleProp, ViewStyle} from 'react-native'; +import type ZoomRange from '@components/MultiGestureCanvas/types'; type ImageViewProps = { /** Whether source url requires authentication */ From a6b46827254d9e06249d98207771a6ede85150b3 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 15 Jan 2024 17:31:34 +0700 Subject: [PATCH 03/11] type fix --- src/components/ImageView/index.native.tsx | 18 +++++++++--------- src/components/ImageView/index.tsx | 21 ++++++++++++++++----- src/components/ImageView/types.ts | 7 ++----- src/components/Lightbox.js | 3 ++- src/components/MultiGestureCanvas/types.ts | 3 ++- src/styles/stylePropTypes.js | 2 +- 6 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/components/ImageView/index.native.tsx b/src/components/ImageView/index.native.tsx index 74db0869f9e1..e36bb39d2bed 100644 --- a/src/components/ImageView/index.native.tsx +++ b/src/components/ImageView/index.native.tsx @@ -1,21 +1,21 @@ import React from 'react'; import Lightbox from '@components/Lightbox'; import {zoomRangeDefaultProps} from '@components/MultiGestureCanvas/propTypes'; -import type * as ImageViewTypes from './types'; +import type {ImageViewProps} from './types'; function ImageView({ - isAuthTokenRequired, + isAuthTokenRequired = false, url, onScaleChanged, - onPress = () => {}, - style = {}, + onPress, + style, zoomRange = zoomRangeDefaultProps.zoomRange, onError, - isUsedInCarousel, - isSingleCarouselItem, - carouselItemIndex, - carouselActiveItemIndex, -}: ImageViewTypes.ImageViewProps) { + isUsedInCarousel = false, + isSingleCarouselItem = false, + carouselItemIndex = 0, + carouselActiveItemIndex = 0, +}: ImageViewProps) { const hasSiblingCarouselItems = isUsedInCarousel && !isSingleCarouselItem; return ( diff --git a/src/components/ImageView/index.tsx b/src/components/ImageView/index.tsx index f0d43121f9ef..3731a4806cbc 100644 --- a/src/components/ImageView/index.tsx +++ b/src/components/ImageView/index.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useEffect, useRef, useState} from 'react'; -import type {GestureResponderEvent, LayoutChangeEvent} from 'react-native'; +import type {GestureResponderEvent, LayoutChangeEvent, NativeSyntheticEvent} from 'react-native'; import {View} from 'react-native'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import Image from '@components/Image'; @@ -10,9 +10,11 @@ import useThemeStyles from '@hooks/useThemeStyles'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import CONST from '@src/CONST'; import viewRef from '@src/types/utils/viewRef'; -import type * as ImageViewTypes from './types'; +import type {ImageLoadNativeEventData, ImageViewProps} from './types'; -function ImageView({isAuthTokenRequired = false, url, fileName, onError = () => {}}: ImageViewTypes.ImageViewProps) { +type ZoomDelta = {offsetX: number; offsetY: number}; + +function ImageView({isAuthTokenRequired = false, url, fileName, onError}: ImageViewProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const [isLoading, setIsLoading] = useState(true); @@ -28,7 +30,7 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError = () => const [imgWidth, setImgWidth] = useState(0); const [imgHeight, setImgHeight] = useState(0); const [zoomScale, setZoomScale] = useState(0); - const [zoomDelta, setZoomDelta] = useState({offsetX: 0, offsetY: 0}); + const [zoomDelta, setZoomDelta] = useState(); const scrollableRef = useRef(null); const canUseTouchScreen = DeviceCapabilities.canUseTouchScreen(); @@ -49,6 +51,9 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError = () => setContainerWidth(width); }; + /** + * When open image, set image width, height. + */ const setImageRegion = (imageWidth: number, imageHeight: number) => { if (imageHeight <= 0) { return; @@ -67,7 +72,7 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError = () => setIsZoomed(false); }; - const imageLoad = ({nativeEvent}: {nativeEvent: ImageViewTypes.ImageLoadNativeEventData}) => { + const imageLoad = ({nativeEvent}: NativeSyntheticEvent) => { setImageRegion(nativeEvent.width, nativeEvent.height); setIsLoading(false); }; @@ -81,6 +86,12 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError = () => setInitialScrollTop(scrollableRef.current?.scrollTop ?? 0); }; + /** + * Convert touch point to zoomed point + * @param x point when click zoom + * @param y point when click zoom + * @returns converted touch point + */ const getScrollOffset = (x: number, y: number) => { let offsetX = 0; let offsetY = 0; diff --git a/src/components/ImageView/types.ts b/src/components/ImageView/types.ts index 80fabed0ee58..9ea51fd3c82c 100644 --- a/src/components/ImageView/types.ts +++ b/src/components/ImageView/types.ts @@ -1,12 +1,11 @@ import type {StyleProp, ViewStyle} from 'react-native'; -import type ZoomRange from '@components/MultiGestureCanvas/types'; +import type {ZoomRange} from '@components/MultiGestureCanvas/types'; type ImageViewProps = { /** Whether source url requires authentication */ isAuthTokenRequired?: boolean; /** Handles scale changed event in image zoom component. Used on native only */ - // eslint-disable-next-line react/no-unused-prop-types onScaleChanged: (scale: number) => void; /** URL to full-sized image */ @@ -18,9 +17,6 @@ type ImageViewProps = { /** Handles errors while displaying the image */ onError?: () => void; - /** Whether this view is the active screen */ - isFocused?: boolean; - /** Whether this AttachmentView is shown as part of a AttachmentCarousel */ isUsedInCarousel?: boolean; @@ -47,4 +43,5 @@ type ImageLoadNativeEventData = { width: number; height: number; }; + export type {ImageViewProps, ImageLoadNativeEventData}; diff --git a/src/components/Lightbox.js b/src/components/Lightbox.js index a941d23a5f16..8b7d68befafd 100644 --- a/src/components/Lightbox.js +++ b/src/components/Lightbox.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {ActivityIndicator, PixelRatio, StyleSheet, View} from 'react-native'; import useStyleUtils from '@hooks/useStyleUtils'; +import stylePropTypes from '@styles/stylePropTypes'; import * as AttachmentsPropTypes from './Attachments/propTypes'; import Image from './Image'; import MultiGestureCanvas from './MultiGestureCanvas'; @@ -44,7 +45,7 @@ const propTypes = { activeIndex: PropTypes.number, /** Additional styles to add to the component */ - style: PropTypes.oneOfType([PropTypes.bool, PropTypes.arrayOf(PropTypes.object), PropTypes.object]), + style: stylePropTypes, }; const defaultProps = { diff --git a/src/components/MultiGestureCanvas/types.ts b/src/components/MultiGestureCanvas/types.ts index 0242f045feef..3c8480257700 100644 --- a/src/components/MultiGestureCanvas/types.ts +++ b/src/components/MultiGestureCanvas/types.ts @@ -3,4 +3,5 @@ type ZoomRange = { max: number; }; -export default ZoomRange; +// eslint-disable-next-line import/prefer-default-export +export type {ZoomRange}; diff --git a/src/styles/stylePropTypes.js b/src/styles/stylePropTypes.js index f9ecdb98ff13..b82db94140ee 100644 --- a/src/styles/stylePropTypes.js +++ b/src/styles/stylePropTypes.js @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -const stylePropTypes = PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object), PropTypes.func]); +const stylePropTypes = PropTypes.oneOfType([PropTypes.object, PropTypes.bool, PropTypes.arrayOf(PropTypes.object), PropTypes.func]); export default stylePropTypes; From 3f19479cb86d4204e9faf7d717b705a96a5b60a7 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 15 Jan 2024 17:41:57 +0700 Subject: [PATCH 04/11] fix: revert native event --- src/components/ImageView/index.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/ImageView/index.tsx b/src/components/ImageView/index.tsx index 3731a4806cbc..1c10c8116325 100644 --- a/src/components/ImageView/index.tsx +++ b/src/components/ImageView/index.tsx @@ -138,9 +138,10 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError}: ImageV }; const trackPointerPosition = useCallback( - (e: MouseEvent) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (e: any) => { // Whether the pointer is released inside the ImageView - const isInsideImageView = scrollableRef.current?.contains(e.target as Node); + const isInsideImageView = scrollableRef.current?.contains(e.nativeEvent.target); if (!isInsideImageView && isZoomed && isDragging && isMouseDown) { setIsDragging(false); From f8bb83d29eba0e059d54d31bd9cc627fd10be673 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 17 Jan 2024 15:37:25 +0700 Subject: [PATCH 05/11] remove any type --- src/components/ImageView/index.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/components/ImageView/index.tsx b/src/components/ImageView/index.tsx index 1c10c8116325..e8ee2ba3075a 100644 --- a/src/components/ImageView/index.tsx +++ b/src/components/ImageView/index.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useEffect, useRef, useState} from 'react'; +import React, {MouseEvent as ReactMouseEvent, useCallback, useEffect, useRef, useState} from 'react'; import type {GestureResponderEvent, LayoutChangeEvent, NativeSyntheticEvent} from 'react-native'; import {View} from 'react-native'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; @@ -112,8 +112,8 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError}: ImageV return {offsetX, offsetY}; }; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const onContainerPress = (e: any) => { + const onContainerPress = (mouseEvent?: GestureResponderEvent | KeyboardEvent) => { + const e = mouseEvent as unknown as ReactMouseEvent; if (!isZoomed && !isDragging) { if (e.nativeEvent) { const {offsetX, offsetY} = e.nativeEvent; @@ -138,10 +138,9 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError}: ImageV }; const trackPointerPosition = useCallback( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (e: any) => { + (e: MouseEvent) => { // Whether the pointer is released inside the ImageView - const isInsideImageView = scrollableRef.current?.contains(e.nativeEvent.target); + const isInsideImageView = scrollableRef.current?.contains(e.target as Node); if (!isInsideImageView && isZoomed && isDragging && isMouseDown) { setIsDragging(false); From e0c74d377dc06dc718e6a68e5fea927a54011843 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 17 Jan 2024 15:46:20 +0700 Subject: [PATCH 06/11] clean code --- src/components/ImageView/index.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/components/ImageView/index.tsx b/src/components/ImageView/index.tsx index e8ee2ba3075a..fb696fb03c64 100644 --- a/src/components/ImageView/index.tsx +++ b/src/components/ImageView/index.tsx @@ -112,11 +112,11 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError}: ImageV return {offsetX, offsetY}; }; - const onContainerPress = (mouseEvent?: GestureResponderEvent | KeyboardEvent) => { - const e = mouseEvent as unknown as ReactMouseEvent; + const onContainerPress = (e?: GestureResponderEvent | KeyboardEvent) => { + const mouseEvent = e as unknown as ReactMouseEvent; if (!isZoomed && !isDragging) { - if (e.nativeEvent) { - const {offsetX, offsetY} = e.nativeEvent; + if (mouseEvent.nativeEvent) { + const {offsetX, offsetY} = mouseEvent.nativeEvent; // Dividing clicked positions by the zoom scale to get coordinates // so that once we zoom we will scroll to the clicked location. @@ -139,8 +139,9 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError}: ImageV const trackPointerPosition = useCallback( (e: MouseEvent) => { + const mouseEvent = e as unknown as ReactMouseEvent; // Whether the pointer is released inside the ImageView - const isInsideImageView = scrollableRef.current?.contains(e.target as Node); + const isInsideImageView = scrollableRef.current?.contains(mouseEvent.nativeEvent.target as Node); if (!isInsideImageView && isZoomed && isDragging && isMouseDown) { setIsDragging(false); @@ -152,13 +153,14 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError}: ImageV const trackMovement = useCallback( (e: MouseEvent) => { + const mouseEvent = e as unknown as ReactMouseEvent; if (!isZoomed) { return; } if (isDragging && isMouseDown && scrollableRef.current) { - const x = e.x; - const y = e.y; + const x = mouseEvent.nativeEvent.x; + const y = mouseEvent.nativeEvent.y; const moveX = initialX - x; const moveY = initialY - y; scrollableRef.current.scrollLeft = initialScrollLeft + moveX; From 3e4c2fd231f7b378ce5707ea9b3a9a2ab7fd17d0 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 19 Jan 2024 16:21:41 +0700 Subject: [PATCH 07/11] remove nativeEvent --- src/components/ImageView/index.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/components/ImageView/index.tsx b/src/components/ImageView/index.tsx index fb696fb03c64..13a9033e2d4b 100644 --- a/src/components/ImageView/index.tsx +++ b/src/components/ImageView/index.tsx @@ -1,4 +1,5 @@ -import React, {MouseEvent as ReactMouseEvent, useCallback, useEffect, useRef, useState} from 'react'; +import type {MouseEvent as ReactMouseEvent} from 'react'; +import React, { useCallback, useEffect, useRef, useState} from 'react'; import type {GestureResponderEvent, LayoutChangeEvent, NativeSyntheticEvent} from 'react-native'; import {View} from 'react-native'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; @@ -138,10 +139,9 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError}: ImageV }; const trackPointerPosition = useCallback( - (e: MouseEvent) => { - const mouseEvent = e as unknown as ReactMouseEvent; + (event: MouseEvent) => { // Whether the pointer is released inside the ImageView - const isInsideImageView = scrollableRef.current?.contains(mouseEvent.nativeEvent.target as Node); + const isInsideImageView = scrollableRef.current?.contains(event.target as Node); if (!isInsideImageView && isZoomed && isDragging && isMouseDown) { setIsDragging(false); @@ -152,15 +152,14 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError}: ImageV ); const trackMovement = useCallback( - (e: MouseEvent) => { - const mouseEvent = e as unknown as ReactMouseEvent; + (event: MouseEvent) => { if (!isZoomed) { return; } if (isDragging && isMouseDown && scrollableRef.current) { - const x = mouseEvent.nativeEvent.x; - const y = mouseEvent.nativeEvent.y; + const x = event.x; + const y = event.y; const moveX = initialX - x; const moveY = initialY - y; scrollableRef.current.scrollLeft = initialScrollLeft + moveX; From df1502d54b41d5040d0a044165070d033c4e4e37 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 19 Jan 2024 16:25:17 +0700 Subject: [PATCH 08/11] nativeEvent checker --- src/components/ImageView/index.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/ImageView/index.tsx b/src/components/ImageView/index.tsx index 13a9033e2d4b..ed6cfd6413a3 100644 --- a/src/components/ImageView/index.tsx +++ b/src/components/ImageView/index.tsx @@ -1,4 +1,4 @@ -import type {MouseEvent as ReactMouseEvent} from 'react'; +import type {MouseEvent as ReactMouseEvent, SyntheticEvent} from 'react'; import React, { useCallback, useEffect, useRef, useState} from 'react'; import type {GestureResponderEvent, LayoutChangeEvent, NativeSyntheticEvent} from 'react-native'; import {View} from 'react-native'; @@ -113,11 +113,10 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError}: ImageV return {offsetX, offsetY}; }; - const onContainerPress = (e?: GestureResponderEvent | KeyboardEvent) => { - const mouseEvent = e as unknown as ReactMouseEvent; + const onContainerPress = (e?: GestureResponderEvent | KeyboardEvent | SyntheticEvent) => { if (!isZoomed && !isDragging) { - if (mouseEvent.nativeEvent) { - const {offsetX, offsetY} = mouseEvent.nativeEvent; + if (e && 'nativeEvent' in e && 'offsetX' in e.nativeEvent) { + const {offsetX, offsetY} = e.nativeEvent; // Dividing clicked positions by the zoom scale to get coordinates // so that once we zoom we will scroll to the clicked location. From dbadc31306a6e4fc53df78ab8031c70b2fbcef87 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 19 Jan 2024 16:28:12 +0700 Subject: [PATCH 09/11] lint fix --- src/components/ImageView/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ImageView/index.tsx b/src/components/ImageView/index.tsx index ed6cfd6413a3..3677111c09df 100644 --- a/src/components/ImageView/index.tsx +++ b/src/components/ImageView/index.tsx @@ -1,5 +1,5 @@ -import type {MouseEvent as ReactMouseEvent, SyntheticEvent} from 'react'; -import React, { useCallback, useEffect, useRef, useState} from 'react'; +import type {SyntheticEvent} from 'react'; +import React, {useCallback, useEffect, useRef, useState} from 'react'; import type {GestureResponderEvent, LayoutChangeEvent, NativeSyntheticEvent} from 'react-native'; import {View} from 'react-native'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; From 13c2a366301d182b2e59407124c075f4bca39072 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 22 Jan 2024 16:29:07 +0700 Subject: [PATCH 10/11] fix: clean code --- src/components/ImageView/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ImageView/index.tsx b/src/components/ImageView/index.tsx index 3677111c09df..ec37abf6d275 100644 --- a/src/components/ImageView/index.tsx +++ b/src/components/ImageView/index.tsx @@ -115,7 +115,7 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError}: ImageV const onContainerPress = (e?: GestureResponderEvent | KeyboardEvent | SyntheticEvent) => { if (!isZoomed && !isDragging) { - if (e && 'nativeEvent' in e && 'offsetX' in e.nativeEvent) { + if (e && 'nativeEvent' in e && e.nativeEvent instanceof PointerEvent) { const {offsetX, offsetY} = e.nativeEvent; // Dividing clicked positions by the zoom scale to get coordinates From 22f73e22300f70e9fbe2fbb67bd0d3d59898a4ee Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 25 Jan 2024 15:43:44 +0700 Subject: [PATCH 11/11] change to default export --- src/components/ImageView/types.ts | 2 +- src/components/MultiGestureCanvas/types.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/ImageView/types.ts b/src/components/ImageView/types.ts index 9ea51fd3c82c..bf83bc44d47b 100644 --- a/src/components/ImageView/types.ts +++ b/src/components/ImageView/types.ts @@ -1,5 +1,5 @@ import type {StyleProp, ViewStyle} from 'react-native'; -import type {ZoomRange} from '@components/MultiGestureCanvas/types'; +import type ZoomRange from '@components/MultiGestureCanvas/types'; type ImageViewProps = { /** Whether source url requires authentication */ diff --git a/src/components/MultiGestureCanvas/types.ts b/src/components/MultiGestureCanvas/types.ts index 3c8480257700..0242f045feef 100644 --- a/src/components/MultiGestureCanvas/types.ts +++ b/src/components/MultiGestureCanvas/types.ts @@ -3,5 +3,4 @@ type ZoomRange = { max: number; }; -// eslint-disable-next-line import/prefer-default-export -export type {ZoomRange}; +export default ZoomRange;