@mpxjs/webpack-plugin 2.10.17-beta.2 → 2.10.17-beta.4
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 +60 -0
- package/lib/file-loader.js +4 -1
- package/lib/global.d.ts +16 -0
- package/lib/index.js +22 -2
- package/lib/json-compiler/index.js +13 -4
- package/lib/platform/json/wx/index.js +6 -0
- package/lib/platform/style/wx/index.js +57 -33
- package/lib/platform/template/wx/component-config/ad.js +5 -0
- package/lib/platform/template/wx/component-config/button.js +9 -2
- package/lib/platform/template/wx/component-config/camera.js +25 -3
- package/lib/platform/template/wx/component-config/canvas.js +8 -1
- package/lib/platform/template/wx/component-config/cover-image.js +7 -2
- package/lib/platform/template/wx/component-config/cover-view.js +3 -1
- package/lib/platform/template/wx/component-config/form.js +27 -2
- package/lib/platform/template/wx/component-config/image.js +5 -0
- package/lib/platform/template/wx/component-config/input.js +10 -0
- package/lib/platform/template/wx/component-config/label.js +10 -2
- package/lib/platform/template/wx/component-config/map.js +11 -0
- package/lib/platform/template/wx/component-config/movable-area.js +4 -1
- package/lib/platform/template/wx/component-config/movable-view.js +17 -2
- package/lib/platform/template/wx/component-config/navigator.js +26 -0
- package/lib/platform/template/wx/component-config/picker-view.js +12 -0
- package/lib/platform/template/wx/component-config/picker.js +3 -1
- package/lib/platform/template/wx/component-config/progress.js +11 -1
- package/lib/platform/template/wx/component-config/rich-text.js +5 -0
- package/lib/platform/template/wx/component-config/scroll-view.js +12 -1
- package/lib/platform/template/wx/component-config/slider.js +8 -0
- package/lib/platform/template/wx/component-config/swiper-item.js +5 -2
- package/lib/platform/template/wx/component-config/swiper.js +10 -0
- package/lib/platform/template/wx/component-config/text.js +5 -0
- package/lib/platform/template/wx/component-config/textarea.js +19 -2
- package/lib/platform/template/wx/component-config/unsupported.js +10 -1
- package/lib/platform/template/wx/component-config/video.js +10 -0
- package/lib/platform/template/wx/index.js +21 -1
- package/lib/react/LoadAsyncChunkModule.js +1 -1
- package/lib/react/processStyles.js +21 -9
- package/lib/react/style-helper.js +76 -13
- package/lib/resolver/AddModePlugin.js +23 -8
- package/lib/runtime/components/react/animationHooks/index.ts +75 -0
- package/lib/runtime/components/react/animationHooks/useAnimationAPIHooks.ts +198 -0
- package/lib/runtime/components/react/animationHooks/useTransitionHooks.ts +297 -0
- package/lib/runtime/components/react/animationHooks/utils.ts +196 -0
- package/lib/runtime/components/react/context.ts +7 -1
- package/lib/runtime/components/react/dist/animationHooks/index.d.ts +16 -0
- package/lib/runtime/components/react/dist/animationHooks/index.d.ts.map +1 -0
- package/lib/runtime/components/react/dist/animationHooks/index.js +67 -0
- package/lib/runtime/components/react/dist/animationHooks/useAnimationAPIHooks.d.ts +4 -0
- package/lib/runtime/components/react/dist/animationHooks/useAnimationAPIHooks.d.ts.map +1 -0
- package/lib/runtime/components/react/dist/animationHooks/useAnimationAPIHooks.js +182 -0
- package/lib/runtime/components/react/dist/animationHooks/useTransitionHooks.d.ts +4 -0
- package/lib/runtime/components/react/dist/animationHooks/useTransitionHooks.d.ts.map +1 -0
- package/lib/runtime/components/react/dist/animationHooks/useTransitionHooks.js +274 -0
- package/lib/runtime/components/react/dist/animationHooks/utils.d.ts +110 -0
- package/lib/runtime/components/react/dist/animationHooks/utils.d.ts.map +1 -0
- package/lib/runtime/components/react/dist/animationHooks/utils.js +150 -0
- package/lib/runtime/components/react/dist/context.d.ts +6 -1
- package/lib/runtime/components/react/dist/context.d.ts.map +1 -1
- package/lib/runtime/components/react/dist/mpx-camera.d.ts +32 -0
- package/lib/runtime/components/react/dist/mpx-camera.d.ts.map +1 -0
- package/lib/runtime/components/react/dist/mpx-camera.jsx +236 -0
- package/lib/runtime/components/react/dist/mpx-input.d.ts +2 -0
- package/lib/runtime/components/react/dist/mpx-input.d.ts.map +1 -1
- package/lib/runtime/components/react/dist/mpx-input.jsx +21 -10
- package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.d.ts.map +1 -1
- package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +3 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-swiper.d.ts +10 -0
- package/lib/runtime/components/react/dist/mpx-swiper.d.ts.map +1 -1
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +28 -16
- package/lib/runtime/components/react/dist/mpx-view.d.ts +3 -2
- package/lib/runtime/components/react/dist/mpx-view.d.ts.map +1 -1
- package/lib/runtime/components/react/dist/mpx-view.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +1 -1
- package/lib/runtime/components/react/dist/utils.d.ts +1 -0
- package/lib/runtime/components/react/dist/utils.d.ts.map +1 -1
- package/lib/runtime/components/react/dist/utils.jsx +34 -13
- package/lib/runtime/components/react/mpx-camera.tsx +327 -0
- package/lib/runtime/components/react/mpx-input.tsx +26 -10
- package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +3 -0
- package/lib/runtime/components/react/mpx-portal/portal-manager.tsx +2 -2
- package/lib/runtime/components/react/mpx-swiper.tsx +43 -15
- package/lib/runtime/components/react/mpx-view.tsx +4 -5
- package/lib/runtime/components/react/mpx-web-view.tsx +1 -1
- package/lib/runtime/components/react/types/global.d.ts +1 -0
- package/lib/runtime/components/react/utils.tsx +34 -16
- package/lib/runtime/optionProcessor.js +5 -0
- package/lib/runtime/optionProcessorReact.js +7 -0
- package/lib/runtime/stringify.wxs +2 -2
- package/lib/style-compiler/strip-conditional-loader/rebaseUrl.js +225 -0
- package/lib/style-compiler/strip-conditional-loader.js +55 -180
- package/lib/template-compiler/compiler.js +1 -3
- package/lib/utils/dom-tag-config.js +1 -1
- package/lib/utils/string.js +25 -1
- package/package.json +2 -1
- package/lib/runtime/components/react/dist/useAnimationHooks.d.ts +0 -33
- package/lib/runtime/components/react/dist/useAnimationHooks.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/useAnimationHooks.js +0 -289
- package/lib/runtime/components/react/useAnimationHooks.ts +0 -320
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { hasOwn, dash2hump, error } from '@mpxjs/utils'
|
|
2
|
+
import { useMemo, useRef, useEffect } from 'react'
|
|
3
|
+
import {
|
|
4
|
+
Easing,
|
|
5
|
+
makeMutable,
|
|
6
|
+
runOnJS,
|
|
7
|
+
useSharedValue,
|
|
8
|
+
useAnimatedStyle,
|
|
9
|
+
cancelAnimation
|
|
10
|
+
} from 'react-native-reanimated'
|
|
11
|
+
import {
|
|
12
|
+
easingKey,
|
|
13
|
+
transitionSupportedProperty,
|
|
14
|
+
transformInitial,
|
|
15
|
+
cubicBezierExp,
|
|
16
|
+
secondRegExp,
|
|
17
|
+
percentExp,
|
|
18
|
+
getTransformObj,
|
|
19
|
+
getUnit,
|
|
20
|
+
getInitialVal,
|
|
21
|
+
getAnimation,
|
|
22
|
+
isTransform
|
|
23
|
+
} from './utils'
|
|
24
|
+
import { parseValues, useRunOnJSCallback } from '../utils'
|
|
25
|
+
import type { SharedValue, AnimatableValue, EasingFunction } from 'react-native-reanimated'
|
|
26
|
+
import type { TransformsStyle } from 'react-native'
|
|
27
|
+
import type { ExtendedViewStyle } from '../types/common'
|
|
28
|
+
import type { AnimationHooksPropsType, TransitionMap, TimingFunction } from './utils'
|
|
29
|
+
|
|
30
|
+
type AnimationDataType = {
|
|
31
|
+
property?: string
|
|
32
|
+
duration?: number
|
|
33
|
+
delay?: number
|
|
34
|
+
easing: EasingFunction
|
|
35
|
+
}
|
|
36
|
+
const propName = {
|
|
37
|
+
transition: '',
|
|
38
|
+
transitionDuration: 'duration',
|
|
39
|
+
transitionProperty: 'property',
|
|
40
|
+
transitionTimingFunction: 'easing',
|
|
41
|
+
transitionDelay: 'delay'
|
|
42
|
+
}
|
|
43
|
+
const behaviorExp = /^(allow-discrete|normal)$/
|
|
44
|
+
const defaultValueExp = /^(inherit|initial|revert|revert-layer|unset)$/
|
|
45
|
+
const timingFunctionExp = /^(step-start|step-end|steps)/
|
|
46
|
+
// cubic-bezier 参数解析
|
|
47
|
+
function getBezierParams (str: string) {
|
|
48
|
+
// ease 0.25, 0.1, 0.25, 1.0
|
|
49
|
+
return str.match(cubicBezierExp)?.[1]?.split(',').map(item => +item)
|
|
50
|
+
}
|
|
51
|
+
// 解析 transition-prop
|
|
52
|
+
function parseTransitionSingleProp (vals: string[], property: string) {
|
|
53
|
+
let setDuration = false
|
|
54
|
+
property = propName[property as keyof typeof propName]
|
|
55
|
+
return vals.map(val => {
|
|
56
|
+
// transition-property all
|
|
57
|
+
if (val === 'all') {
|
|
58
|
+
error('[Mpx runtime error]: the value of transition-property is not supported \'all\'')
|
|
59
|
+
return undefined
|
|
60
|
+
}
|
|
61
|
+
// behavior
|
|
62
|
+
if (behaviorExp.test(val)) {
|
|
63
|
+
error('[Mpx runtime error]: transition-behavior is not supported')
|
|
64
|
+
return undefined
|
|
65
|
+
}
|
|
66
|
+
// global values
|
|
67
|
+
if (defaultValueExp.test(val)) {
|
|
68
|
+
error('[Mpx runtime error]: global values is not supported')
|
|
69
|
+
return undefined
|
|
70
|
+
}
|
|
71
|
+
if (timingFunctionExp.test(val)) {
|
|
72
|
+
error('[Mpx runtime error]: the timingFunction in step-start,step-end,steps() is not supported')
|
|
73
|
+
return undefined
|
|
74
|
+
}
|
|
75
|
+
// timingFunction
|
|
76
|
+
if (Object.keys(easingKey).includes(val) || cubicBezierExp.test(val)) {
|
|
77
|
+
const bezierParams = getBezierParams(val)
|
|
78
|
+
return {
|
|
79
|
+
easing: bezierParams?.length ? Easing.bezier(bezierParams[0], bezierParams[1], bezierParams[2], bezierParams[3]) : easingKey[val as TimingFunction] || Easing.inOut(Easing.ease)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// duration & delay
|
|
83
|
+
if (secondRegExp.test(val)) {
|
|
84
|
+
const newProperty = property || (!setDuration ? 'duration' : 'delay')
|
|
85
|
+
setDuration = true
|
|
86
|
+
// console.log('parseTransitionSingleProp val=', val, property, setDuration)
|
|
87
|
+
return {
|
|
88
|
+
[newProperty]: getUnit(val)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// property
|
|
92
|
+
return {
|
|
93
|
+
property: dash2hump(val)
|
|
94
|
+
}
|
|
95
|
+
}).filter(item => item !== undefined)
|
|
96
|
+
}
|
|
97
|
+
// transition 解析
|
|
98
|
+
function parseTransitionStyle (originalStyle: ExtendedViewStyle) {
|
|
99
|
+
let transitionData: AnimationDataType[] = []
|
|
100
|
+
Object.entries(originalStyle).filter(arr => arr[0].includes('transition')).forEach(([prop, value]) => {
|
|
101
|
+
if (prop === 'transition') {
|
|
102
|
+
const vals = parseValues(value, ',').map(item => {
|
|
103
|
+
return parseTransitionSingleProp(parseValues(item), prop).reduce((map, subItem) => {
|
|
104
|
+
return Object.assign(map, subItem)
|
|
105
|
+
}, {} as AnimationDataType)
|
|
106
|
+
})
|
|
107
|
+
// console.log(`parseTransitionStyle ${prop}=${value} formatVal=`, vals)
|
|
108
|
+
if (transitionData.length) {
|
|
109
|
+
transitionData = (vals.length > transitionData.length ? vals : transitionData).map((transitionItem, i) => {
|
|
110
|
+
const valItem = vals[i] || {}
|
|
111
|
+
const current = transitionData[i] || {}
|
|
112
|
+
// console.log('parseTransitionStyle current=', current)
|
|
113
|
+
// console.log('parseTransitionStyle valItem=', valItem)
|
|
114
|
+
// console.log('parseTransitionStyle mergeObj=', Object.assign({}, current, valItem))
|
|
115
|
+
return Object.assign({}, current, valItem)
|
|
116
|
+
})
|
|
117
|
+
// console.log(`parseTransitionStyle ${prop}=${value}, transitionData=`, transitionData)
|
|
118
|
+
} else {
|
|
119
|
+
transitionData = vals
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
const vals = parseTransitionSingleProp(parseValues(value, ','), prop)
|
|
123
|
+
// console.log(`parseTransitionStyle ${prop}=${value} formatVal=`, vals)
|
|
124
|
+
// formatVal [{"property": "transform"}, {"property": "marginLeft"}]
|
|
125
|
+
if (transitionData.length) {
|
|
126
|
+
transitionData = (vals.length > transitionData.length ? vals : transitionData).map((transitionItem, i) => {
|
|
127
|
+
const valItem = vals[i] || vals[vals.length - 1]
|
|
128
|
+
const current = transitionData[i] || transitionData[transitionData.length - 1]
|
|
129
|
+
// console.log('parseTransitionStyle current=', current)
|
|
130
|
+
// console.log('parseTransitionStyle valItem=', valItem)
|
|
131
|
+
// console.log('parseTransitionStyle mergeObj=', Object.assign({}, current, valItem))
|
|
132
|
+
return Object.assign({}, current, valItem)
|
|
133
|
+
})
|
|
134
|
+
// console.log(`parseTransitionStyle ${prop}=${value}, transitionData=`, transitionData)
|
|
135
|
+
} else {
|
|
136
|
+
transitionData = vals as AnimationDataType[]
|
|
137
|
+
}
|
|
138
|
+
// transitionData.push(...vals)
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
// console.log(`parseTransitionStyle transitionData=`, transitionData)
|
|
142
|
+
// 从style 中解析的动画数据,结构如下:
|
|
143
|
+
// transitionMap= {"marginLeft": {"delay": 0, "duration": 3000, "easing": []}, "transform": {"delay": 0, "duration": 3000, "easing": []}}
|
|
144
|
+
const transitionMap = transitionData.reduce((acc, cur) => {
|
|
145
|
+
// hasOwn(transitionSupportedProperty, dash2hump(val)) || val === Transform
|
|
146
|
+
const { property = '', duration = 0, delay = 0, easing = Easing.inOut(Easing.ease) } = cur
|
|
147
|
+
if ((hasOwn(transitionSupportedProperty, dash2hump(property)) || property === 'transform') && duration > 0) {
|
|
148
|
+
acc[property] = {
|
|
149
|
+
duration,
|
|
150
|
+
delay,
|
|
151
|
+
easing
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return acc
|
|
155
|
+
}, {} as TransitionMap)
|
|
156
|
+
// console.log(`parseTransitionStyle transitionMap=`, transitionMap)
|
|
157
|
+
return transitionMap
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export default function useTransitionHooks<T, P> (props: AnimationHooksPropsType) {
|
|
161
|
+
// console.log(`useTransitionHooks, props=`, props)
|
|
162
|
+
const { style: originalStyle = {}, transitionend } = props
|
|
163
|
+
// style变更标识(首次render不执行),初始值为0,首次渲染后为1
|
|
164
|
+
const animationDeps = useRef(0)
|
|
165
|
+
// 记录上次style map
|
|
166
|
+
// const lastStyleRef = useRef({} as {[propName: keyof ExtendedViewStyle]: number|string})
|
|
167
|
+
// ** 从 style 中获取动画数据
|
|
168
|
+
const transitionMap = useMemo(() => {
|
|
169
|
+
return parseTransitionStyle(originalStyle)
|
|
170
|
+
}, [])
|
|
171
|
+
// ** style prop sharedValue interpolateOutput: SharedValue<InterpolateOutput>
|
|
172
|
+
const { shareValMap, animatedKeys, animatedKeysShareVal } = useMemo(() => {
|
|
173
|
+
// 记录需要执行动画的 propName
|
|
174
|
+
const animatedKeys = [] as string[]
|
|
175
|
+
const animatedKeysShareVal = [] as (string|string[])[]
|
|
176
|
+
const transforms = [] as string[]
|
|
177
|
+
const shareValMap = Object.keys(transitionMap).reduce((valMap, property) => {
|
|
178
|
+
// const { property } = transition || {}
|
|
179
|
+
if (property === 'transform') {
|
|
180
|
+
Object.keys(originalStyle.transform ? getTransformObj(originalStyle.transform!) : transformInitial).forEach((key) => {
|
|
181
|
+
const defaultVal = getInitialVal(originalStyle, key)
|
|
182
|
+
// console.log(`shareValMap property=${key} defaultVal=${defaultVal}`)
|
|
183
|
+
valMap[key] = makeMutable(defaultVal)
|
|
184
|
+
animatedKeys.push(key)
|
|
185
|
+
transforms.push(key)
|
|
186
|
+
})
|
|
187
|
+
} else if (hasOwn(transitionSupportedProperty, property)) {
|
|
188
|
+
const defaultVal = getInitialVal(originalStyle, property)
|
|
189
|
+
// console.log(`shareValMap property=${property} defaultVal=${defaultVal}`)
|
|
190
|
+
valMap[property] = makeMutable(defaultVal)
|
|
191
|
+
animatedKeys.push(property)
|
|
192
|
+
animatedKeysShareVal.push(property)
|
|
193
|
+
}
|
|
194
|
+
// console.log('shareValMap = ', valMap)
|
|
195
|
+
return valMap
|
|
196
|
+
}, {} as { [propName: keyof ExtendedViewStyle]: SharedValue<string|number> })
|
|
197
|
+
if (transforms.length) animatedKeysShareVal.push(transforms)
|
|
198
|
+
return {
|
|
199
|
+
shareValMap,
|
|
200
|
+
animatedKeys,
|
|
201
|
+
animatedKeysShareVal
|
|
202
|
+
}
|
|
203
|
+
}, [])
|
|
204
|
+
// 有动画样式的 style key(useAnimatedStyle使用)
|
|
205
|
+
const animatedStyleKeys = useSharedValue(animatedKeysShareVal)
|
|
206
|
+
const runOnJSCallbackRef = useRef({})
|
|
207
|
+
const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef)
|
|
208
|
+
// 根据 animation action 创建&驱动动画
|
|
209
|
+
function createAnimation () {
|
|
210
|
+
let transformTransitionendDone = false
|
|
211
|
+
animatedKeys.forEach(key => {
|
|
212
|
+
// console.log(`createAnimation key=${key} originalStyle=`, originalStyle)
|
|
213
|
+
const isTransformKey = isTransform(key)
|
|
214
|
+
let ruleV = originalStyle[key]
|
|
215
|
+
if (isTransformKey) {
|
|
216
|
+
const transform = getTransformObj(originalStyle.transform!)
|
|
217
|
+
ruleV = transform[key]
|
|
218
|
+
}
|
|
219
|
+
let toVal = ruleV !== undefined
|
|
220
|
+
? ruleV
|
|
221
|
+
: transitionSupportedProperty[key]
|
|
222
|
+
const shareVal = shareValMap[key].value
|
|
223
|
+
if (percentExp.test(`${toVal}`) && !percentExp.test(shareVal as string) && !isNaN(+shareVal)) {
|
|
224
|
+
// 获取到的toVal为百分比格式化shareValMap为百分比
|
|
225
|
+
shareValMap[key].value = `${shareVal as number * 100}%`
|
|
226
|
+
} else if (percentExp.test(shareVal as string) && !percentExp.test(toVal as string) && !isNaN(+toVal)) {
|
|
227
|
+
// 初始值为百分比则格式化toVal为百分比
|
|
228
|
+
toVal = `${toVal * 100}%`
|
|
229
|
+
} else if (typeof toVal !== typeof shareVal) {
|
|
230
|
+
// 动画起始值和终态值类型不一致报错提示一下
|
|
231
|
+
error(`[Mpx runtime error]: Value types of property ${key} must be consistent during the animation`)
|
|
232
|
+
}
|
|
233
|
+
// console.log(`key=${key} oldVal=${shareValMap[key].value} newVal=${toVal}`)
|
|
234
|
+
const { delay = 0, duration, easing } = transitionMap[isTransformKey ? 'transform' : key]
|
|
235
|
+
// console.log('animationOptions=', { delay, duration, easing })
|
|
236
|
+
let callback
|
|
237
|
+
if (transitionend && (!isTransformKey || !transformTransitionendDone)) {
|
|
238
|
+
runOnJSCallbackRef.current = {
|
|
239
|
+
animationCallback: (duration: number, finished: boolean, current?: AnimatableValue) => {
|
|
240
|
+
transitionend(finished, current, duration)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
callback = (finished?: boolean, current?: AnimatableValue) => {
|
|
244
|
+
'worklet'
|
|
245
|
+
// 动画结束后设置下一次transformOrigin
|
|
246
|
+
if (finished) {
|
|
247
|
+
runOnJS(runOnJSCallback)('animationCallback', duration, finished, current)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const animation = getAnimation({ key, value: toVal! }, { delay, duration, easing }, callback)
|
|
252
|
+
// Todo transform 有多个属性时也仅执行一次 transitionend(对齐wx)
|
|
253
|
+
if (isTransformKey) {
|
|
254
|
+
transformTransitionendDone = true
|
|
255
|
+
}
|
|
256
|
+
shareValMap[key].value = animation
|
|
257
|
+
// console.log(`useTransitionHooks, ${key}=`, animation)
|
|
258
|
+
})
|
|
259
|
+
}
|
|
260
|
+
// ** style 更新
|
|
261
|
+
useEffect(() => {
|
|
262
|
+
// console.log('useEffect originalStyle animationDeps=', animationDeps.current, originalStyle)
|
|
263
|
+
// 首次不执行
|
|
264
|
+
if (!animationDeps.current) {
|
|
265
|
+
animationDeps.current = 1
|
|
266
|
+
return
|
|
267
|
+
}
|
|
268
|
+
createAnimation()
|
|
269
|
+
}, [originalStyle])
|
|
270
|
+
// ** 清空动画
|
|
271
|
+
useEffect(() => {
|
|
272
|
+
return () => {
|
|
273
|
+
Object.values(shareValMap).forEach((value) => {
|
|
274
|
+
cancelAnimation(value)
|
|
275
|
+
})
|
|
276
|
+
}
|
|
277
|
+
}, [])
|
|
278
|
+
// ** 生成动画样式
|
|
279
|
+
return useAnimatedStyle(() => {
|
|
280
|
+
// console.info(`useAnimatedStyle styles=`, originalStyle)
|
|
281
|
+
return animatedStyleKeys.value.reduce((styles, key) => {
|
|
282
|
+
if (Array.isArray(key)) {
|
|
283
|
+
const transformStyle = getTransformObj(originalStyle.transform || [])
|
|
284
|
+
key.forEach((transformKey) => {
|
|
285
|
+
transformStyle[transformKey] = shareValMap[transformKey].value
|
|
286
|
+
})
|
|
287
|
+
styles.transform = Object.entries(transformStyle).map(([key, value]) => {
|
|
288
|
+
return { [key]: value }
|
|
289
|
+
}) as Extract<'transform', TransformsStyle>
|
|
290
|
+
} else {
|
|
291
|
+
styles[key] = shareValMap[key].value
|
|
292
|
+
}
|
|
293
|
+
// console.log('animationStyle', styles)
|
|
294
|
+
return styles
|
|
295
|
+
}, {} as ExtendedViewStyle)
|
|
296
|
+
})
|
|
297
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Easing,
|
|
3
|
+
withTiming,
|
|
4
|
+
withDelay
|
|
5
|
+
} from 'react-native-reanimated'
|
|
6
|
+
import type { AnimatableValue, WithTimingConfig, AnimationCallback, EasingFunction } from 'react-native-reanimated'
|
|
7
|
+
import { hasOwn } from '@mpxjs/utils'
|
|
8
|
+
import type { ExtendedViewStyle } from '../types/common'
|
|
9
|
+
import type { _ViewProps } from '../mpx-view'
|
|
10
|
+
|
|
11
|
+
export type TimingFunction = 'linear' | 'ease' | 'ease-in' | 'ease-in-out'| 'ease-out'
|
|
12
|
+
|
|
13
|
+
export type AnimatedOption = {
|
|
14
|
+
duration: number
|
|
15
|
+
delay?: number
|
|
16
|
+
useNativeDriver?: boolean
|
|
17
|
+
timingFunction?: TimingFunction
|
|
18
|
+
transformOrigin?: string
|
|
19
|
+
}
|
|
20
|
+
export type ExtendWithTimingConfig = WithTimingConfig & {
|
|
21
|
+
delay?: number
|
|
22
|
+
}
|
|
23
|
+
export type AnimationStepItem = {
|
|
24
|
+
animatedOption: AnimatedOption
|
|
25
|
+
rules: Map<string, number | string>
|
|
26
|
+
transform: Map<string, number>
|
|
27
|
+
}
|
|
28
|
+
export type AnimationProp = {
|
|
29
|
+
id: number,
|
|
30
|
+
actions: AnimationStepItem[]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type CustomAnimationCallback = (finished?: boolean, current?: AnimatableValue, duration?: number) => void
|
|
34
|
+
|
|
35
|
+
export type TransitionMap = {
|
|
36
|
+
[propName: string]: {
|
|
37
|
+
duration: number
|
|
38
|
+
delay?: number
|
|
39
|
+
easing: EasingFunction
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type InterpolateOutput = {
|
|
44
|
+
[propName: string]: string[]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type AnimationHooksPropsType = _ViewProps & { transitionend?: CustomAnimationCallback }
|
|
48
|
+
|
|
49
|
+
// ms s 单位匹配
|
|
50
|
+
export const secondRegExp = /^\s*(\d*(?:\.\d+)?)(s|ms)?\s*$/
|
|
51
|
+
export const cubicBezierExp = /cubic-bezier\(["']?(.*?)["']?\)/
|
|
52
|
+
export const percentExp = /^((-?(\d+(\.\d+)?|\.\d+))%)$/
|
|
53
|
+
// export const PropNameColorExp = /^c|Color$/
|
|
54
|
+
// export const NumberExp = /^((opacity|flex-grow|flex-shrink|gap|left|right|top|bottom)|(.+-(width|height|left|right|top|bottom|radius|spacing|size|gap|index|offset|opacity)))$/
|
|
55
|
+
// export const ColorExp = /^(color|(.+Color))$/
|
|
56
|
+
// transform
|
|
57
|
+
// export const transform = 'transform'
|
|
58
|
+
// export const transformOrigin = 'transformOrigin'
|
|
59
|
+
// export const transition = 'transition'
|
|
60
|
+
|
|
61
|
+
// 微信 timingFunction 和 RN Easing 对应关系
|
|
62
|
+
export const easingKey = {
|
|
63
|
+
linear: Easing.linear,
|
|
64
|
+
ease: Easing.inOut(Easing.ease),
|
|
65
|
+
'ease-in': Easing.in(Easing.poly(3)),
|
|
66
|
+
'ease-in-out': Easing.inOut(Easing.poly(3)),
|
|
67
|
+
'ease-out': Easing.out(Easing.poly(3))
|
|
68
|
+
// 'step-start': '',
|
|
69
|
+
// 'step-end': ''
|
|
70
|
+
}
|
|
71
|
+
export const transformInitial: ExtendedViewStyle = {
|
|
72
|
+
// matrix: 0,
|
|
73
|
+
// matrix3d: 0,
|
|
74
|
+
// rotate: '0deg',
|
|
75
|
+
rotateX: '0deg',
|
|
76
|
+
rotateY: '0deg',
|
|
77
|
+
rotateZ: '0deg',
|
|
78
|
+
// rotate3d:[0,0,0]
|
|
79
|
+
// scale: 1,
|
|
80
|
+
// scale3d: [1, 1, 1],
|
|
81
|
+
scaleX: 1,
|
|
82
|
+
scaleY: 1,
|
|
83
|
+
// scaleZ: 1,
|
|
84
|
+
// skew: 0,
|
|
85
|
+
skewX: '0deg',
|
|
86
|
+
skewY: '0deg',
|
|
87
|
+
// translate: 0,
|
|
88
|
+
// translate3d: 0,
|
|
89
|
+
translateX: 0,
|
|
90
|
+
translateY: 0
|
|
91
|
+
// translateZ: 0,
|
|
92
|
+
}
|
|
93
|
+
// animation api 动画默认初始值
|
|
94
|
+
export const animationAPIInitialValue: ExtendedViewStyle = Object.assign({
|
|
95
|
+
opacity: 1,
|
|
96
|
+
backgroundColor: 'transparent',
|
|
97
|
+
width: 0,
|
|
98
|
+
height: 0,
|
|
99
|
+
top: 0,
|
|
100
|
+
right: 0,
|
|
101
|
+
bottom: 0,
|
|
102
|
+
left: 0,
|
|
103
|
+
transformOrigin: ['50%', '50%', 0]
|
|
104
|
+
}, transformInitial)
|
|
105
|
+
// transition property
|
|
106
|
+
export const transitionSupportedProperty = Object.assign({
|
|
107
|
+
color: 'transparent',
|
|
108
|
+
borderColor: 'transparent',
|
|
109
|
+
borderBottomColor: 'transparent',
|
|
110
|
+
borderLeftColor: 'transparent',
|
|
111
|
+
borderRightColor: 'transparent',
|
|
112
|
+
borderTopColor: 'transparent',
|
|
113
|
+
borderTopLeftRadius: 0,
|
|
114
|
+
borderTopRightRadius: 0,
|
|
115
|
+
borderBottomLeftRadius: 0,
|
|
116
|
+
borderBottomRightRadius: 0,
|
|
117
|
+
borderRadius: 0,
|
|
118
|
+
borderBottomWidth: 0,
|
|
119
|
+
borderLeftWidth: 0,
|
|
120
|
+
borderRightWidth: 0,
|
|
121
|
+
borderTopWidth: 0,
|
|
122
|
+
borderWidth: 0,
|
|
123
|
+
margin: 0,
|
|
124
|
+
marginBottom: 0,
|
|
125
|
+
marginLeft: 0,
|
|
126
|
+
marginRight: 0,
|
|
127
|
+
marginTop: 0,
|
|
128
|
+
marginHorizontal: 0,
|
|
129
|
+
marginVertical: 0,
|
|
130
|
+
maxHeight: 0,
|
|
131
|
+
maxWidth: 0,
|
|
132
|
+
minHeight: 0,
|
|
133
|
+
minWidth: 0,
|
|
134
|
+
padding: 0,
|
|
135
|
+
paddingBottom: 0,
|
|
136
|
+
paddingLeft: 0,
|
|
137
|
+
paddingRight: 0,
|
|
138
|
+
paddingTop: 0,
|
|
139
|
+
paddingHorizontal: 0,
|
|
140
|
+
paddingVertical: 0,
|
|
141
|
+
fontSize: 0, // Todo
|
|
142
|
+
letterSpacing: 0 // Todo
|
|
143
|
+
}, animationAPIInitialValue)
|
|
144
|
+
|
|
145
|
+
// export type PropertyType = keyof transitionSupportedProperty
|
|
146
|
+
// transform
|
|
147
|
+
export const isTransform = (key: string) => hasOwn(transformInitial, key)
|
|
148
|
+
// transform 数组转对象
|
|
149
|
+
export function getTransformObj (transforms: { [propName: string]: string | number }[]) {
|
|
150
|
+
'worklet'
|
|
151
|
+
return (transforms || []).reduce((transformObj, item) => {
|
|
152
|
+
return Object.assign(transformObj, item)
|
|
153
|
+
}, {} as { [propName: string]: string | number })
|
|
154
|
+
}
|
|
155
|
+
// 获取样式初始值(prop style or 默认值)
|
|
156
|
+
export function getInitialVal (style: ExtendedViewStyle, key: string) {
|
|
157
|
+
if (isTransform(key) && Array.isArray(style.transform)) {
|
|
158
|
+
let initialVal = transitionSupportedProperty[key]
|
|
159
|
+
// 仅支持 { transform: [{rotateX: '45deg'}, {rotateZ: '0.785398rad'}] } 格式的初始样式
|
|
160
|
+
style.transform.forEach(item => {
|
|
161
|
+
if (item[key] !== undefined) initialVal = item[key]
|
|
162
|
+
})
|
|
163
|
+
return initialVal
|
|
164
|
+
}
|
|
165
|
+
return style[key] === undefined ? transitionSupportedProperty[key] : style[key]
|
|
166
|
+
}
|
|
167
|
+
// animated key transform 格式化
|
|
168
|
+
export function formatAnimatedKeys (keys: string[]) {
|
|
169
|
+
// console.log('formatAnimatedKeys keys=', keys)
|
|
170
|
+
const animatedKeys = [] as (string|string[])[]
|
|
171
|
+
const transforms = [] as string[]
|
|
172
|
+
keys.forEach(key => {
|
|
173
|
+
if (isTransform(key)) {
|
|
174
|
+
transforms.push(key)
|
|
175
|
+
} else {
|
|
176
|
+
animatedKeys.push(key)
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
if (transforms.length) animatedKeys.push(transforms)
|
|
180
|
+
// console.log('formatAnimatedKeys animatedKeys=', animatedKeys)
|
|
181
|
+
return animatedKeys
|
|
182
|
+
}
|
|
183
|
+
// 解析动画时长
|
|
184
|
+
export function getUnit (duration: string) {
|
|
185
|
+
const match = secondRegExp.exec(duration)
|
|
186
|
+
return match ? match[2] === 's' ? +match[1] * 1000 : +match[1] : 0
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// 根据动画数据创建单个animation
|
|
190
|
+
export function getAnimation ({ key, value }: { key: string, value: string|number }, { delay = 0, duration, easing }: ExtendWithTimingConfig, callback?: AnimationCallback) {
|
|
191
|
+
// console.log('getAnimation', key, value, delay, duration, easing)
|
|
192
|
+
const animation = typeof callback === 'function'
|
|
193
|
+
? withTiming(value, { duration, easing }, callback)
|
|
194
|
+
: withTiming(value, { duration, easing })
|
|
195
|
+
return delay ? withDelay(delay, animation) : animation
|
|
196
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createContext, Dispatch, MutableRefObject, SetStateAction } from 'react'
|
|
2
|
-
import { NativeSyntheticEvent, Animated } from 'react-native'
|
|
2
|
+
import { NativeSyntheticEvent, Animated, ScaledSize } from 'react-native'
|
|
3
3
|
import { noop } from '@mpxjs/utils'
|
|
4
4
|
|
|
5
5
|
export type LabelContextValue = MutableRefObject<{
|
|
@@ -10,6 +10,7 @@ export type KeyboardAvoidContextValue = MutableRefObject<{
|
|
|
10
10
|
cursorSpacing: number
|
|
11
11
|
ref: MutableRefObject<any>
|
|
12
12
|
adjustPosition: boolean
|
|
13
|
+
holdKeyboard?: boolean
|
|
13
14
|
keyboardHeight?: number
|
|
14
15
|
onKeyboardShow?: () => void
|
|
15
16
|
} | null>
|
|
@@ -56,6 +57,11 @@ export interface RouteContextValue {
|
|
|
56
57
|
navigation: Record<string, any>
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
export interface DimensionsValue {
|
|
61
|
+
window: ScaledSize;
|
|
62
|
+
screen: ScaledSize;
|
|
63
|
+
}
|
|
64
|
+
|
|
59
65
|
export interface StickyContextValue {
|
|
60
66
|
registerStickyHeader: Function
|
|
61
67
|
unregisterStickyHeader: Function
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MutableRefObject } from 'react';
|
|
2
|
+
import type { NativeSyntheticEvent } from 'react-native';
|
|
3
|
+
import type { _ViewProps } from '../mpx-view';
|
|
4
|
+
export type AnimationType = 'api' | 'animation' | 'transition' | 'none';
|
|
5
|
+
export default function useAnimationHooks<T, P>(props: _ViewProps & {
|
|
6
|
+
enableAnimation?: boolean | AnimationType;
|
|
7
|
+
layoutRef: MutableRefObject<any>;
|
|
8
|
+
transitionend?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void;
|
|
9
|
+
}): {
|
|
10
|
+
enableStyleAnimation: boolean;
|
|
11
|
+
animationStyle?: undefined;
|
|
12
|
+
} | {
|
|
13
|
+
enableStyleAnimation: boolean;
|
|
14
|
+
animationStyle: import("../types/common").ExtendedViewStyle;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../animationHooks/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAA;AAC7C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAG7C,MAAM,MAAM,aAAa,GAAG,KAAK,GAAC,WAAW,GAAC,YAAY,GAAC,MAAM,CAAA;AAEjE,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAG,KAAK,EAAE,UAAU,GAAG;IAAE,eAAe,CAAC,EAAE,OAAO,GAAG,aAAa,CAAC;IAAC,SAAS,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,UAAU,CAAC,GAAG,OAAO,KAAK,IAAI,CAAA;CAAE;;;;;;EA8DhO"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { error, collectDataset, hasOwn } from '@mpxjs/utils';
|
|
2
|
+
import { useRef } from 'react';
|
|
3
|
+
import useAnimationAPIHooks from './useAnimationAPIHooks';
|
|
4
|
+
import useTransitionHooks from './useTransitionHooks';
|
|
5
|
+
export default function useAnimationHooks(props) {
|
|
6
|
+
const { style: originalStyle = {}, enableAnimation, animation, transitionend, layoutRef } = props;
|
|
7
|
+
// 记录动画类型
|
|
8
|
+
let animationType = '';
|
|
9
|
+
if (hasOwn(originalStyle, 'animation') || (hasOwn(originalStyle, 'animationName') && hasOwn(originalStyle, 'animationDuration'))) {
|
|
10
|
+
// css animation 只做检测提示
|
|
11
|
+
animationType = 'animation';
|
|
12
|
+
}
|
|
13
|
+
if (!!animation || enableAnimation === true) {
|
|
14
|
+
animationType = 'api';
|
|
15
|
+
}
|
|
16
|
+
// 优先级 css transition > API
|
|
17
|
+
if (hasOwn(originalStyle, 'transition') || (hasOwn(originalStyle, 'transitionProperty') && hasOwn(originalStyle, 'transitionDuration'))) {
|
|
18
|
+
animationType = 'transition';
|
|
19
|
+
}
|
|
20
|
+
// 优先以 enableAnimation 定义类型为准
|
|
21
|
+
if (enableAnimation === 'api' || enableAnimation === 'transition' || enableAnimation === 'animation') {
|
|
22
|
+
animationType = enableAnimation;
|
|
23
|
+
}
|
|
24
|
+
const animationTypeRef = useRef(animationType);
|
|
25
|
+
if (animationType && animationTypeRef.current !== animationType) {
|
|
26
|
+
// 允许 API、CssTransition 到 none,不允许 API、CssTransition 互切,不允许 none 到 API、CssTransition
|
|
27
|
+
error('[Mpx runtime error]: The animation type should be stable in the component lifecycle, or you can set animation type with [enable-animation].');
|
|
28
|
+
}
|
|
29
|
+
if (animationType === 'animation') {
|
|
30
|
+
// 暂不支持 CssAnimation 提示
|
|
31
|
+
error('[Mpx runtime error]: CSS animation is not supported yet');
|
|
32
|
+
return { enableStyleAnimation: false };
|
|
33
|
+
}
|
|
34
|
+
if (!animationTypeRef.current)
|
|
35
|
+
return { enableStyleAnimation: false };
|
|
36
|
+
const hooksProps = { style: originalStyle };
|
|
37
|
+
if (transitionend && typeof transitionend === 'function') {
|
|
38
|
+
function withTimingCallback(finished, current, duration) {
|
|
39
|
+
const target = {
|
|
40
|
+
id: animation?.id || -1,
|
|
41
|
+
dataset: collectDataset(props),
|
|
42
|
+
offsetLeft: layoutRef?.current?.offsetLeft || 0,
|
|
43
|
+
offsetTop: layoutRef?.current?.offsetTop || 0
|
|
44
|
+
};
|
|
45
|
+
transitionend({
|
|
46
|
+
type: 'transitionend',
|
|
47
|
+
// elapsedTime 对齐wx 单位s
|
|
48
|
+
detail: { elapsedTime: duration ? duration / 1000 : 0, finished, current },
|
|
49
|
+
target,
|
|
50
|
+
currentTarget: target,
|
|
51
|
+
timeStamp: Date.now()
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
Object.assign(hooksProps, { transitionend: withTimingCallback });
|
|
55
|
+
}
|
|
56
|
+
if (animationTypeRef.current === 'api') {
|
|
57
|
+
Object.assign(hooksProps, { animation });
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
enableStyleAnimation: !!animationTypeRef.current,
|
|
61
|
+
animationStyle: animationTypeRef.current === 'api'
|
|
62
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
63
|
+
? useAnimationAPIHooks(hooksProps)
|
|
64
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
65
|
+
: useTransitionHooks(hooksProps)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAnimationAPIHooks.d.ts","sourceRoot":"","sources":["../../animationHooks/useAnimationAPIHooks.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACxD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAA;AAEtD,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAAG,KAAK,EAAE,uBAAuB,qBA0KjF"}
|