From ecfb6cbe81dae4a267e4b9ce4e9597fae918abd8 Mon Sep 17 00:00:00 2001 From: shangqunfeng Date: Fri, 29 Nov 2024 14:58:30 +0800 Subject: [PATCH 1/6] feat(image): image opt component. --- .../runtime/components/react/mpx-image.tsx | 427 ++++++++++++++++++ .../components/react/mpx-image/index.tsx | 345 -------------- .../components/react/mpx-image/svg.tsx | 22 - .../lib/runtime/components/react/utils.tsx | 2 + packages/webpack-plugin/package.json | 1 + 5 files changed, 430 insertions(+), 367 deletions(-) create mode 100644 packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx delete mode 100644 packages/webpack-plugin/lib/runtime/components/react/mpx-image/index.tsx delete mode 100644 packages/webpack-plugin/lib/runtime/components/react/mpx-image/svg.tsx diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx new file mode 100644 index 0000000000..4f2e1c46cf --- /dev/null +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx @@ -0,0 +1,427 @@ +/** + * ✔ src + * ✔ mode + * ✘ show-menu-by-longpress + * ✔ binderror + * ✔ bindload + * ✘ fade-in + * ✔ webp + * ✘ lazy-load + * ✔ bindtap + * ✔ DEFAULT_SIZE + */ +import { useEffect, useMemo, useState, useRef, forwardRef } from 'react' +import { + Image as RNImage, + View, + ImageStyle, + ImageResizeMode, + NativeSyntheticEvent, + ImageErrorEventData, + LayoutChangeEvent, + DimensionValue, + ImageLoadEventData +} from 'react-native' +import { noop } from '@mpxjs/utils' +import { SvgCssUri } from 'react-native-svg/css' +import useInnerProps, { getCustomEvent } from './getInnerListeners' +import useNodesRef, { HandlerRef } from './useNodesRef' +import { SVG_REGEXP, useLayout, useTransformStyle, renderImage } from './utils' + +export type Mode = + | 'scaleToFill' + | 'aspectFit' + | 'aspectFill' + | 'widthFix' + | 'heightFix' + | 'top' + | 'bottom' + | 'center' + | 'left' + | 'right' + | 'top left' + | 'top right' + | 'bottom left' + | 'bottom right' + +export interface ImageProps { + src?: string + mode?: Mode + svg?: boolean + style?: ImageStyle & Record + 'enable-offset'?: boolean; + 'enable-var'?: boolean + 'external-var-context'?: Record + 'parent-font-size'?: number + 'parent-width'?: number + 'parent-height'?: number + 'enable-fast-image'?: boolean + bindload?: (evt: NativeSyntheticEvent | unknown) => void + binderror?: (evt: NativeSyntheticEvent | unknown) => void +} + +interface ImageState { + viewWidth?: number + viewHeight?: number + imageWidth?: number + imageHeight?: number + ratio?: number +} + +const DEFAULT_IMAGE_WIDTH = 320 +const DEFAULT_IMAGE_HEIGHT = 240 + +const cropMode: Mode[] = [ + 'top', + 'bottom', + 'center', + 'right', + 'left', + 'top left', + 'top right', + 'bottom left', + 'bottom right' +] + +const ModeMap = new Map([ + ['scaleToFill', 'stretch'], + ['aspectFit', 'contain'], + ['aspectFill', 'cover'], + ['widthFix', 'stretch'], + ['heightFix', 'stretch'], + ...cropMode.map<[Mode, ImageResizeMode]>(mode => [mode, 'stretch']) +]) + +const isNumber = (value: DimensionValue) => typeof value === 'number' + +const relativeCenteredSize = (viewSize: number, imageSize: number) => (viewSize - imageSize) / 2 + +function noMeetCalcRule (isSvg: boolean, mode: Mode, viewWidth: number, viewHeight: number, ratio: number) { + const isMeetSize = viewWidth && viewHeight && ratio + if (isSvg && !isMeetSize) return true + if (!isSvg && !['scaleToFill', 'aspectFit', 'aspectFill'].includes(mode) && !isMeetSize) return true + return false +} + +const Image = forwardRef, ImageProps>((props, ref): JSX.Element => { + const { + src = '', + mode = 'scaleToFill', + style = {}, + 'enable-var': enableVar, + 'external-var-context': externalVarContext, + 'parent-font-size': parentFontSize, + 'enable-fast-image': enableFastImage, + 'parent-width': parentWidth, + 'parent-height': parentHeight, + bindload, + binderror + } = props + + const defaultStyle = { + width: DEFAULT_IMAGE_WIDTH, + height: DEFAULT_IMAGE_HEIGHT + } + + const styleObj = { + ...defaultStyle, + ...style, + overflow: 'hidden' + } + + const state = useRef({}) + + const nodeRef = useRef(null) + useNodesRef(props, ref, nodeRef, { + defaultStyle + }) + + const isSvg = SVG_REGEXP.test(src) + const isWidthFixMode = mode === 'widthFix' + const isHeightFixMode = mode === 'heightFix' + const isCropMode = cropMode.includes(mode) + const isLayoutMode = isWidthFixMode || isHeightFixMode || isCropMode + const resizeMode: ImageResizeMode = ModeMap.get(mode) || 'stretch' + + const onLayout = ({ nativeEvent: { layout: { width, height } } }: LayoutChangeEvent) => { + state.current.viewWidth = width + state.current.viewHeight = height + + if (state.current.imageWidth && state.current.imageHeight && state.current.ratio) { + setViewWidth(width) + setViewHeight(height) + setRatio(state.current.ratio) + setImageWidth(state.current.imageWidth) + setImageHeight(state.current.imageHeight) + state.current = {} + setLoaded(true) + } + } + + const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }) + + const { layoutRef, layoutStyle, layoutProps } = useLayout({ + props, + hasSelfPercent, + setWidth, + setHeight, + nodeRef, + onLayout: isLayoutMode ? onLayout : noop + }) + + const { width, height } = normalStyle + + const [viewWidth, setViewWidth] = useState(isNumber(width) ? width : 0) + const [viewHeight, setViewHeight] = useState(isNumber(height) ? height : 0) + const [imageWidth, setImageWidth] = useState(0) + const [imageHeight, setImageHeight] = useState(0) + const [ratio, setRatio] = useState(0) + const [loaded, setLoaded] = useState(!isLayoutMode) + + const fixedHeight = useMemo(() => { + const fixed = viewWidth * ratio + return !fixed ? viewHeight : fixed + }, [ratio, viewWidth, viewHeight]) + + const fixedWidth = useMemo(() => { + if (!ratio) return viewWidth + const fixed = viewHeight / ratio + return !fixed ? viewWidth : fixed + }, [ratio, viewWidth, viewHeight]) + + const modeStyle: ImageStyle = useMemo(() => { + if (noMeetCalcRule(isSvg, mode, viewWidth, viewHeight, ratio)) return {} + switch (mode) { + case 'scaleToFill': + case 'aspectFit': + if (isSvg) { + const scale = ratio <= 1 + ? imageWidth >= viewWidth ? viewWidth / imageWidth : imageWidth / viewWidth + : imageHeight >= viewHeight ? viewHeight / imageHeight : imageHeight / viewHeight + return { + transform: [ + { scale }, + ratio <= 1 ? { translateY: -(imageHeight * scale - viewHeight) / 2 / scale } : { translateX: -(imageWidth * scale - viewWidth) / 2 / scale } + ] + } + } + return {} + case 'aspectFill': + if (isSvg) { + const scale = ratio >= 1 + ? imageWidth >= viewWidth ? viewWidth / imageWidth : imageWidth / viewWidth + : imageHeight >= viewHeight ? viewHeight / imageHeight : imageHeight / viewHeight + return { + transform: [ + { scale }, + ratio >= 1 ? { translateY: -(imageHeight * scale - viewHeight) / 2 / scale } : { translateX: -(imageWidth * scale - viewWidth) / 2 / scale } + ] + } + } + return {} + case 'widthFix': + case 'heightFix': + if (isSvg) { + const scale = ratio >= 1 + ? imageWidth >= fixedWidth ? fixedWidth / imageWidth : imageWidth / fixedWidth + : imageHeight >= fixedHeight ? fixedHeight / imageHeight : imageHeight / fixedHeight + return { + transform: [{ scale }] + } + } + return {} + case 'top': + return { + transform: [ + { translateX: relativeCenteredSize(viewWidth, imageWidth) } + ] + } + case 'bottom': + return { + transform: [ + { translateY: viewHeight - imageHeight }, + { translateX: relativeCenteredSize(viewWidth, imageWidth) } + ] + } + case 'center': + return { + transform: [ + { translateY: relativeCenteredSize(viewHeight, imageHeight) }, + { translateX: relativeCenteredSize(viewWidth, imageWidth) } + ] + } + case 'left': + return { + transform: [ + { translateY: relativeCenteredSize(viewHeight, imageHeight) } + ] + } + case 'right': + return { + transform: [ + { translateY: relativeCenteredSize(viewHeight, imageHeight) }, + { translateX: viewWidth - imageWidth } + ] + } + case 'top left': + return {} + case 'top right': + return { + transform: [ + { translateX: viewWidth - imageWidth } + ] + } + case 'bottom left': + return { + transform: [ + { translateY: viewHeight - imageHeight } + ] + } + case 'bottom right': + return { + transform: [ + { translateY: viewHeight - imageHeight }, + { translateX: viewWidth - imageWidth } + ] + } + default: + return {} + } + }, [isSvg, mode, viewWidth, viewHeight, imageWidth, imageHeight, ratio, fixedWidth, fixedHeight]) + + const onSvgLoad = (evt: LayoutChangeEvent) => { + const { width, height } = evt.nativeEvent.layout + setRatio(!width ? 0 : height / width) + setImageWidth(width) + setImageHeight(height) + + bindload && bindload( + getCustomEvent( + 'load', + evt, + { + detail: { width, height }, + layoutRef + }, + props + ) + ) + } + + const onSvgError = (evt: Error) => { + binderror!( + getCustomEvent( + 'error', + evt, + { + detail: { errMsg: evt?.message }, + layoutRef + }, + props + ) + ) + } + + const onImageLoad = (evt: NativeSyntheticEvent) => { + evt.persist() + RNImage.getSize(src, (width: number, height: number) => { + bindload!( + getCustomEvent( + 'load', + evt, + { + detail: { width, height }, + layoutRef + }, + props + ) + ) + }) + } + + const onImageError = (evt: NativeSyntheticEvent) => { + binderror!( + getCustomEvent( + 'error', + evt, + { + detail: { errMsg: evt.nativeEvent.error }, + layoutRef + }, + props + ) + ) + } + + useEffect(() => { + if (!isSvg && isLayoutMode) { + RNImage.getSize(src, (width: number, height: number) => { + state.current.imageWidth = width + state.current.imageHeight = height + state.current.ratio = !width ? 0 : height / width + + if (state.current.viewWidth && state.current.viewHeight) { + setViewWidth(state.current.viewWidth) + setViewHeight(state.current.viewHeight) + setRatio(!width ? 0 : height / width) + setImageWidth(width) + setImageHeight(height) + state.current = {} + setLoaded(true) + } + }) + } + }, [src, isSvg, isLayoutMode]) + + const innerProps = useInnerProps( + props, + { + ref: nodeRef, + style: { + ...normalStyle, + ...layoutStyle, + ...(isHeightFixMode && { width: fixedWidth }), + ...(isWidthFixMode && { height: fixedHeight }) + }, + ...layoutProps + }, + [], + { + layoutRef + } + ) + + + return ( + + { + isSvg + ? + : loaded && renderImage({ + source: { uri: src }, + resizeMode: resizeMode, + onLoad: bindload && onImageLoad, + onError: binderror && onImageError, + style: { + transformOrigin: 'top left', + width: isCropMode ? imageWidth : '100%', + height: isCropMode ? imageHeight : '100%', + ...(isCropMode && modeStyle) + } + }, enableFastImage) + } + + ) +}) + +Image.displayName = 'mpx-image' + +export default Image diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-image/index.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-image/index.tsx deleted file mode 100644 index 78e2e921dd..0000000000 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-image/index.tsx +++ /dev/null @@ -1,345 +0,0 @@ -/** - * ✔ src - * - mode: Partially, Only SVG format do not support - * ✘ show-menu-by-longpress - * ✔ binderror - * ✔ bindload - * ✘ fade-in - * ✔ webp - * ✘ lazy-load - * ✔ bindtap - * ✔ DEFAULT_SIZE - */ -import { useEffect, useMemo, useState, useRef, forwardRef } from 'react' - -import { - Image as RNImage, - View, - ImageStyle, - ImageSourcePropType, - ImageResizeMode, - StyleSheet, - NativeSyntheticEvent, - ImageErrorEventData, - LayoutChangeEvent, - DimensionValue, - ImageLoadEventData -} from 'react-native' -import useInnerProps, { getCustomEvent } from '../getInnerListeners' -import useNodesRef, { HandlerRef } from '../useNodesRef' -import { useLayout, useTransformStyle } from '../utils' - -export type Mode = - | 'scaleToFill' - | 'aspectFit' - | 'aspectFill' - | 'widthFix' - | 'heightFix' - | 'top' - | 'bottom' - | 'center' - | 'left' - | 'right' - | 'top left' - | 'top right' - | 'bottom left' - | 'bottom right' - -export type SvgNumberProp = string | number | undefined - -export interface ImageProps { - src?: string - mode?: Mode - svg?: boolean - style?: ImageStyle & Record - 'enable-offset'?: boolean; - 'enable-var'?: boolean - 'external-var-context'?: Record - 'parent-font-size'?: number - 'parent-width'?: number - 'parent-height'?: number - bindload?: (evt: NativeSyntheticEvent | unknown) => void - binderror?: (evt: NativeSyntheticEvent | unknown) => void -} - -const DEFAULT_IMAGE_WIDTH = 320 -const DEFAULT_IMAGE_HEIGHT = 240 -// const REMOTE_SVG_REGEXP = /https?:\/\/.*\.(?:svg)/i - -// const styls = StyleSheet.create({ -// suspense: { -// display: 'flex', -// justifyContent: 'center', -// alignItems: 'center', -// width: '100%', -// height: '100%', -// }, -// }) - -const cropMode: Mode[] = [ - 'top', - 'bottom', - 'center', - 'right', - 'left', - 'top left', - 'top right', - 'bottom left', - 'bottom right' -] - -const ModeMap = new Map([ - ['scaleToFill', 'stretch'], - ['aspectFit', 'contain'], - ['aspectFill', 'cover'], - ['widthFix', 'stretch'], - ['heightFix', 'stretch'], - ...cropMode.map<[Mode, ImageResizeMode]>(mode => [mode, 'stretch']) -]) - -const isNumber = (value: DimensionValue) => typeof value === 'number' - -const relativeCenteredSize = (viewSize: number, imageSize: number) => (viewSize - imageSize) / 2 - -// const Svg = lazy(() => import('./svg')) - -// const Fallback = ( -// -// loading ... -// -// ) - -const Image = forwardRef, ImageProps>((props, ref): JSX.Element => { - const { - src = '', - mode = 'scaleToFill', - // svg = false, - style = {}, - 'enable-var': enableVar, - 'external-var-context': externalVarContext, - 'parent-font-size': parentFontSize, - 'parent-width': parentWidth, - 'parent-height': parentHeight, - bindload, - binderror - } = props - - const defaultStyle = { - width: DEFAULT_IMAGE_WIDTH, - height: DEFAULT_IMAGE_HEIGHT - } - - const styleObj = { - ...defaultStyle, - ...style, - overflow: 'hidden' - } - - const nodeRef = useRef(null) - useNodesRef(props, ref, nodeRef, { - defaultStyle - }) - - const onLayout = ({ nativeEvent: { layout: { width, height } } }: LayoutChangeEvent) => { - setViewWidth(width) - setViewHeight(height) - } - - const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }) - - const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef, onLayout }) - - const { width, height } = normalStyle - - const preSrc = useRef() - - const resizeMode: ImageResizeMode = ModeMap.get(mode) || 'stretch' - const isWidthFixMode = mode === 'widthFix' - const isHeightFixMode = mode === 'heightFix' - const isCropMode = cropMode.includes(mode) - - const source: ImageSourcePropType = typeof src === 'string' ? { uri: src } : src - - const [viewWidth, setViewWidth] = useState(isNumber(width) ? width : 0) - const [viewHeight, setViewHeight] = useState(isNumber(height) ? height : 0) - const [imageWidth, setImageWidth] = useState(0) - const [imageHeight, setImageHeight] = useState(0) - const [ratio, setRatio] = useState(0) - const [loaded, setLoaded] = useState(false) - - const fixedHeight = useMemo(() => { - const fixed = viewWidth * ratio - return !fixed ? viewHeight : fixed - }, [ratio, viewWidth, viewHeight]) - - const fixedWidth = useMemo(() => { - if (!ratio) return viewWidth - const fixed = viewHeight / ratio - return !fixed ? viewWidth : fixed - }, [ratio, viewWidth, viewHeight]) - - const cropModeStyle: ImageStyle = useMemo(() => { - switch (mode) { - case 'top': - return { top: 0, left: relativeCenteredSize(viewWidth, imageWidth) } - case 'bottom': - return { top: 'auto', bottom: 0, left: relativeCenteredSize(viewWidth, imageWidth) } - case 'center': - return { top: relativeCenteredSize(viewHeight, imageHeight), left: relativeCenteredSize(viewWidth, imageWidth) } - case 'left': - return { top: relativeCenteredSize(viewHeight, imageHeight), left: 0 } - case 'right': - return { top: relativeCenteredSize(viewHeight, imageHeight), left: 'auto', right: 0 } - case 'top left': - return { top: 0, left: 0 } - case 'top right': - return { top: 0, left: 'auto', right: 0 } - case 'bottom left': - return { top: 'auto', bottom: 0, left: 0 } - case 'bottom right': - return { top: 'auto', bottom: 0, left: 'auto', right: 0 } - default: - return {} - } - }, [mode, viewWidth, viewHeight, imageWidth, imageHeight]) - - const onImageLoad = (evt: NativeSyntheticEvent) => { - if (!bindload) return - if (typeof src === 'string') { - evt.persist() - RNImage.getSize(src, (width: number, height: number) => { - bindload( - getCustomEvent( - 'load', - evt, - { - detail: { width, height }, - layoutRef - }, - props - ) - ) - }) - } else { - const { width = 0, height = 0 } = RNImage.resolveAssetSource(src) || {} - bindload( - getCustomEvent( - 'load', - evt, - { - detail: { width, height }, - layoutRef - }, - props - ) - ) - } - } - - const onImageError = (evt: NativeSyntheticEvent) => { - binderror && - binderror( - getCustomEvent( - 'error', - evt, - { - detail: { errMsg: evt.nativeEvent.error }, - layoutRef - }, - props - ) - ) - } - - useEffect(() => { - if (!isWidthFixMode && !isHeightFixMode && !isCropMode) { - setLoaded(true) - return - } - - const changed = preSrc.current !== src - preSrc.current = src - changed && setLoaded(false) - - if (typeof src === 'string') { - RNImage.getSize(src, (width: number, height: number) => { - if (isWidthFixMode || isHeightFixMode) { - setRatio(width === 0 ? 0 : height / width) - } - if (isCropMode) { - setImageWidth(width) - setImageHeight(height) - } - changed && setLoaded(true) - }) - } else { - const { width = 0, height = 0 } = RNImage.resolveAssetSource(src) || {} - if (isWidthFixMode || isHeightFixMode) { - setRatio(width === 0 ? 0 : height / width) - } - if (isCropMode) { - setImageWidth(width) - setImageHeight(height) - } - changed && setLoaded(true) - } - }, [isWidthFixMode, isHeightFixMode, isCropMode, src]) - - const innerProps = useInnerProps(props, { - ref: nodeRef, - style: { - ...normalStyle, - ...layoutStyle, - ...(isHeightFixMode && { width: fixedWidth }), - ...(isWidthFixMode && { height: fixedHeight }) - }, - ...layoutProps - }, - [], - { - layoutRef - }) - - // if (typeof src === 'string' && REMOTE_SVG_REGEXP.test(src)) { - // return ( - // - // - // - // - // - // ) - // } - - // if (svg) { - // return ( - // - // - // - // - // - // ) - // } - - return ( - - { - loaded && - } - - ) -}) - -Image.displayName = 'MpxImage' - -export default Image diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-image/svg.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-image/svg.tsx deleted file mode 100644 index 205c941fc1..0000000000 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-image/svg.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { JSX } from 'react' -import type { ImageSourcePropType, ImageStyle, StyleProp } from 'react-native' -import { SvgCssUri, WithLocalSvg } from 'react-native-svg/css' -interface SvgProps { - local?: boolean - src: string | ImageSourcePropType - style?: StyleProp - width?: string | number - height?: string | number -} - -const Svg = ({ local = false, src, style, width, height }: SvgProps): JSX.Element => { - return local - ? ( - - ) - : ( - - ) -} - -export default Svg diff --git a/packages/webpack-plugin/lib/runtime/components/react/utils.tsx b/packages/webpack-plugin/lib/runtime/components/react/utils.tsx index dcb3904753..4c69b7589c 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/utils.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/utils.tsx @@ -10,6 +10,7 @@ import type { AnyFunc, ExtendedFunctionComponent } from './types/common' export const TEXT_STYLE_REGEX = /color|font.*|text.*|letterSpacing|lineHeight|includeFontPadding|writingDirection/ export const PERCENT_REGEX = /^\s*-?\d+(\.\d+)?%\s*$/ export const URL_REGEX = /^\s*url\(["']?(.*?)["']?\)\s*$/ +export const SVG_REGEXP = /https?:\/\/.*\.(?:svg)/i export const BACKGROUND_REGEX = /^background(Image|Size|Repeat|Position)$/ export const TEXT_PROPS_REGEX = /ellipsizeMode|numberOfLines/ export const DEFAULT_FONT_SIZE = 16 @@ -610,3 +611,4 @@ export function pickStyle (styleObj: Record = {}, pickedKeys: Array return acc }, {}) } +g \ No newline at end of file diff --git a/packages/webpack-plugin/package.json b/packages/webpack-plugin/package.json index 8d0bbae0b8..84291a684d 100644 --- a/packages/webpack-plugin/package.json +++ b/packages/webpack-plugin/package.json @@ -91,6 +91,7 @@ "react-native-gesture-handler": "^2.18.1", "react-native-linear-gradient": "^2.8.3", "react-native-reanimated": "^3.15.2", + "react-native-svg": "^15.8.0", "react-native-safe-area-context": "^4.12.0", "react-native-webview": "^13.12.2", "rimraf": "^6.0.1" From 53db3ec9817ba74f471a3ec505e7c1053755791f Mon Sep 17 00:00:00 2001 From: shangqunfeng Date: Fri, 29 Nov 2024 14:59:37 +0800 Subject: [PATCH 2/6] fix(*): fix code. --- packages/webpack-plugin/lib/runtime/components/react/utils.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/webpack-plugin/lib/runtime/components/react/utils.tsx b/packages/webpack-plugin/lib/runtime/components/react/utils.tsx index 4c69b7589c..c65a650dbe 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/utils.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/utils.tsx @@ -610,5 +610,4 @@ export function pickStyle (styleObj: Record = {}, pickedKeys: Array } return acc }, {}) -} -g \ No newline at end of file +} \ No newline at end of file From 889c84633446d1f31ac6342def9b05c0e011e843 Mon Sep 17 00:00:00 2001 From: WX-DongXing Date: Fri, 29 Nov 2024 15:09:26 +0800 Subject: [PATCH 3/6] feat: remove useless types --- .../lib/runtime/components/react/mpx-image.tsx | 1 - .../runtime/components/react/types/global.d.ts | 16 ---------------- 2 files changed, 17 deletions(-) diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx index 4f2e1c46cf..1592c0895b 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx @@ -391,7 +391,6 @@ const Image = forwardRef, ImageProps>((props, re } ) - return ( { diff --git a/packages/webpack-plugin/lib/runtime/components/react/types/global.d.ts b/packages/webpack-plugin/lib/runtime/components/react/types/global.d.ts index 93eed03767..06f51e76da 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/types/global.d.ts +++ b/packages/webpack-plugin/lib/runtime/components/react/types/global.d.ts @@ -1,19 +1,3 @@ -declare module 'react-native-svg/css' { - import type { ImageSourcePropType, StyleProp, ImageStyle } from 'react-native' - import type { SvgProps as SvgCssUriProps } from 'react-native-svg' - - export const SvgCssUri: React.ComponentType - - export interface WithLocalSvgProps { - asset: ImageSourcePropType - style?: StyleProp - width?: string | number - height?: string | number - } - - export const WithLocalSvg: React.ComponentType -} - declare module '@mpxjs/utils' { export function isEmptyObject (obj: Object): boolean export function isFunction (fn: unknown): boolean From 15c7cc52e02c0d581078e1e95d6b4019595ee036 Mon Sep 17 00:00:00 2001 From: qy <41629087+nianxiongdi@users.noreply.github.com> Date: Sat, 30 Nov 2024 11:57:24 +0800 Subject: [PATCH 4/6] Update utils.tsx --- packages/webpack-plugin/lib/runtime/components/react/utils.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack-plugin/lib/runtime/components/react/utils.tsx b/packages/webpack-plugin/lib/runtime/components/react/utils.tsx index c65a650dbe..5a9cc45534 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/utils.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/utils.tsx @@ -610,4 +610,4 @@ export function pickStyle (styleObj: Record = {}, pickedKeys: Array } return acc }, {}) -} \ No newline at end of file +} From c0d6987f034f3ffefe482720385d4638c766886b Mon Sep 17 00:00:00 2001 From: shangqunfeng Date: Mon, 9 Dec 2024 12:56:07 +0800 Subject: [PATCH 5/6] fix(*): fix code. --- .../lib/runtime/components/react/mpx-image.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx index 1592c0895b..07c30371ee 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx @@ -360,7 +360,11 @@ const Image = forwardRef, ImageProps>((props, re state.current.imageHeight = height state.current.ratio = !width ? 0 : height / width - if (state.current.viewWidth && state.current.viewHeight) { + if (isWidthFixMode + ? state.current.viewWidth + : isHeightFixMode + ? state.current.viewHeight + : state.current.viewWidth && state.current.viewHeight) { setViewWidth(state.current.viewWidth) setViewHeight(state.current.viewHeight) setRatio(!width ? 0 : height / width) From 7a3cb8a2c7da076e79543e9070ed7cfea6bcc5ff Mon Sep 17 00:00:00 2001 From: WX-DongXing Date: Mon, 9 Dec 2024 19:34:28 +0800 Subject: [PATCH 6/6] feat: extend object --- .../runtime/components/react/mpx-image.tsx | 66 +++++++++++-------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx index 07c30371ee..998dddd179 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx @@ -26,7 +26,7 @@ import { noop } from '@mpxjs/utils' import { SvgCssUri } from 'react-native-svg/css' import useInnerProps, { getCustomEvent } from './getInnerListeners' import useNodesRef, { HandlerRef } from './useNodesRef' -import { SVG_REGEXP, useLayout, useTransformStyle, renderImage } from './utils' +import { SVG_REGEXP, useLayout, useTransformStyle, renderImage, extendObject } from './utils' export type Mode = | 'scaleToFill' @@ -123,11 +123,12 @@ const Image = forwardRef, ImageProps>((props, re height: DEFAULT_IMAGE_HEIGHT } - const styleObj = { - ...defaultStyle, - ...style, - overflow: 'hidden' - } + const styleObj = extendObject( + {}, + defaultStyle, + style, + { overflow: 'hidden' } + ) const state = useRef({}) @@ -365,8 +366,8 @@ const Image = forwardRef, ImageProps>((props, re : isHeightFixMode ? state.current.viewHeight : state.current.viewWidth && state.current.viewHeight) { - setViewWidth(state.current.viewWidth) - setViewHeight(state.current.viewHeight) + state.current.viewWidth && setViewWidth(state.current.viewWidth) + state.current.viewHeight && setViewHeight(state.current.viewHeight) setRatio(!width ? 0 : height / width) setImageWidth(width) setImageHeight(height) @@ -379,17 +380,24 @@ const Image = forwardRef, ImageProps>((props, re const innerProps = useInnerProps( props, - { - ref: nodeRef, - style: { - ...normalStyle, - ...layoutStyle, - ...(isHeightFixMode && { width: fixedWidth }), - ...(isWidthFixMode && { height: fixedHeight }) + extendObject( + { + ref: nodeRef, + style: extendObject( + {}, + normalStyle, + layoutStyle, + isHeightFixMode ? { width: fixedWidth } : {}, + isWidthFixMode ? { height: fixedHeight } : {} + ) }, - ...layoutProps - }, - [], + layoutProps + ), + [ + 'src', + 'mode', + 'svg' + ], { layoutRef } @@ -403,22 +411,24 @@ const Image = forwardRef, ImageProps>((props, re uri={src} onLayout={onSvgLoad} onError={binderror && onSvgError} - style={{ - transformOrigin: 'top left', - ...modeStyle - }} + style={extendObject( + { transformOrigin: 'top left' }, + modeStyle + )} /> : loaded && renderImage({ source: { uri: src }, resizeMode: resizeMode, onLoad: bindload && onImageLoad, onError: binderror && onImageError, - style: { - transformOrigin: 'top left', - width: isCropMode ? imageWidth : '100%', - height: isCropMode ? imageHeight : '100%', - ...(isCropMode && modeStyle) - } + style: extendObject( + { + transformOrigin: 'top left', + width: isCropMode ? imageWidth : '100%', + height: isCropMode ? imageHeight : '100%' + }, + isCropMode ? modeStyle : {} + ) }, enableFastImage) }