diff --git a/packages/api-proxy/src/platform/api/animation/animation.react.js b/packages/api-proxy/src/platform/api/animation/animation.react.js new file mode 100644 index 0000000000..b3c59c11bb --- /dev/null +++ b/packages/api-proxy/src/platform/api/animation/animation.react.js @@ -0,0 +1,281 @@ +class Animation { + constructor ( + { + duration = 400, + delay = 0, + timingFunction = 'linear', + transformOrigin = '50% 50% 0' + } = {} + ) { + // 默认值 + this._setDefault(duration, delay, timingFunction, transformOrigin) + this.id = 0 + } + + _transformUnit (...args) { + return args.map(each => { + return global.__formatValue(each) + }) + } + + _formatTransformOrigin (transformOrigin) { + const transformOriginArr = transformOrigin.trim().split(/\s+/, 3).map(item => global.__formatValue(item)) + switch (transformOriginArr.length) { + case 0: + transformOriginArr.push('50%', '50%', 0) + break + case 1: + transformOriginArr.push('50%', 0) + break + case 2: + transformOriginArr.push(0) + break + } + return transformOriginArr + } + + // 设置默认值 + _setDefault (duration, delay, timingFunction, transformOrigin) { + this.DEFAULT = { duration, delay, timingFunction, transformOrigin } + } + + // 属性组合 + rules = new Map() + // transform 对象 + transform = new Map() + // 组合动画 + steps = [] + + matrix (a, b, c, d, tx, ty) { // Todo + console.error('React Native 不支持 matrix 动画') + // this.transform.set('matrix', [a, b, c, d, tx, ty]) + return this + } + + matrix3d (a1, b1, c1, d1, + a2, b2, c2, d2, + a3, b3, c3, d3, + a4, b4, c4, d4 + ) { + console.error('React Native 不支持 matrix3d 动画') + // this.transform.set('matrix3d', [ // Todo + // a1, b1, c1, d1, + // a2, b2, c2, d2, + // a3, b3, c3, d3, + // a4, b4, c4, d4 + // ]) + return this + } + + rotate (angle) { // 旋转变换 + this.transform.set('rotate', `${angle}deg`) + return this + } + + rotate3d (x, y, z, angle) { + if (typeof y !== 'number') { + this.transform.set('rotate3d', x) + } else { + // this.transform.set('rotate3d', [x, y, z, angle]) + this.rotateX(x) + this.rotateY(y) + this.rotateZ(z) + this.rotate(angle) + } + return this + } + + rotateX (angle) { + this.transform.set('rotateX', `${angle}deg`) + return this + } + + rotateY (angle) { + this.transform.set('rotateY', `${angle}deg`) + return this + } + + rotateZ (angle) { + this.transform.set('rotateZ', `${angle}deg`) + return this + } + + scale (x, y) { + const scaleY = (typeof y !== 'undefined' && y !== null) ? y : x + this.scaleX(x) + this.scaleY(scaleY) + // this.transform.set('scale', [x, scaleY]) + return this + } + + scaleX (scale) { + this.transform.set('scaleX', scale) + return this + } + + scaleY (scale) { + this.transform.set('scaleY', scale) + return this + } + + scaleZ (scale) { // Todo Invariant Violation: Invalid transform scaleZ: {"scaleZ":0} + console.error('React Native 不支持 transform scaleZ') + // this.transform.set('scaleZ', scale) + return this + } + + scale3d (x, y, z) { // Todo Invariant Violation: Invalid transform scaleZ: {"scaleZ":0} + console.error('React Native 不支持 transform scaleZ,故不支持 scale3d') + // this.scaleX(x) + // this.scaleY(y) + // this.scaleZ(z) + return this + } + + skew (x, y) { + // this.transform.set('skew', [x, y]) + this.skewX(x) + this.skewY(y) + return this + } + + skewX (angle) { + this.transform.set('skewX', `${angle}deg`) + return this + } + + skewY (angle) { + this.transform.set('skewY', `${angle}deg`) + return this + } + + translate (x, y) { + [x, y] = this._transformUnit(x, y) + // this.transform.set('translate', [x, y]) + this.translateX(x) + this.translateY(y) + return this + } + + translateX (translate) { + [translate] = this._transformUnit(translate) + this.transform.set('translateX', translate) + return this + } + + translateY (translate) { + [translate] = this._transformUnit(translate) + this.transform.set('translateY', translate) + return this + } + + translateZ (translate) { // Todo Invariant Violation: Invalid transform translateZ: {"translateZ":0} + console.error('React Native 不支持 transform translateZ') + // [translate] = this._transformUnit(translate) + // this.transform.set('translateZ', translate) + return this + } + + translate3d (x, y, z) { // Todo Invariant Violation: Invalid transform translateZ: {"translateZ":0} + console.error('React Native 不支持 transform translateZ,故无法支持 translate3d') + // [x, y, z] = this._transformUnit(x, y, z) + // // this.transform.set('translate3d', [x, y, z]) + // this.translateX(x) + // this.translateY(y) + // this.translateZ(z) + return this + } + + opacity (value) { + this.rules.set('opacity', value) + return this + } + + backgroundColor (value) { + this.rules.set('backgroundColor', value) + return this + } + + width (value) { + [value] = this._transformUnit(value) + this.rules.set('width', value) + return this + } + + height (value) { + [value] = this._transformUnit(value) + this.rules.set('height', value) + return this + } + + top (value) { + [value] = this._transformUnit(value) + this.rules.set('top', value) + return this + } + + right (value) { + [value] = this._transformUnit(value) + this.rules.set('right', value) + return this + } + + bottom (value) { + [value] = this._transformUnit(value) + this.rules.set('bottom', value) + return this + } + + left (value) { + [value] = this._transformUnit(value) + this.rules.set('left', value) + return this + } + + // 关键帧载入 + step (arg = {}) { + const { DEFAULT } = this + let { + duration = DEFAULT.duration, + delay = DEFAULT.delay, + timingFunction = DEFAULT.timingFunction, + transformOrigin = DEFAULT.transformOrigin + } = arg + if (typeof transformOrigin !== 'string') { + console.error('Value of transformOrigin only support string type, please check again') + transformOrigin = DEFAULT.transformOrigin + } + this.steps.push({ + animatedOption: { + duration, + delay, + timingFunction, + transformOrigin: this._formatTransformOrigin(transformOrigin) + }, + rules: this.rules, + transform: this.transform + }) + // 清空 rules 和 transform + this.rules = new Map() + this.transform = new Map() + return this + } + + // 数据 + createAnimationData () { + const steps = this.steps + this.steps = [] + return steps + } + + // 动画数据产出 + export () { + this.id++ + return { + id: this.id, + actions: this.createAnimationData() + } + } +} + +export default Animation diff --git a/packages/api-proxy/src/platform/api/animation/index.android.js b/packages/api-proxy/src/platform/api/animation/index.android.js new file mode 100644 index 0000000000..25aabdbcf9 --- /dev/null +++ b/packages/api-proxy/src/platform/api/animation/index.android.js @@ -0,0 +1 @@ +export * from './index.ios' diff --git a/packages/api-proxy/src/platform/api/animation/index.ios.js b/packages/api-proxy/src/platform/api/animation/index.ios.js new file mode 100644 index 0000000000..d372710f15 --- /dev/null +++ b/packages/api-proxy/src/platform/api/animation/index.ios.js @@ -0,0 +1,5 @@ +import Animation from './animation.react' + +export const createAnimation = (option) => { + return new Animation(option) +} diff --git a/packages/webpack-plugin/lib/platform/style/wx/index.js b/packages/webpack-plugin/lib/platform/style/wx/index.js index b7e4e83390..bf8bf95284 100644 --- a/packages/webpack-plugin/lib/platform/style/wx/index.js +++ b/packages/webpack-plugin/lib/platform/style/wx/index.js @@ -190,12 +190,16 @@ module.exports = function getSpec ({ warn, error }) { flex: ['flexGrow', 'flexShrink', 'flexBasis'], // flex-flow: <'flex-direction'> or flex-flow: <'flex-direction'> and <'flex-wrap'> 'flex-flow': ['flexDirection', 'flexWrap'], - 'border-radius': ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius'] + 'border-radius': ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius'], + 'border-width': ['borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth'], + 'border-color': ['borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor'], + margin: ['marginTop', 'marginRight', 'marginBottom', 'marginLeft'], + padding: ['paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft'] } const formatAbbreviation = ({ prop, value, selector }, { mode }) => { const original = `${prop}:${value}` const props = AbbreviationMap[prop] - const values = parseValues(value) + const values = Array.isArray(value) ? value : parseValues(value) const cssMap = [] let idx = 0 let propsIdx = 0 @@ -255,32 +259,20 @@ module.exports = function getSpec ({ warn, error }) { return cssMap } - // margin padding - const formatMargins = ({ prop, value, selector }) => { - const values = parseValues(value) - // format - let suffix = [] + const formatCompositeVal = ({ prop, value, selector }, { mode }) => { + const values = parseValues(value).splice(0, 4) switch (values.length) { - // case 1: + case 1: + verifyValues({ prop, value, selector }, false) + return { prop, value } case 2: - suffix = ['Vertical', 'Horizontal'] + values.push(...values) break case 3: - suffix = ['Top', 'Horizontal', 'Bottom'] - break - case 4: - suffix = ['Top', 'Right', 'Bottom', 'Left'] + values.push(values[1]) break } - return values.map((value, index) => { - const newProp = `${prop}${suffix[index] || ''}` - // validate - verifyValues({ prop: hump2dash(newProp), value, selector }, false) - return { - prop: newProp, - value: value - } - }) + return formatAbbreviation({ prop, value: values, selector }, { mode }) } // line-height @@ -374,22 +366,6 @@ module.exports = function getSpec ({ warn, error }) { return false } - // border-radius 缩写转换 - const getBorderRadius = ({ prop, value, selector }, { mode }) => { - const values = parseValues(value) - if (values.length === 1) { - verifyValues({ prop, value, selector }, false) - return { prop, value } - } else { - if (values.length === 2) { - values.push(...values) - } else if (values.length === 3) { - values.push(values[1]) - } - return formatAbbreviation({ prop, value: values.join(' ') }, { mode }) - } - } - // transform 转换 const formatTransform = ({ prop, value, selector }, { mode }) => { if (Array.isArray(value)) return { prop, value } @@ -566,15 +542,10 @@ module.exports = function getSpec ({ warn, error }) { ios: checkBackgroundImage, android: checkBackgroundImage }, - { - test: 'border-radius', - ios: getBorderRadius, - android: getBorderRadius - }, { // margin padding 内外边距的处理 - test: /^(margin|padding)$/, - ios: formatMargins, - android: formatMargins + test: /^(margin|padding|border-radius|border-width|border-color)$/, + ios: formatCompositeVal, + android: formatCompositeVal }, { // line-height 换算 test: 'line-height', diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx index 44578c85eb..6ce4774000 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx @@ -7,6 +7,9 @@ import { View, TextStyle, NativeSyntheticEvent, ViewProps, ImageStyle, ImageResizeMode, StyleSheet, Image, LayoutChangeEvent, Text } from 'react-native' import { useRef, useState, useEffect, forwardRef, ReactNode, JSX, Children, cloneElement } from 'react' import useInnerProps from './getInnerListeners' +import Animated from 'react-native-reanimated' +import useAnimationHooks from './useAnimationHooks' +import type { AnimationProp } from './useAnimationHooks' import { ExtendedViewStyle } from './types/common' import useNodesRef, { HandlerRef } from './useNodesRef' import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout } from './utils' @@ -14,6 +17,7 @@ import LinearGradient from 'react-native-linear-gradient' export interface _ViewProps extends ViewProps { style?: ExtendedViewStyle + animation?: AnimationProp children?: ReactNode | ReactNode[] 'hover-style'?: ExtendedViewStyle 'hover-start-time'?: number @@ -24,6 +28,7 @@ export interface _ViewProps extends ViewProps { 'parent-font-size'?: number 'parent-width'?: number 'parent-height'?: number + 'enable-animation'?: boolean bindtouchstart?: (event: NativeSyntheticEvent | unknown) => void bindtouchmove?: (event: NativeSyntheticEvent | unknown) => void bindtouchend?: (event: NativeSyntheticEvent | unknown) => void @@ -650,9 +655,11 @@ const _View = forwardRef, _ViewProps>((viewProps, r 'enable-var': enableVar, 'external-var-context': externalVarContext, 'enable-background': enableBackground, + 'enable-animation': enableAnimation, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, - 'parent-height': parentHeight + 'parent-height': parentHeight, + animation } = props const [isHover, setIsHover] = useState(false) @@ -747,9 +754,10 @@ const _View = forwardRef, _ViewProps>((viewProps, r layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef }) + const viewStyle = Object.assign({}, innerStyle, layoutStyle) const innerProps = useInnerProps(props, { ref: nodeRef, - style: { ...innerStyle, ...layoutStyle }, + style: viewStyle, ...layoutProps, ...(hoverStyle && { bindtouchstart: onTouchStart, @@ -764,25 +772,37 @@ const _View = forwardRef, _ViewProps>((viewProps, r layoutRef }) - return ( - - { - wrapWithChildren( - props, - { - hasVarDec, - enableBackground: enableBackgroundRef.current, - textStyle, - backgroundStyle, - varContext: varContextRef.current, - textProps - } - ) - } - - ) + {childNode} + ) + : ( + {childNode} + ) }) _View.displayName = 'mpx-view' 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 fae56a20ab..a3161e0348 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 @@ -47,7 +47,7 @@ interface FormRef { } const _WebView = forwardRef, WebViewProps>((props, ref): JSX.Element => { - const { src, bindmessage = noop, bindload = noop, binderror = noop } = props + const { src = '', bindmessage = noop, bindload = noop, binderror = noop } = props if (props.style) { warn('The web-view component does not support the style prop.') } diff --git a/packages/webpack-plugin/lib/runtime/components/react/types/common.ts b/packages/webpack-plugin/lib/runtime/components/react/types/common.ts index ccadea6c43..6ba1874a45 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/types/common.ts +++ b/packages/webpack-plugin/lib/runtime/components/react/types/common.ts @@ -9,4 +9,5 @@ export type ExtendedViewStyle = ViewStyle & { borderRadius?: string | number backgroundPosition?: backgroundPositionList [key: string]: any + transform?: {[key: string]: number | string}[] } diff --git a/packages/webpack-plugin/lib/runtime/components/react/useAnimationHooks.ts b/packages/webpack-plugin/lib/runtime/components/react/useAnimationHooks.ts new file mode 100644 index 0000000000..2b08317e6e --- /dev/null +++ b/packages/webpack-plugin/lib/runtime/components/react/useAnimationHooks.ts @@ -0,0 +1,248 @@ +import { useEffect, useMemo, useRef } from 'react' +import { TransformsStyle } from 'react-native' +import { + Easing, + useSharedValue, + withTiming, + useAnimatedStyle, + withSequence, + withDelay, + makeMutable, + cancelAnimation, + SharedValue, + WithTimingConfig, + AnimationCallback +} from 'react-native-reanimated' +import { ExtendedViewStyle } from './types/common' +import type { _ViewProps } from './mpx-view' + +// type TransformKey = 'translateX' | 'translateY' | 'rotate' | 'rotateX' | 'rotateY' | 'rotateZ' | 'scaleX' | 'scaleY' | 'skewX' | 'skewY' +// type NormalKey = 'opacity' | 'backgroundColor' | 'width' | 'height' | 'top' | 'right' | 'bottom' | 'left' | 'transformOrigin' +// type RuleKey = TransformKey | NormalKey +type AnimatedOption = { + duration: number + delay: number + useNativeDriver: boolean + timingFunction: 'linear' | 'ease' | 'ease-in' | 'ease-in-out'| 'ease-out' + transformOrigin: string +} +type ExtendWithTimingConfig = WithTimingConfig & { + delay: number +} +export type AnimationStepItem = { + animatedOption: AnimatedOption + rules: Map + transform: Map +} +export type AnimationProp = { + id: number, + actions: AnimationStepItem[] +} + +// 微信 timingFunction 和 RN Easing 对应关系 +const EasingKey = { + linear: Easing.linear, + ease: Easing.ease, + 'ease-in': Easing.in(Easing.ease), + 'ease-in-out': Easing.inOut(Easing.ease), + 'ease-out': Easing.out(Easing.ease) + // 'step-start': '', + // 'step-end': '' +} +const TransformInitial: ExtendedViewStyle = { + // matrix: 0, + // matrix3d: 0, + rotate: '0deg', + rotateX: '0deg', + rotateY: '0deg', + rotateZ: '0deg', + // rotate3d:[0,0,0] + scale: 1, + // scale3d: [1, 1, 1], + scaleX: 1, + scaleY: 1, + // scaleZ: 1, + skew: 0, + skewX: '0deg', + skewY: '0deg', + translate: 0, + // translate3d: 0, + translateX: 0, + translateY: 0 + // translateZ: 0, +} +// 动画默认初始值 +const InitialValue: ExtendedViewStyle = Object.assign({ + opacity: 1, + backgroundColor: 'transparent', + width: 0, + height: 0, + top: 0, + right: 0, + bottom: 0, + left: 0, + transformOrigin: ['50%', '50%', 0] +}, TransformInitial) +const TransformOrigin = 'transformOrigin' +// deg 角度 +// const isDeg = (key: RuleKey) => ['rotateX', 'rotateY', 'rotateZ', 'rotate', 'skewX', 'skewY'].includes(key) +// 背景色 +// const isBg = (key: RuleKey) => key === 'backgroundColor' +// transform +const isTransform = (key: string) => Object.keys(TransformInitial).includes(key) + +export default function useAnimationHooks (props: _ViewProps) { + const { style: originalStyle = {}, animation } = props + // id 标识 + const id = animation?.id || -1 + // 有动画样式的 style key + const animatedStyleKeys = useSharedValue([] as (string|string[])[]) + const animatedKeys = useRef({} as {[propName: keyof ExtendedViewStyle]: Boolean}) + // ** 全量 style prop sharedValue + // 不能做增量的原因: + // 1 尝试用 useRef,但 useAnimatedStyle 访问后的 ref 不能在增加新的值,被冻结 + // 2 尝试用 useSharedValue,因为实际触发的 style prop 需要是 sharedValue 才能驱动动画,若外层 shareValMap 也是 sharedValue,动画无法驱动。 + const shareValMap = useMemo(() => { + return Object.keys(InitialValue).reduce((valMap, key) => { + const defaultVal = getInitialVal(key, isTransform(key)) + valMap[key] = makeMutable(defaultVal) + return valMap + }, {} as { [propName: keyof ExtendedViewStyle]: SharedValue }) + }, []) + // ** 获取动画样式prop & 驱动动画 + useEffect(() => { + if (id === -1) return + // 更新动画样式 key map + animatedKeys.current = getAnimatedStyleKeys() + const keys = Object.keys(animatedKeys.current) + animatedStyleKeys.value = formatAnimatedKeys([TransformOrigin, ...keys]) + // 驱动动画 + createAnimation(keys) + }, [id]) + // ** 清空动画 + useEffect(() => { + return () => { + Object.values(shareValMap).forEach((value) => { + cancelAnimation(value) + }) + } + }, []) + // 根据 animation action 创建&驱动动画 key => wi + function createAnimation (animatedKeys: string[] = []) { + const actions = animation?.actions || [] + const sequence = {} as { [propName: keyof ExtendedViewStyle]: (string|number)[] } + const lastValueMap = {} as { [propName: keyof ExtendedViewStyle]: string|number } + actions.forEach(({ animatedOption, rules, transform }, index) => { + const { delay, duration, timingFunction, transformOrigin } = animatedOption + const easing = EasingKey[timingFunction] || Easing.inOut(Easing.quad) + let needSetCallback = true + const setTransformOrigin: AnimationCallback = (finished: boolean) => { + 'worklet' + // 动画结束后设置下一次transformOrigin + if (finished) { + if (index < actions.length - 1) { + const transformOrigin = actions[index + 1].animatedOption?.transformOrigin + transformOrigin && (shareValMap[TransformOrigin].value = transformOrigin) + } + } + } + if (index === 0) { + // 设置当次中心 + shareValMap[TransformOrigin].value = transformOrigin + } + // 添加每个key的多次step动画 + animatedKeys.forEach(key => { + let toVal = (rules.get(key) || transform.get(key)) as number|string + // key不存在,第一轮取shareValMap[key]value,非第一轮取上一轮的 + if (!toVal) { + toVal = index > 0 ? lastValueMap[key] : shareValMap[key].value + } + const animation = getAnimation({ key, value: toVal }, { delay, duration, easing }, needSetCallback ? setTransformOrigin : undefined) + needSetCallback = false + if (!sequence[key]) { + sequence[key] = [animation] + } else { + sequence[key].push(animation) + } + // 更新一下 lastValueMap + lastValueMap[key] = toVal + }) + // 赋值驱动动画 + animatedKeys.forEach((key) => { + const animations = sequence[key] + shareValMap[key].value = withSequence(...animations) + }) + }) + } + // 创建单个animation + function getAnimation ({ key, value }: { key: string, value: string|number }, { delay, duration, easing }: ExtendWithTimingConfig, callback?: AnimationCallback) { + const animation = typeof callback === 'function' + ? withTiming(value, { duration, easing }, callback) + : withTiming(value, { duration, easing }) + return delay ? withDelay(delay, animation) : animation + } + // 获取初始值(prop style or 默认值) + function getInitialVal (key: keyof ExtendedViewStyle, isTransform = false) { + if (isTransform && originalStyle.transform?.length) { + let initialVal = InitialValue[key] + // 仅支持 { transform: [{rotateX: '45deg'}, {rotateZ: '0.785398rad'}] } 格式的初始样式 + originalStyle.transform.forEach(item => { + if (item[key] !== undefined) initialVal = item[key] + }) + return initialVal + } + return originalStyle[key] === undefined ? InitialValue[key] : originalStyle[key] + } + // 循环 animation actions 获取所有有动画的 style prop name + function getAnimatedStyleKeys () { + return (animation?.actions || []).reduce((keyMap, action) => { + const { rules, transform } = action + const ruleArr = [...rules.keys(), ...transform.keys()] + ruleArr.forEach(key => { + if (!keyMap[key]) keyMap[key] = true + }) + return keyMap + }, animatedKeys.current) + } + // animated key transform 格式化 + function formatAnimatedKeys (keys: string[] = []) { + const animatedKeys = [] as (string|string[])[] + const transforms = [] as string[] + keys.forEach(key => { + if (isTransform(key)) { + transforms.push(key) + } else { + animatedKeys.push(key) + } + }) + if (transforms.length) animatedKeys.push(transforms) + return animatedKeys + } + // transform 数组转对象 + function getTransformObj () { + 'worklet' + const transforms = originalStyle.transform || [] + return transforms.reduce((transformObj, item) => { + return Object.assign(transformObj, item) + }, {} as { [propName: string]: string | number }) + } + // ** 生成动画样式 + return useAnimatedStyle(() => { + // console.info(`useAnimatedStyle styles=`, originalStyle) + return animatedStyleKeys.value.reduce((styles, key) => { + // console.info('getAnimationStyles', key, shareValMap[key].value) + if (Array.isArray(key)) { + const transformStyle = getTransformObj() + key.forEach((transformKey) => { + transformStyle[transformKey] = shareValMap[transformKey].value + }) + styles.transform = Object.entries(transformStyle).map(([key, value]) => { + return { [key]: value } + }) as Extract<'transform', TransformsStyle> + } else { + styles[key] = shareValMap[key].value + } + return styles + }, Object.assign({}, originalStyle) as ExtendedViewStyle) + }) +} diff --git a/packages/webpack-plugin/package.json b/packages/webpack-plugin/package.json index 911be86874..9781cb26e4 100644 --- a/packages/webpack-plugin/package.json +++ b/packages/webpack-plugin/package.json @@ -88,6 +88,7 @@ "@types/react": "^18.2.79", "react-native": "^0.74.5", "react-native-gesture-handler": "^2.18.1", + "react-native-reanimated": "^3.15.2", "react-native-linear-gradient": "^2.8.3", "react-native-safe-area-context": "^4.12.0", "react-native-webview": "^13.12.2",