diff --git a/packages/api-proxy/src/platform/api/system/rnSystem.js b/packages/api-proxy/src/platform/api/system/rnSystem.js index 058d9f550f..eaaaed6930 100644 --- a/packages/api-proxy/src/platform/api/system/rnSystem.js +++ b/packages/api-proxy/src/platform/api/system/rnSystem.js @@ -5,7 +5,7 @@ import { getWindowInfo } from './rnWindowInfo' const getSystemInfoSync = function () { const windowInfo = getWindowInfo() - const { screenWidth, screenHeight, safeArea } = windowInfo + const { screenWidth, screenHeight } = windowInfo const result = { brand: DeviceInfo.getBrand(), @@ -13,7 +13,6 @@ const getSystemInfoSync = function () { system: `${DeviceInfo.getSystemName()} ${DeviceInfo.getSystemVersion()}`, platform: DeviceInfo.isEmulatorSync() ? 'emulator' : DeviceInfo.getSystemName(), deviceOrientation: screenWidth > screenHeight ? 'portrait' : 'landscape', - statusBarHeight: safeArea.top, fontSizeSetting: PixelRatio.getFontScale(), ...windowInfo } 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/mpx-web-view.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-web-view.tsx index 01ede3e3ec..aa5e2964c1 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-web-view.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-web-view.tsx @@ -165,15 +165,17 @@ const _WebView = forwardRef, WebViewProps>((pr } }) } + const events = { + ...(bindload && { onLoad: _load }), + ...(binderror && { onError: _error }), + ...(bindmessage && { onMessage: _message }) + } 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 diff --git a/packages/webpack-plugin/lib/runtime/components/react/utils.tsx b/packages/webpack-plugin/lib/runtime/components/react/utils.tsx index dcb3904753..5a9cc45534 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 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"