@mpxjs/webpack-plugin 2.9.64 → 2.9.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/config.js +38 -10
- package/lib/index.js +5 -1
- package/lib/platform/style/wx/index.js +66 -60
- package/lib/platform/template/wx/index.js +12 -8
- package/lib/react/processTemplate.js +4 -2
- package/lib/react/style-helper.js +2 -5
- package/lib/runtime/components/react/context.ts +8 -0
- package/lib/runtime/components/react/dist/context.js +1 -0
- package/lib/runtime/components/react/dist/mpx-button.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +3 -2
- package/lib/runtime/components/react/dist/mpx-form.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-icon.jsx +3 -2
- package/lib/runtime/components/react/dist/mpx-image/index.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-input.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-label.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +3 -2
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-picker/date.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-picker/region.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +4 -2
- package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +3 -2
- package/lib/runtime/components/react/dist/mpx-picker-view.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-radio.jsx +3 -2
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +13 -3
- package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +78 -77
- package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +3 -2
- package/lib/runtime/components/react/dist/mpx-switch.jsx +3 -2
- package/lib/runtime/components/react/dist/mpx-text.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-view.jsx +45 -15
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +4 -3
- package/lib/runtime/components/react/dist/useAnimationHooks.js +215 -0
- package/lib/runtime/components/react/dist/useNodesRef.js +1 -5
- package/lib/runtime/components/react/dist/utils.jsx +50 -37
- package/lib/runtime/components/react/mpx-button.tsx +3 -1
- package/lib/runtime/components/react/mpx-checkbox-group.tsx +3 -1
- package/lib/runtime/components/react/mpx-checkbox.tsx +4 -1
- package/lib/runtime/components/react/mpx-form.tsx +2 -1
- package/lib/runtime/components/react/mpx-icon.tsx +3 -2
- package/lib/runtime/components/react/mpx-image/index.tsx +2 -1
- package/lib/runtime/components/react/mpx-input.tsx +2 -1
- package/lib/runtime/components/react/mpx-label.tsx +2 -1
- package/lib/runtime/components/react/mpx-movable-area.tsx +3 -2
- package/lib/runtime/components/react/mpx-movable-view.tsx +2 -1
- package/lib/runtime/components/react/mpx-picker/date.tsx +2 -1
- package/lib/runtime/components/react/mpx-picker/index.tsx +2 -1
- package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +2 -1
- package/lib/runtime/components/react/mpx-picker/region.tsx +2 -1
- package/lib/runtime/components/react/mpx-picker/selector.tsx +2 -1
- package/lib/runtime/components/react/mpx-picker/time.tsx +4 -2
- package/lib/runtime/components/react/mpx-picker-view-column.tsx +3 -2
- package/lib/runtime/components/react/mpx-picker-view.tsx +2 -1
- package/lib/runtime/components/react/mpx-radio-group.tsx +2 -1
- package/lib/runtime/components/react/mpx-radio.tsx +3 -2
- package/lib/runtime/components/react/mpx-scroll-view.tsx +14 -2
- package/lib/runtime/components/react/mpx-swiper/carouse.tsx +77 -75
- package/lib/runtime/components/react/mpx-swiper/index.tsx +4 -1
- package/lib/runtime/components/react/mpx-swiper-item.tsx +2 -1
- package/lib/runtime/components/react/mpx-switch.tsx +2 -1
- package/lib/runtime/components/react/mpx-text.tsx +2 -1
- package/lib/runtime/components/react/mpx-view.tsx +55 -23
- package/lib/runtime/components/react/mpx-web-view.tsx +4 -3
- package/lib/runtime/components/react/types/common.ts +8 -2
- package/lib/runtime/components/react/types/global.d.ts +11 -1
- package/lib/runtime/components/react/useAnimationHooks.ts +248 -0
- package/lib/runtime/components/react/useNodesRef.ts +1 -6
- package/lib/runtime/components/react/utils.tsx +71 -50
- package/lib/runtime/components/web/mpx-scroll-view.vue +25 -5
- package/lib/style-compiler/index.js +5 -4
- package/lib/template-compiler/compiler.js +127 -158
- package/lib/utils/const.js +2 -1
- package/lib/web/processStyles.js +6 -2
- package/lib/web/processTemplate.js +2 -3
- package/lib/wxml/loader.js +1 -1
- package/package.json +6 -4
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
import { View, TextStyle, NativeSyntheticEvent, ViewProps, ImageStyle, ImageResizeMode, StyleSheet, Image, LayoutChangeEvent, Text } from 'react-native'
|
|
8
8
|
import { useRef, useState, useEffect, forwardRef, ReactNode, JSX, Children, cloneElement } from 'react'
|
|
9
9
|
import useInnerProps from './getInnerListeners'
|
|
10
|
+
import Animated from 'react-native-reanimated'
|
|
11
|
+
import useAnimationHooks from './useAnimationHooks'
|
|
12
|
+
import type { AnimationProp } from './useAnimationHooks'
|
|
10
13
|
import { ExtendedViewStyle } from './types/common'
|
|
11
14
|
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
12
15
|
import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout } from './utils'
|
|
@@ -14,6 +17,7 @@ import LinearGradient from 'react-native-linear-gradient'
|
|
|
14
17
|
|
|
15
18
|
export interface _ViewProps extends ViewProps {
|
|
16
19
|
style?: ExtendedViewStyle
|
|
20
|
+
animation?: AnimationProp
|
|
17
21
|
children?: ReactNode | ReactNode[]
|
|
18
22
|
'hover-style'?: ExtendedViewStyle
|
|
19
23
|
'hover-start-time'?: number
|
|
@@ -24,6 +28,7 @@ export interface _ViewProps extends ViewProps {
|
|
|
24
28
|
'parent-font-size'?: number
|
|
25
29
|
'parent-width'?: number
|
|
26
30
|
'parent-height'?: number
|
|
31
|
+
'enable-animation'?: boolean
|
|
27
32
|
bindtouchstart?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
|
|
28
33
|
bindtouchmove?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
|
|
29
34
|
bindtouchend?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
|
|
@@ -114,6 +119,17 @@ const applyHandlers = (handlers: Handler[], args: any[]) => {
|
|
|
114
119
|
}
|
|
115
120
|
}
|
|
116
121
|
|
|
122
|
+
const normalizeStyle = (style: ExtendedViewStyle = {}) => {
|
|
123
|
+
['backgroundSize', 'backgroundPosition'].forEach(name => {
|
|
124
|
+
if (style[name] && typeof style[name] === 'string') {
|
|
125
|
+
if (style[name].trim()) {
|
|
126
|
+
style[name] = style[name].split(' ')
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
return style
|
|
131
|
+
}
|
|
132
|
+
|
|
117
133
|
const isPercent = (val: string | number | undefined): val is string => typeof val === 'string' && PERCENT_REGEX.test(val)
|
|
118
134
|
|
|
119
135
|
const isBackgroundSizeKeyword = (val: string | number): boolean => typeof val === 'string' && /^cover|contain$/.test(val)
|
|
@@ -501,7 +517,7 @@ function normalizeBackgroundSize (backgroundSize: Exclude<ExtendedViewStyle['bac
|
|
|
501
517
|
}
|
|
502
518
|
|
|
503
519
|
function preParseImage (imageStyle?: ExtendedViewStyle) {
|
|
504
|
-
const { backgroundImage = '', backgroundSize = ['auto'], backgroundPosition = [0, 0] } = imageStyle || {}
|
|
520
|
+
const { backgroundImage = '', backgroundSize = ['auto'], backgroundPosition = [0, 0] } = normalizeStyle(imageStyle) || {}
|
|
505
521
|
const { type, src, linearInfo } = parseBgImage(backgroundImage)
|
|
506
522
|
|
|
507
523
|
return {
|
|
@@ -589,8 +605,8 @@ function wrapImage (imageStyle?: ExtendedViewStyle) {
|
|
|
589
605
|
}
|
|
590
606
|
setImageSizeWidth(sizeInfo.current.width)
|
|
591
607
|
setImageSizeHeight(sizeInfo.current.height)
|
|
592
|
-
setShow(true)
|
|
593
608
|
}
|
|
609
|
+
setShow(true)
|
|
594
610
|
} else if (sizeInfo.current) {
|
|
595
611
|
setLayoutInfoWidth(width)
|
|
596
612
|
setLayoutInfoHeight(height)
|
|
@@ -600,7 +616,7 @@ function wrapImage (imageStyle?: ExtendedViewStyle) {
|
|
|
600
616
|
}
|
|
601
617
|
}
|
|
602
618
|
|
|
603
|
-
return <View key='backgroundImage' {...needLayout ? { onLayout } : null} style={{ ...StyleSheet.absoluteFillObject,
|
|
619
|
+
return <View key='backgroundImage' {...needLayout ? { onLayout } : null} style={{ ...StyleSheet.absoluteFillObject, overflow: 'hidden' }}>
|
|
604
620
|
{show && type === 'linear' && <LinearGradient useAngle={true} {...imageStyleToProps(preImageInfo, sizeInfo.current as Size, layoutInfo.current as Size)} /> }
|
|
605
621
|
{show && type === 'image' && <Image {...imageStyleToProps(preImageInfo, sizeInfo.current as Size, layoutInfo.current as Size)} />}
|
|
606
622
|
</View>
|
|
@@ -639,9 +655,11 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
|
|
|
639
655
|
'enable-var': enableVar,
|
|
640
656
|
'external-var-context': externalVarContext,
|
|
641
657
|
'enable-background': enableBackground,
|
|
658
|
+
'enable-animation': enableAnimation,
|
|
642
659
|
'parent-font-size': parentFontSize,
|
|
643
660
|
'parent-width': parentWidth,
|
|
644
|
-
'parent-height': parentHeight
|
|
661
|
+
'parent-height': parentHeight,
|
|
662
|
+
animation
|
|
645
663
|
} = props
|
|
646
664
|
|
|
647
665
|
const [isHover, setIsHover] = useState(false)
|
|
@@ -686,7 +704,8 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
|
|
|
686
704
|
throw new Error('[Mpx runtime error]: background use should be stable in the component lifecycle, or you can set [enable-background] with true.')
|
|
687
705
|
}
|
|
688
706
|
|
|
689
|
-
const
|
|
707
|
+
const nodeRef = useRef(null)
|
|
708
|
+
useNodesRef<View, _ViewProps>(props, ref, nodeRef, {
|
|
690
709
|
defaultStyle
|
|
691
710
|
})
|
|
692
711
|
|
|
@@ -735,9 +754,10 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
|
|
|
735
754
|
layoutProps
|
|
736
755
|
} = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef })
|
|
737
756
|
|
|
757
|
+
const viewStyle = Object.assign({}, innerStyle, layoutStyle)
|
|
738
758
|
const innerProps = useInnerProps(props, {
|
|
739
759
|
ref: nodeRef,
|
|
740
|
-
style:
|
|
760
|
+
style: viewStyle,
|
|
741
761
|
...layoutProps,
|
|
742
762
|
...(hoverStyle && {
|
|
743
763
|
bindtouchstart: onTouchStart,
|
|
@@ -752,25 +772,37 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
|
|
|
752
772
|
layoutRef
|
|
753
773
|
})
|
|
754
774
|
|
|
755
|
-
|
|
756
|
-
|
|
775
|
+
enableAnimation = enableAnimation || !!animation
|
|
776
|
+
const enableAnimationRef = useRef(enableAnimation)
|
|
777
|
+
if (enableAnimationRef.current !== enableAnimation) {
|
|
778
|
+
throw new Error('[Mpx runtime error]: animation use should be stable in the component lifecycle, or you can set [enable-animation] with true.')
|
|
779
|
+
}
|
|
780
|
+
const finalStyle = enableAnimation
|
|
781
|
+
? useAnimationHooks({
|
|
782
|
+
animation,
|
|
783
|
+
style: viewStyle
|
|
784
|
+
})
|
|
785
|
+
: viewStyle
|
|
786
|
+
const childNode = wrapWithChildren(props, {
|
|
787
|
+
hasVarDec,
|
|
788
|
+
enableBackground: enableBackgroundRef.current,
|
|
789
|
+
textStyle,
|
|
790
|
+
backgroundStyle,
|
|
791
|
+
varContext: varContextRef.current,
|
|
792
|
+
textProps
|
|
793
|
+
})
|
|
794
|
+
return animation?.actions?.length
|
|
795
|
+
? (<Animated.View
|
|
757
796
|
{...innerProps}
|
|
797
|
+
style={finalStyle}
|
|
758
798
|
>
|
|
759
|
-
{
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
backgroundStyle,
|
|
767
|
-
varContext: varContextRef.current,
|
|
768
|
-
textProps
|
|
769
|
-
}
|
|
770
|
-
)
|
|
771
|
-
}
|
|
772
|
-
</View>
|
|
773
|
-
)
|
|
799
|
+
{childNode}
|
|
800
|
+
</Animated.View>)
|
|
801
|
+
: (<View
|
|
802
|
+
{...innerProps}
|
|
803
|
+
>
|
|
804
|
+
{childNode}
|
|
805
|
+
</View>)
|
|
774
806
|
})
|
|
775
807
|
|
|
776
808
|
_View.displayName = 'mpx-view'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { forwardRef, JSX, useEffect } from 'react'
|
|
1
|
+
import { forwardRef, JSX, useEffect, useRef } from 'react'
|
|
2
2
|
import { noop, warn } from '@mpxjs/utils'
|
|
3
3
|
import { Portal } from '@ant-design/react-native'
|
|
4
4
|
import { getCustomEvent } from './getInnerListeners'
|
|
@@ -47,7 +47,7 @@ interface FormRef {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((props, ref): JSX.Element => {
|
|
50
|
-
const { src, bindmessage = noop, bindload = noop, binderror = noop } = props
|
|
50
|
+
const { src = '', bindmessage = noop, bindload = noop, binderror = noop } = props
|
|
51
51
|
if (props.style) {
|
|
52
52
|
warn('The web-view component does not support the style prop.')
|
|
53
53
|
}
|
|
@@ -59,7 +59,8 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
59
59
|
bottom: 0 as number
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
const
|
|
62
|
+
const webViewRef = useRef<WebView>(null)
|
|
63
|
+
useNodesRef<WebView, WebViewProps>(props, ref, webViewRef, {
|
|
63
64
|
defaultStyle: defaultWebViewStyle
|
|
64
65
|
})
|
|
65
66
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { ViewStyle
|
|
1
|
+
import { ViewStyle } from 'react-native'
|
|
2
|
+
import { FunctionComponent } from 'react'
|
|
2
3
|
|
|
3
4
|
type NumberVal = number | `${number}%`
|
|
4
|
-
type backgroundPositionList = [
|
|
5
|
+
type backgroundPositionList = ['left' | 'right', NumberVal, 'top' | 'bottom', NumberVal] | []
|
|
5
6
|
|
|
6
7
|
export type ExtendedViewStyle = ViewStyle & {
|
|
7
8
|
backgroundImage?: string
|
|
@@ -9,4 +10,9 @@ export type ExtendedViewStyle = ViewStyle & {
|
|
|
9
10
|
borderRadius?: string | number
|
|
10
11
|
backgroundPosition?: backgroundPositionList
|
|
11
12
|
[key: string]: any
|
|
13
|
+
transform?: {[key: string]: number | string}[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type ExtendedFunctionComponent = FunctionComponent & {
|
|
17
|
+
isCustomText?: boolean
|
|
12
18
|
}
|
|
@@ -26,6 +26,16 @@ declare module '@mpxjs/utils' {
|
|
|
26
26
|
export function isObject (value): value is Object
|
|
27
27
|
export function error (msg: string, location?: string, e?: any): void
|
|
28
28
|
export function warn (msg: string, location?: string, e?: any): void
|
|
29
|
+
export function getFocusedNavigation (): {
|
|
30
|
+
insets: {
|
|
31
|
+
top: number
|
|
32
|
+
bottom: number
|
|
33
|
+
left: number
|
|
34
|
+
right: number
|
|
35
|
+
}
|
|
36
|
+
} | undefined
|
|
29
37
|
}
|
|
30
38
|
|
|
31
|
-
declare let global:
|
|
39
|
+
declare let global: {
|
|
40
|
+
__formatValue (value: string): string | number
|
|
41
|
+
} & Record<string, any>
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef } from 'react'
|
|
2
|
+
import { TransformsStyle } from 'react-native'
|
|
3
|
+
import {
|
|
4
|
+
Easing,
|
|
5
|
+
useSharedValue,
|
|
6
|
+
withTiming,
|
|
7
|
+
useAnimatedStyle,
|
|
8
|
+
withSequence,
|
|
9
|
+
withDelay,
|
|
10
|
+
makeMutable,
|
|
11
|
+
cancelAnimation,
|
|
12
|
+
SharedValue,
|
|
13
|
+
WithTimingConfig,
|
|
14
|
+
AnimationCallback
|
|
15
|
+
} from 'react-native-reanimated'
|
|
16
|
+
import { ExtendedViewStyle } from './types/common'
|
|
17
|
+
import type { _ViewProps } from './mpx-view'
|
|
18
|
+
|
|
19
|
+
// type TransformKey = 'translateX' | 'translateY' | 'rotate' | 'rotateX' | 'rotateY' | 'rotateZ' | 'scaleX' | 'scaleY' | 'skewX' | 'skewY'
|
|
20
|
+
// type NormalKey = 'opacity' | 'backgroundColor' | 'width' | 'height' | 'top' | 'right' | 'bottom' | 'left' | 'transformOrigin'
|
|
21
|
+
// type RuleKey = TransformKey | NormalKey
|
|
22
|
+
type AnimatedOption = {
|
|
23
|
+
duration: number
|
|
24
|
+
delay: number
|
|
25
|
+
useNativeDriver: boolean
|
|
26
|
+
timingFunction: 'linear' | 'ease' | 'ease-in' | 'ease-in-out'| 'ease-out'
|
|
27
|
+
transformOrigin: string
|
|
28
|
+
}
|
|
29
|
+
type ExtendWithTimingConfig = WithTimingConfig & {
|
|
30
|
+
delay: number
|
|
31
|
+
}
|
|
32
|
+
export type AnimationStepItem = {
|
|
33
|
+
animatedOption: AnimatedOption
|
|
34
|
+
rules: Map<string, number | string>
|
|
35
|
+
transform: Map<string, number>
|
|
36
|
+
}
|
|
37
|
+
export type AnimationProp = {
|
|
38
|
+
id: number,
|
|
39
|
+
actions: AnimationStepItem[]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 微信 timingFunction 和 RN Easing 对应关系
|
|
43
|
+
const EasingKey = {
|
|
44
|
+
linear: Easing.linear,
|
|
45
|
+
ease: Easing.ease,
|
|
46
|
+
'ease-in': Easing.in(Easing.ease),
|
|
47
|
+
'ease-in-out': Easing.inOut(Easing.ease),
|
|
48
|
+
'ease-out': Easing.out(Easing.ease)
|
|
49
|
+
// 'step-start': '',
|
|
50
|
+
// 'step-end': ''
|
|
51
|
+
}
|
|
52
|
+
const TransformInitial: ExtendedViewStyle = {
|
|
53
|
+
// matrix: 0,
|
|
54
|
+
// matrix3d: 0,
|
|
55
|
+
rotate: '0deg',
|
|
56
|
+
rotateX: '0deg',
|
|
57
|
+
rotateY: '0deg',
|
|
58
|
+
rotateZ: '0deg',
|
|
59
|
+
// rotate3d:[0,0,0]
|
|
60
|
+
scale: 1,
|
|
61
|
+
// scale3d: [1, 1, 1],
|
|
62
|
+
scaleX: 1,
|
|
63
|
+
scaleY: 1,
|
|
64
|
+
// scaleZ: 1,
|
|
65
|
+
skew: 0,
|
|
66
|
+
skewX: '0deg',
|
|
67
|
+
skewY: '0deg',
|
|
68
|
+
translate: 0,
|
|
69
|
+
// translate3d: 0,
|
|
70
|
+
translateX: 0,
|
|
71
|
+
translateY: 0
|
|
72
|
+
// translateZ: 0,
|
|
73
|
+
}
|
|
74
|
+
// 动画默认初始值
|
|
75
|
+
const InitialValue: ExtendedViewStyle = Object.assign({
|
|
76
|
+
opacity: 1,
|
|
77
|
+
backgroundColor: 'transparent',
|
|
78
|
+
width: 0,
|
|
79
|
+
height: 0,
|
|
80
|
+
top: 0,
|
|
81
|
+
right: 0,
|
|
82
|
+
bottom: 0,
|
|
83
|
+
left: 0,
|
|
84
|
+
transformOrigin: ['50%', '50%', 0]
|
|
85
|
+
}, TransformInitial)
|
|
86
|
+
const TransformOrigin = 'transformOrigin'
|
|
87
|
+
// deg 角度
|
|
88
|
+
// const isDeg = (key: RuleKey) => ['rotateX', 'rotateY', 'rotateZ', 'rotate', 'skewX', 'skewY'].includes(key)
|
|
89
|
+
// 背景色
|
|
90
|
+
// const isBg = (key: RuleKey) => key === 'backgroundColor'
|
|
91
|
+
// transform
|
|
92
|
+
const isTransform = (key: string) => Object.keys(TransformInitial).includes(key)
|
|
93
|
+
|
|
94
|
+
export default function useAnimationHooks<T, P> (props: _ViewProps) {
|
|
95
|
+
const { style: originalStyle = {}, animation } = props
|
|
96
|
+
// id 标识
|
|
97
|
+
const id = animation?.id || -1
|
|
98
|
+
// 有动画样式的 style key
|
|
99
|
+
const animatedStyleKeys = useSharedValue([] as (string|string[])[])
|
|
100
|
+
const animatedKeys = useRef({} as {[propName: keyof ExtendedViewStyle]: Boolean})
|
|
101
|
+
// ** 全量 style prop sharedValue
|
|
102
|
+
// 不能做增量的原因:
|
|
103
|
+
// 1 尝试用 useRef,但 useAnimatedStyle 访问后的 ref 不能在增加新的值,被冻结
|
|
104
|
+
// 2 尝试用 useSharedValue,因为实际触发的 style prop 需要是 sharedValue 才能驱动动画,若外层 shareValMap 也是 sharedValue,动画无法驱动。
|
|
105
|
+
const shareValMap = useMemo(() => {
|
|
106
|
+
return Object.keys(InitialValue).reduce((valMap, key) => {
|
|
107
|
+
const defaultVal = getInitialVal(key, isTransform(key))
|
|
108
|
+
valMap[key] = makeMutable(defaultVal)
|
|
109
|
+
return valMap
|
|
110
|
+
}, {} as { [propName: keyof ExtendedViewStyle]: SharedValue<string|number> })
|
|
111
|
+
}, [])
|
|
112
|
+
// ** 获取动画样式prop & 驱动动画
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
if (id === -1) return
|
|
115
|
+
// 更新动画样式 key map
|
|
116
|
+
animatedKeys.current = getAnimatedStyleKeys()
|
|
117
|
+
const keys = Object.keys(animatedKeys.current)
|
|
118
|
+
animatedStyleKeys.value = formatAnimatedKeys([TransformOrigin, ...keys])
|
|
119
|
+
// 驱动动画
|
|
120
|
+
createAnimation(keys)
|
|
121
|
+
}, [id])
|
|
122
|
+
// ** 清空动画
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
return () => {
|
|
125
|
+
Object.values(shareValMap).forEach((value) => {
|
|
126
|
+
cancelAnimation(value)
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
}, [])
|
|
130
|
+
// 根据 animation action 创建&驱动动画 key => wi
|
|
131
|
+
function createAnimation (animatedKeys: string[] = []) {
|
|
132
|
+
const actions = animation?.actions || []
|
|
133
|
+
const sequence = {} as { [propName: keyof ExtendedViewStyle]: (string|number)[] }
|
|
134
|
+
const lastValueMap = {} as { [propName: keyof ExtendedViewStyle]: string|number }
|
|
135
|
+
actions.forEach(({ animatedOption, rules, transform }, index) => {
|
|
136
|
+
const { delay, duration, timingFunction, transformOrigin } = animatedOption
|
|
137
|
+
const easing = EasingKey[timingFunction] || Easing.inOut(Easing.quad)
|
|
138
|
+
let needSetCallback = true
|
|
139
|
+
const setTransformOrigin: AnimationCallback = (finished: boolean) => {
|
|
140
|
+
'worklet'
|
|
141
|
+
// 动画结束后设置下一次transformOrigin
|
|
142
|
+
if (finished) {
|
|
143
|
+
if (index < actions.length - 1) {
|
|
144
|
+
const transformOrigin = actions[index + 1].animatedOption?.transformOrigin
|
|
145
|
+
transformOrigin && (shareValMap[TransformOrigin].value = transformOrigin)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (index === 0) {
|
|
150
|
+
// 设置当次中心
|
|
151
|
+
shareValMap[TransformOrigin].value = transformOrigin
|
|
152
|
+
}
|
|
153
|
+
// 添加每个key的多次step动画
|
|
154
|
+
animatedKeys.forEach(key => {
|
|
155
|
+
let toVal = (rules.get(key) || transform.get(key)) as number|string
|
|
156
|
+
// key不存在,第一轮取shareValMap[key]value,非第一轮取上一轮的
|
|
157
|
+
if (!toVal) {
|
|
158
|
+
toVal = index > 0 ? lastValueMap[key] : shareValMap[key].value
|
|
159
|
+
}
|
|
160
|
+
const animation = getAnimation({ key, value: toVal }, { delay, duration, easing }, needSetCallback ? setTransformOrigin : undefined)
|
|
161
|
+
needSetCallback = false
|
|
162
|
+
if (!sequence[key]) {
|
|
163
|
+
sequence[key] = [animation]
|
|
164
|
+
} else {
|
|
165
|
+
sequence[key].push(animation)
|
|
166
|
+
}
|
|
167
|
+
// 更新一下 lastValueMap
|
|
168
|
+
lastValueMap[key] = toVal
|
|
169
|
+
})
|
|
170
|
+
// 赋值驱动动画
|
|
171
|
+
animatedKeys.forEach((key) => {
|
|
172
|
+
const animations = sequence[key]
|
|
173
|
+
shareValMap[key].value = withSequence(...animations)
|
|
174
|
+
})
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
// 创建单个animation
|
|
178
|
+
function getAnimation ({ key, value }: { key: string, value: string|number }, { delay, duration, easing }: ExtendWithTimingConfig, callback?: AnimationCallback) {
|
|
179
|
+
const animation = typeof callback === 'function'
|
|
180
|
+
? withTiming(value, { duration, easing }, callback)
|
|
181
|
+
: withTiming(value, { duration, easing })
|
|
182
|
+
return delay ? withDelay(delay, animation) : animation
|
|
183
|
+
}
|
|
184
|
+
// 获取初始值(prop style or 默认值)
|
|
185
|
+
function getInitialVal (key: keyof ExtendedViewStyle, isTransform = false) {
|
|
186
|
+
if (isTransform && originalStyle.transform?.length) {
|
|
187
|
+
let initialVal = InitialValue[key]
|
|
188
|
+
// 仅支持 { transform: [{rotateX: '45deg'}, {rotateZ: '0.785398rad'}] } 格式的初始样式
|
|
189
|
+
originalStyle.transform.forEach(item => {
|
|
190
|
+
if (item[key] !== undefined) initialVal = item[key]
|
|
191
|
+
})
|
|
192
|
+
return initialVal
|
|
193
|
+
}
|
|
194
|
+
return originalStyle[key] === undefined ? InitialValue[key] : originalStyle[key]
|
|
195
|
+
}
|
|
196
|
+
// 循环 animation actions 获取所有有动画的 style prop name
|
|
197
|
+
function getAnimatedStyleKeys () {
|
|
198
|
+
return (animation?.actions || []).reduce((keyMap, action) => {
|
|
199
|
+
const { rules, transform } = action
|
|
200
|
+
const ruleArr = [...rules.keys(), ...transform.keys()]
|
|
201
|
+
ruleArr.forEach(key => {
|
|
202
|
+
if (!keyMap[key]) keyMap[key] = true
|
|
203
|
+
})
|
|
204
|
+
return keyMap
|
|
205
|
+
}, animatedKeys.current)
|
|
206
|
+
}
|
|
207
|
+
// animated key transform 格式化
|
|
208
|
+
function formatAnimatedKeys (keys: string[] = []) {
|
|
209
|
+
const animatedKeys = [] as (string|string[])[]
|
|
210
|
+
const transforms = [] as string[]
|
|
211
|
+
keys.forEach(key => {
|
|
212
|
+
if (isTransform(key)) {
|
|
213
|
+
transforms.push(key)
|
|
214
|
+
} else {
|
|
215
|
+
animatedKeys.push(key)
|
|
216
|
+
}
|
|
217
|
+
})
|
|
218
|
+
if (transforms.length) animatedKeys.push(transforms)
|
|
219
|
+
return animatedKeys
|
|
220
|
+
}
|
|
221
|
+
// transform 数组转对象
|
|
222
|
+
function getTransformObj () {
|
|
223
|
+
'worklet'
|
|
224
|
+
const transforms = originalStyle.transform || []
|
|
225
|
+
return transforms.reduce((transformObj, item) => {
|
|
226
|
+
return Object.assign(transformObj, item)
|
|
227
|
+
}, {} as { [propName: string]: string | number })
|
|
228
|
+
}
|
|
229
|
+
// ** 生成动画样式
|
|
230
|
+
return useAnimatedStyle(() => {
|
|
231
|
+
// console.info(`useAnimatedStyle styles=`, originalStyle)
|
|
232
|
+
return animatedStyleKeys.value.reduce((styles, key) => {
|
|
233
|
+
// console.info('getAnimationStyles', key, shareValMap[key].value)
|
|
234
|
+
if (Array.isArray(key)) {
|
|
235
|
+
const transformStyle = getTransformObj()
|
|
236
|
+
key.forEach((transformKey) => {
|
|
237
|
+
transformStyle[transformKey] = shareValMap[transformKey].value
|
|
238
|
+
})
|
|
239
|
+
styles.transform = Object.entries(transformStyle).map(([key, value]) => {
|
|
240
|
+
return { [key]: value }
|
|
241
|
+
}) as Extract<'transform', TransformsStyle>
|
|
242
|
+
} else {
|
|
243
|
+
styles[key] = shareValMap[key].value
|
|
244
|
+
}
|
|
245
|
+
return styles
|
|
246
|
+
}, Object.assign({}, originalStyle) as ExtendedViewStyle)
|
|
247
|
+
})
|
|
248
|
+
}
|
|
@@ -10,8 +10,7 @@ export type HandlerRef<T, P> = {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export default function useNodesRef<T, P> (props: P, ref: ForwardedRef<HandlerRef<T, P>>, instance:Obj = {}) {
|
|
14
|
-
const nodeRef = useRef<T>(null)
|
|
13
|
+
export default function useNodesRef<T, P> (props: P, ref: ForwardedRef<HandlerRef<T, P>>, nodeRef: RefObject<T>, instance:Obj = {}) {
|
|
15
14
|
const _props = useRef<P | null>(null)
|
|
16
15
|
_props.current = props
|
|
17
16
|
|
|
@@ -26,8 +25,4 @@ export default function useNodesRef<T, P> (props: P, ref: ForwardedRef<HandlerRe
|
|
|
26
25
|
}
|
|
27
26
|
}
|
|
28
27
|
})
|
|
29
|
-
|
|
30
|
-
return {
|
|
31
|
-
nodeRef
|
|
32
|
-
}
|
|
33
28
|
}
|