@mpxjs/webpack-plugin 2.9.70-alpha.0 → 2.9.71
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/LICENSE +433 -0
- package/README.md +1 -1
- package/lib/config.js +0 -14
- package/lib/dependencies/ResolveDependency.js +0 -5
- package/lib/index.js +7 -38
- package/lib/json-compiler/helper.js +3 -3
- package/lib/loader.js +0 -53
- package/lib/parser.js +1 -1
- package/lib/platform/json/wx/index.js +21 -8
- package/lib/platform/style/wx/index.js +51 -54
- package/lib/platform/template/wx/component-config/button.js +2 -14
- package/lib/platform/template/wx/component-config/fix-component-name.js +15 -12
- package/lib/platform/template/wx/component-config/image.js +0 -4
- package/lib/platform/template/wx/component-config/index.js +1 -1
- package/lib/platform/template/wx/component-config/input.js +0 -4
- package/lib/platform/template/wx/component-config/movable-view.js +8 -1
- package/lib/platform/template/wx/component-config/picker-view.js +1 -5
- package/lib/platform/template/wx/component-config/rich-text.js +6 -2
- package/lib/platform/template/wx/component-config/scroll-view.js +1 -5
- package/lib/platform/template/wx/component-config/switch.js +0 -4
- package/lib/platform/template/wx/component-config/text.js +0 -4
- package/lib/platform/template/wx/component-config/textarea.js +0 -5
- package/lib/platform/template/wx/component-config/unsupported.js +1 -1
- package/lib/platform/template/wx/component-config/view.js +0 -4
- package/lib/platform/template/wx/index.js +1 -131
- package/lib/resolve-loader.js +1 -4
- package/lib/runtime/components/react/context.ts +8 -0
- package/lib/runtime/components/react/dist/context.js +2 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +39 -37
- package/lib/runtime/components/react/dist/mpx-button.jsx +16 -44
- package/lib/runtime/components/react/dist/mpx-canvas/html.js +2 -4
- package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +5 -1
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +93 -58
- package/lib/runtime/components/react/dist/mpx-navigator.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +10 -14
- package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +94 -81
- package/lib/runtime/components/react/dist/mpx-picker-view.jsx +19 -16
- package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +10 -11
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +11 -4
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +31 -8
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +435 -371
- package/lib/runtime/components/react/dist/mpx-view.jsx +18 -53
- package/lib/runtime/components/react/dist/pickerFaces.js +3 -8
- package/lib/runtime/components/react/dist/pickerVIewContext.js +5 -0
- package/lib/runtime/components/react/dist/{pickerViewOverlay.jsx → pickerViewIndicator.jsx} +6 -6
- package/lib/runtime/components/react/dist/pickerViewMask.jsx +2 -2
- package/lib/runtime/components/react/dist/useAnimationHooks.js +27 -10
- package/lib/runtime/components/react/dist/utils.jsx +162 -70
- package/lib/runtime/components/react/event.config.ts +25 -26
- package/lib/runtime/components/react/getInnerListeners.ts +236 -182
- package/lib/runtime/components/react/mpx-button.tsx +27 -69
- package/lib/runtime/components/react/mpx-canvas/html.ts +2 -4
- package/lib/runtime/components/react/mpx-canvas/index.tsx +44 -46
- package/lib/runtime/components/react/mpx-checkbox-group.tsx +15 -13
- package/lib/runtime/components/react/mpx-checkbox.tsx +20 -21
- package/lib/runtime/components/react/mpx-form.tsx +15 -20
- package/lib/runtime/components/react/mpx-icon.tsx +2 -2
- package/lib/runtime/components/react/mpx-image.tsx +87 -47
- package/lib/runtime/components/react/mpx-input.tsx +24 -32
- package/lib/runtime/components/react/mpx-label.tsx +12 -14
- package/lib/runtime/components/react/mpx-movable-area.tsx +10 -16
- package/lib/runtime/components/react/mpx-movable-view.tsx +133 -92
- package/lib/runtime/components/react/mpx-navigator.tsx +3 -9
- package/lib/runtime/components/react/mpx-picker-view-column-item.tsx +76 -0
- package/lib/runtime/components/react/mpx-picker-view-column.tsx +206 -183
- package/lib/runtime/components/react/mpx-picker-view.tsx +49 -48
- package/lib/runtime/components/react/mpx-radio-group.tsx +13 -15
- package/lib/runtime/components/react/mpx-radio.tsx +19 -25
- package/lib/runtime/components/react/mpx-rich-text/html.ts +40 -0
- package/lib/runtime/components/react/mpx-rich-text/index.tsx +115 -0
- package/lib/runtime/components/react/mpx-root-portal.tsx +3 -5
- package/lib/runtime/components/react/mpx-scroll-view.tsx +53 -43
- package/lib/runtime/components/react/mpx-swiper-item.tsx +45 -11
- package/lib/runtime/components/react/mpx-swiper.tsx +742 -0
- package/lib/runtime/components/react/mpx-switch.tsx +19 -15
- package/lib/runtime/components/react/mpx-text.tsx +8 -16
- package/lib/runtime/components/react/mpx-textarea.tsx +11 -10
- package/lib/runtime/components/react/mpx-view.tsx +28 -77
- package/lib/runtime/components/react/mpx-web-view.tsx +94 -59
- package/lib/runtime/components/react/pickerFaces.ts +10 -7
- package/lib/runtime/components/react/pickerVIewContext.ts +27 -0
- package/lib/runtime/components/react/pickerViewIndicator.tsx +34 -0
- package/lib/runtime/components/react/pickerViewMask.tsx +30 -0
- package/lib/runtime/components/react/types/{getInnerListeners.ts → getInnerListeners.d.ts} +4 -5
- package/lib/runtime/components/react/types/global.d.ts +12 -1
- package/lib/runtime/components/react/useAnimationHooks.ts +60 -15
- package/lib/runtime/components/react/utils.tsx +175 -71
- package/lib/runtime/components/web/mpx-checkbox.vue +1 -1
- package/lib/runtime/components/web/mpx-picker-view-column.vue +9 -4
- package/lib/runtime/components/web/mpx-web-view.vue +34 -20
- package/lib/runtime/optionProcessor.js +0 -22
- package/lib/style-compiler/index.js +1 -1
- package/lib/style-compiler/plugins/scope-id.js +30 -2
- package/lib/template-compiler/compiler.js +91 -39
- package/lib/utils/env.js +1 -6
- package/lib/utils/pre-process-json.js +9 -5
- package/lib/wxss/loader.js +15 -2
- package/package.json +4 -7
- package/lib/dependencies/AddEntryDependency.js +0 -24
- package/lib/runtime/components/react/dist/types/common.js +0 -1
- package/lib/runtime/components/react/dist/types/getInnerListeners.js +0 -1
- package/lib/runtime/components/react/mpx-swiper/carouse.tsx +0 -527
- package/lib/runtime/components/react/mpx-swiper/index.tsx +0 -80
- package/lib/runtime/components/react/mpx-swiper/type.ts +0 -87
- package/lib/runtime/components/react/pickerOverlay.tsx +0 -32
- package/lib/runtime/components/tenon/getInnerListeners.js +0 -334
- package/lib/runtime/components/tenon/tenon-button.vue +0 -309
- package/lib/runtime/components/tenon/tenon-image.vue +0 -66
- package/lib/runtime/components/tenon/tenon-input.vue +0 -171
- package/lib/runtime/components/tenon/tenon-rich-text.vue +0 -26
- package/lib/runtime/components/tenon/tenon-scroll-view.vue +0 -127
- package/lib/runtime/components/tenon/tenon-switch.vue +0 -96
- package/lib/runtime/components/tenon/tenon-text.vue +0 -70
- package/lib/runtime/components/tenon/tenon-textarea.vue +0 -86
- package/lib/runtime/components/tenon/tenon-view.vue +0 -93
- package/lib/runtime/components/web/event.js +0 -105
- package/lib/runtime/optionProcessor.tenon.js +0 -84
- package/lib/style-compiler/plugins/hm.js +0 -20
- package/lib/tenon/index.js +0 -117
- package/lib/tenon/processJSON.js +0 -352
- package/lib/tenon/processScript.js +0 -203
- package/lib/tenon/processStyles.js +0 -21
- package/lib/tenon/processTemplate.js +0 -126
- package/lib/tenon/script-helper.js +0 -223
- package/lib/utils/get-relative-path.js +0 -25
- /package/lib/runtime/components/react/types/{common.ts → common.d.ts} +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native'
|
|
3
|
+
import LinearGradient from 'react-native-linear-gradient'
|
|
4
|
+
|
|
5
|
+
type MaskProps = {
|
|
6
|
+
itemHeight: number
|
|
7
|
+
maskContainerStyle?: StyleProp<ViewStyle>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const _PickerViewMask = ({
|
|
11
|
+
itemHeight,
|
|
12
|
+
maskContainerStyle
|
|
13
|
+
}: MaskProps) => {
|
|
14
|
+
return (
|
|
15
|
+
<View style={[styles.maskContainer, maskContainerStyle]} pointerEvents={'none'}>
|
|
16
|
+
<LinearGradient colors={['rgba(255,255,255,1)', 'rgba(255,255,255,0.5)']} style={{ flex: 1 }} />
|
|
17
|
+
<View style={{ height: itemHeight }} />
|
|
18
|
+
<LinearGradient colors={['rgba(255,255,255,0.5)', 'rgba(255,255,255,1)']} style={{ flex: 1 }} />
|
|
19
|
+
</View>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
const styles = StyleSheet.create({
|
|
23
|
+
maskContainer: {
|
|
24
|
+
...StyleSheet.absoluteFillObject,
|
|
25
|
+
zIndex: 100
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
_PickerViewMask.displayName = 'MpxPickerViewMask'
|
|
30
|
+
export default _PickerViewMask
|
|
@@ -13,6 +13,8 @@ type RemoveProps = string[];
|
|
|
13
13
|
|
|
14
14
|
type NativeTouchEvent = NativeSyntheticEvent<NativeEvent>
|
|
15
15
|
|
|
16
|
+
type Navigation = Record<string, any>
|
|
17
|
+
|
|
16
18
|
interface NativeEvent {
|
|
17
19
|
timestamp: number;
|
|
18
20
|
pageX: number;
|
|
@@ -36,10 +38,6 @@ interface InnerRef {
|
|
|
36
38
|
bubble: null | ReturnType<typeof setTimeout>;
|
|
37
39
|
capture: null | ReturnType<typeof setTimeout>;
|
|
38
40
|
};
|
|
39
|
-
needPress: {
|
|
40
|
-
bubble: boolean;
|
|
41
|
-
capture: boolean;
|
|
42
|
-
};
|
|
43
41
|
mpxPressInfo: {
|
|
44
42
|
detail: {
|
|
45
43
|
x: number;
|
|
@@ -65,5 +63,6 @@ export {
|
|
|
65
63
|
InnerRef,
|
|
66
64
|
LayoutRef,
|
|
67
65
|
SetTimeoutReturnType,
|
|
68
|
-
DataSetType
|
|
66
|
+
DataSetType,
|
|
67
|
+
Navigation
|
|
69
68
|
}
|
|
@@ -19,10 +19,21 @@ declare module '@mpxjs/utils' {
|
|
|
19
19
|
bottom: number
|
|
20
20
|
left: number
|
|
21
21
|
right: number
|
|
22
|
-
}
|
|
22
|
+
},
|
|
23
|
+
layout: {
|
|
24
|
+
x: number
|
|
25
|
+
y: number
|
|
26
|
+
width: number
|
|
27
|
+
height: number
|
|
28
|
+
},
|
|
29
|
+
setOptions: (params: Record<string, any>) => void
|
|
23
30
|
} | undefined
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
declare let global: {
|
|
27
34
|
__formatValue (value: string): string | number
|
|
28
35
|
} & Record<string, any>
|
|
36
|
+
|
|
37
|
+
declare module '@react-navigation/native' {
|
|
38
|
+
export function useNavigation (): Record<string, any>
|
|
39
|
+
}
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
WithTimingConfig,
|
|
14
14
|
AnimationCallback
|
|
15
15
|
} from 'react-native-reanimated'
|
|
16
|
+
import { error } from '@mpxjs/utils'
|
|
16
17
|
import { ExtendedViewStyle } from './types/common'
|
|
17
18
|
import type { _ViewProps } from './mpx-view'
|
|
18
19
|
|
|
@@ -83,12 +84,34 @@ const InitialValue: ExtendedViewStyle = Object.assign({
|
|
|
83
84
|
const TransformOrigin = 'transformOrigin'
|
|
84
85
|
// transform
|
|
85
86
|
const isTransform = (key: string) => Object.keys(TransformInitial).includes(key)
|
|
87
|
+
// 多value解析
|
|
88
|
+
const parseValues = (str: string, char = ' ') => {
|
|
89
|
+
let stack = 0
|
|
90
|
+
let temp = ''
|
|
91
|
+
const result = []
|
|
92
|
+
for (let i = 0; i < str.length; i++) {
|
|
93
|
+
if (str[i] === '(') {
|
|
94
|
+
stack++
|
|
95
|
+
} else if (str[i] === ')') {
|
|
96
|
+
stack--
|
|
97
|
+
}
|
|
98
|
+
// 非括号内 或者 非分隔字符且非空
|
|
99
|
+
if (stack !== 0 || (str[i] !== char && str[i] !== ' ')) {
|
|
100
|
+
temp += str[i]
|
|
101
|
+
}
|
|
102
|
+
if ((stack === 0 && str[i] === char) || i === str.length - 1) {
|
|
103
|
+
result.push(temp)
|
|
104
|
+
temp = ''
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return result
|
|
108
|
+
}
|
|
86
109
|
// parse string transform, eg: transform: 'rotateX(45deg) rotateZ(0.785398rad)'
|
|
87
110
|
const parseTransform = (transformStr: string) => {
|
|
88
|
-
const values = transformStr
|
|
111
|
+
const values = parseValues(transformStr)
|
|
89
112
|
const transform: {[propName: string]: string|number|number[]}[] = []
|
|
90
113
|
values.forEach(item => {
|
|
91
|
-
const match = item.match(/([/\w]+)\((
|
|
114
|
+
const match = item.match(/([/\w]+)\((.+)\)/)
|
|
92
115
|
if (match && match.length >= 3) {
|
|
93
116
|
let key = match[1]
|
|
94
117
|
const val = match[2]
|
|
@@ -109,7 +132,7 @@ const parseTransform = (transformStr: string) => {
|
|
|
109
132
|
break
|
|
110
133
|
case 'matrix':
|
|
111
134
|
case 'matrix3d':
|
|
112
|
-
transform.push({ [key]: val
|
|
135
|
+
transform.push({ [key]: parseValues(val, ',').map(val => +val) })
|
|
113
136
|
break
|
|
114
137
|
case 'translate':
|
|
115
138
|
case 'scale':
|
|
@@ -120,8 +143,8 @@ const parseTransform = (transformStr: string) => {
|
|
|
120
143
|
{
|
|
121
144
|
// 2 个以上的值处理
|
|
122
145
|
key = key.replace('3d', '')
|
|
123
|
-
const vals = val
|
|
124
|
-
// scale(.5) === scaleX(.5) scaleY(.5)
|
|
146
|
+
const vals = parseValues(val, ',').splice(0, key === 'rotate' ? 4 : 3)
|
|
147
|
+
// scale(.5) === scaleX(.5) scaleY(.5)
|
|
125
148
|
if (vals.length === 1 && key === 'scale') {
|
|
126
149
|
vals.push(vals[0])
|
|
127
150
|
}
|
|
@@ -144,20 +167,32 @@ const formatStyle = (style: ExtendedViewStyle): ExtendedViewStyle => {
|
|
|
144
167
|
})
|
|
145
168
|
}
|
|
146
169
|
|
|
147
|
-
export default function useAnimationHooks<T, P> (props: _ViewProps) {
|
|
148
|
-
const { style = {}, animation } = props
|
|
170
|
+
export default function useAnimationHooks<T, P> (props: _ViewProps & { enableAnimation?: boolean }) {
|
|
171
|
+
const { style = {}, animation, enableAnimation } = props
|
|
172
|
+
|
|
173
|
+
const enableStyleAnimation = enableAnimation || !!animation
|
|
174
|
+
const enableAnimationRef = useRef(enableStyleAnimation)
|
|
175
|
+
if (enableAnimationRef.current !== enableStyleAnimation) {
|
|
176
|
+
error('[Mpx runtime error]: animation use should be stable in the component lifecycle, or you can set [enable-animation] with true.')
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (!enableAnimationRef.current) return { enableStyleAnimation: false }
|
|
180
|
+
|
|
149
181
|
const originalStyle = formatStyle(style)
|
|
150
182
|
// id 标识
|
|
151
183
|
const id = animation?.id || -1
|
|
152
184
|
// 有动画样式的 style key
|
|
185
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
153
186
|
const animatedStyleKeys = useSharedValue([] as (string|string[])[])
|
|
154
187
|
// 记录动画key的style样式值 没有的话设置为false
|
|
188
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
155
189
|
const animatedKeys = useRef({} as {[propName: keyof ExtendedViewStyle]: boolean})
|
|
156
190
|
// const animatedKeys = useRef({} as {[propName: keyof ExtendedViewStyle]: boolean|number|string})
|
|
157
191
|
// ** 全量 style prop sharedValue
|
|
158
192
|
// 不能做增量的原因:
|
|
159
193
|
// 1 尝试用 useRef,但 useAnimatedStyle 访问后的 ref 不能在增加新的值,被冻结
|
|
160
194
|
// 2 尝试用 useSharedValue,因为实际触发的 style prop 需要是 sharedValue 才能驱动动画,若外层 shareValMap 也是 sharedValue,动画无法驱动。
|
|
195
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
161
196
|
const shareValMap = useMemo(() => {
|
|
162
197
|
return Object.keys(InitialValue).reduce((valMap, key) => {
|
|
163
198
|
const defaultVal = getInitialVal(key, isTransform(key))
|
|
@@ -166,6 +201,7 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
|
|
|
166
201
|
}, {} as { [propName: keyof ExtendedViewStyle]: SharedValue<string|number> })
|
|
167
202
|
}, [])
|
|
168
203
|
// ** 获取动画样式prop & 驱动动画
|
|
204
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
169
205
|
useEffect(() => {
|
|
170
206
|
if (id === -1) return
|
|
171
207
|
// 更新动画样式 key map
|
|
@@ -186,6 +222,7 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
|
|
|
186
222
|
// })
|
|
187
223
|
// }, [style])
|
|
188
224
|
// ** 清空动画
|
|
225
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
189
226
|
useEffect(() => {
|
|
190
227
|
return () => {
|
|
191
228
|
Object.values(shareValMap).forEach((value) => {
|
|
@@ -218,12 +255,14 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
|
|
|
218
255
|
}
|
|
219
256
|
// 添加每个key的多次step动画
|
|
220
257
|
animatedKeys.forEach(key => {
|
|
221
|
-
|
|
258
|
+
const ruleV = isTransform(key) ? transform.get(key) : rules.get(key)
|
|
222
259
|
// key不存在,第一轮取shareValMap[key]value,非第一轮取上一轮的
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
260
|
+
const toVal = ruleV !== undefined
|
|
261
|
+
? ruleV
|
|
262
|
+
: index > 0
|
|
263
|
+
? lastValueMap[key]
|
|
264
|
+
: shareValMap[key].value
|
|
265
|
+
const animation = getAnimation({ key, value: toVal! }, { delay, duration, easing }, needSetCallback ? setTransformOrigin : undefined)
|
|
227
266
|
needSetCallback = false
|
|
228
267
|
if (!sequence[key]) {
|
|
229
268
|
sequence[key] = [animation]
|
|
@@ -231,7 +270,7 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
|
|
|
231
270
|
sequence[key].push(animation)
|
|
232
271
|
}
|
|
233
272
|
// 更新一下 lastValueMap
|
|
234
|
-
lastValueMap[key] = toVal
|
|
273
|
+
lastValueMap[key] = toVal!
|
|
235
274
|
})
|
|
236
275
|
// 赋值驱动动画
|
|
237
276
|
animatedKeys.forEach((key) => {
|
|
@@ -311,7 +350,8 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
|
|
|
311
350
|
}, {} as { [propName: string]: string | number })
|
|
312
351
|
}
|
|
313
352
|
// ** 生成动画样式
|
|
314
|
-
|
|
353
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
354
|
+
const animationStyle = useAnimatedStyle(() => {
|
|
315
355
|
// console.info(`useAnimatedStyle styles=`, originalStyle)
|
|
316
356
|
return animatedStyleKeys.value.reduce((styles, key) => {
|
|
317
357
|
// console.info('getAnimationStyles', key, shareValMap[key].value)
|
|
@@ -327,6 +367,11 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
|
|
|
327
367
|
styles[key] = shareValMap[key].value
|
|
328
368
|
}
|
|
329
369
|
return styles
|
|
330
|
-
},
|
|
370
|
+
}, {} as ExtendedViewStyle)
|
|
331
371
|
})
|
|
372
|
+
|
|
373
|
+
return {
|
|
374
|
+
enableStyleAnimation: enableAnimationRef.current,
|
|
375
|
+
animationStyle
|
|
376
|
+
}
|
|
332
377
|
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { useEffect, useCallback, useMemo, useRef, ReactNode, ReactElement, isValidElement, useContext, useState, Dispatch, SetStateAction, Children, cloneElement } from 'react'
|
|
2
|
-
import { LayoutChangeEvent, TextStyle, ImageProps, Image } from 'react-native'
|
|
3
|
-
import { isObject, isFunction, isNumber, hasOwn, diffAndCloneA, error, warn
|
|
4
|
-
import { VarContext } from './context'
|
|
2
|
+
import { LayoutChangeEvent, TextStyle, ImageProps, Image, Platform } from 'react-native'
|
|
3
|
+
import { isObject, isFunction, isNumber, hasOwn, diffAndCloneA, error, warn } from '@mpxjs/utils'
|
|
4
|
+
import { VarContext, ScrollViewContext } from './context'
|
|
5
5
|
import { ExpressionParser, parseFunc, ReplaceSource } from './parser'
|
|
6
6
|
import { initialWindowMetrics } from 'react-native-safe-area-context'
|
|
7
|
+
import { useNavigation } from '@react-navigation/native'
|
|
7
8
|
import FastImage, { FastImageProps } from '@d11/react-native-fast-image'
|
|
8
|
-
import type { AnyFunc, ExtendedFunctionComponent } from './types/common'
|
|
9
|
+
import type { AnyFunc, ExtendedFunctionComponent, ExtendedViewStyle } from './types/common'
|
|
10
|
+
import { runOnJS } from 'react-native-reanimated'
|
|
11
|
+
import { Gesture } from 'react-native-gesture-handler'
|
|
9
12
|
|
|
10
13
|
export const TEXT_STYLE_REGEX = /color|font.*|text.*|letterSpacing|lineHeight|includeFontPadding|writingDirection/
|
|
11
14
|
export const PERCENT_REGEX = /^\s*-?\d+(\.\d+)?%\s*$/
|
|
@@ -18,8 +21,15 @@ export const HIDDEN_STYLE = {
|
|
|
18
21
|
opacity: 0
|
|
19
22
|
}
|
|
20
23
|
|
|
21
|
-
const
|
|
24
|
+
declare const __mpx_mode__: 'ios' | 'android'
|
|
25
|
+
|
|
26
|
+
export const isIOS = __mpx_mode__ === 'ios'
|
|
27
|
+
export const isAndroid = __mpx_mode__ === 'android'
|
|
28
|
+
|
|
29
|
+
const varDecRegExp = /^--/
|
|
22
30
|
const varUseRegExp = /var\(/
|
|
31
|
+
const unoVarDecRegExp = /^--un-/
|
|
32
|
+
const unoVarUseRegExp = /var\(--un-/
|
|
23
33
|
const calcUseRegExp = /calc\(/
|
|
24
34
|
const envUseRegExp = /env\(/
|
|
25
35
|
|
|
@@ -30,14 +40,13 @@ const safeAreaInsetMap: Record<string, 'top' | 'right' | 'bottom' | 'left'> = {
|
|
|
30
40
|
'safe-area-inset-left': 'left'
|
|
31
41
|
}
|
|
32
42
|
|
|
33
|
-
function getSafeAreaInset (name: string) {
|
|
34
|
-
const navigation = getFocusedNavigation()
|
|
43
|
+
function getSafeAreaInset (name: string, navigation: Record<string, any>) {
|
|
35
44
|
const insets = extendObject({}, initialWindowMetrics?.insets, navigation?.insets)
|
|
36
45
|
return insets[safeAreaInsetMap[name]]
|
|
37
46
|
}
|
|
38
47
|
|
|
39
48
|
export function omit<T, K extends string> (obj: T, fields: K[]): Omit<T, K> {
|
|
40
|
-
const shallowCopy: any =
|
|
49
|
+
const shallowCopy: any = extendObject({}, obj)
|
|
41
50
|
for (let i = 0; i < fields.length; i += 1) {
|
|
42
51
|
const key = fields[i]
|
|
43
52
|
delete shallowCopy[key]
|
|
@@ -77,7 +86,7 @@ export const parseInlineStyle = (inlineStyle = ''): Record<string, string> => {
|
|
|
77
86
|
const [k, v, ...rest] = style.split(':')
|
|
78
87
|
if (rest.length || !v || !k) return styleObj
|
|
79
88
|
const key = k.trim().replace(/-./g, c => c.substring(1).toUpperCase())
|
|
80
|
-
return
|
|
89
|
+
return extendObject(styleObj, { [key]: global.__formatValue(v.trim()) })
|
|
81
90
|
}, {})
|
|
82
91
|
}
|
|
83
92
|
|
|
@@ -230,7 +239,7 @@ function transformVar (styleObj: Record<string, any>, varKeyPaths: Array<Array<s
|
|
|
230
239
|
})
|
|
231
240
|
}
|
|
232
241
|
|
|
233
|
-
function transformEnv (styleObj: Record<string, any>, envKeyPaths: Array<Array<string
|
|
242
|
+
function transformEnv (styleObj: Record<string, any>, envKeyPaths: Array<Array<string>>, navigation: Record<string, any>) {
|
|
234
243
|
envKeyPaths.forEach((envKeyPath) => {
|
|
235
244
|
setStyle(styleObj, envKeyPath, ({ target, key, value }) => {
|
|
236
245
|
const parsed = parseFunc(value, 'env')
|
|
@@ -238,7 +247,7 @@ function transformEnv (styleObj: Record<string, any>, envKeyPaths: Array<Array<s
|
|
|
238
247
|
parsed.forEach(({ start, end, args }) => {
|
|
239
248
|
const name = args[0]
|
|
240
249
|
const fallback = args[1] || ''
|
|
241
|
-
const value = '' + (getSafeAreaInset(name) ?? global.__formatValue(fallback))
|
|
250
|
+
const value = '' + (getSafeAreaInset(name, navigation) ?? global.__formatValue(fallback))
|
|
242
251
|
replaced.replace(start, end - 1, value)
|
|
243
252
|
})
|
|
244
253
|
target[key] = global.__formatValue(replaced.source())
|
|
@@ -286,20 +295,27 @@ interface TransformStyleConfig {
|
|
|
286
295
|
|
|
287
296
|
export function useTransformStyle (styleObj: Record<string, any> = {}, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }: TransformStyleConfig) {
|
|
288
297
|
const varStyle: Record<string, any> = {}
|
|
298
|
+
const unoVarStyle: Record<string, any> = {}
|
|
289
299
|
const normalStyle: Record<string, any> = {}
|
|
300
|
+
const normalStyleRef = useRef<Record<string, any>>({})
|
|
301
|
+
const normalStyleChangedRef = useRef(false)
|
|
290
302
|
let hasVarDec = false
|
|
291
303
|
let hasVarUse = false
|
|
292
304
|
let hasSelfPercent = false
|
|
293
305
|
const varKeyPaths: Array<Array<string>> = []
|
|
306
|
+
const unoVarKeyPaths: Array<Array<string>> = []
|
|
294
307
|
const percentKeyPaths: Array<Array<string>> = []
|
|
295
308
|
const calcKeyPaths: Array<Array<string>> = []
|
|
296
309
|
const envKeyPaths: Array<Array<string>> = []
|
|
297
310
|
const [width, setWidth] = useState(0)
|
|
298
311
|
const [height, setHeight] = useState(0)
|
|
312
|
+
const navigation = useNavigation()
|
|
299
313
|
|
|
300
314
|
function varVisitor ({ key, value, keyPath }: VisitorArg) {
|
|
301
315
|
if (keyPath.length === 1) {
|
|
302
|
-
if (
|
|
316
|
+
if (unoVarDecRegExp.test(key)) {
|
|
317
|
+
unoVarStyle[key] = value
|
|
318
|
+
} else if (varDecRegExp.test(key)) {
|
|
303
319
|
hasVarDec = true
|
|
304
320
|
varStyle[key] = value
|
|
305
321
|
} else {
|
|
@@ -308,25 +324,32 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { enableV
|
|
|
308
324
|
}
|
|
309
325
|
}
|
|
310
326
|
// 对于var定义中使用的var无需替换值,可以通过resolveVar递归解析出值
|
|
311
|
-
if (!varDecRegExp.test(key)
|
|
312
|
-
|
|
313
|
-
|
|
327
|
+
if (!varDecRegExp.test(key)) {
|
|
328
|
+
// 一般情况下一个样式属性中不会混用unocss var和普通css var,可分开进行互斥处理
|
|
329
|
+
if (unoVarUseRegExp.test(value)) {
|
|
330
|
+
unoVarKeyPaths.push(keyPath.slice())
|
|
331
|
+
} else if (varUseRegExp.test(value)) {
|
|
332
|
+
hasVarUse = true
|
|
333
|
+
varKeyPaths.push(keyPath.slice())
|
|
334
|
+
}
|
|
314
335
|
}
|
|
315
336
|
}
|
|
316
337
|
|
|
317
|
-
// traverse var
|
|
338
|
+
// traverse var & generate normalStyle
|
|
318
339
|
traverseStyle(styleObj, [varVisitor])
|
|
340
|
+
|
|
319
341
|
hasVarDec = hasVarDec || !!externalVarContext
|
|
320
342
|
enableVar = enableVar || hasVarDec || hasVarUse
|
|
321
343
|
const enableVarRef = useRef(enableVar)
|
|
322
344
|
if (enableVarRef.current !== enableVar) {
|
|
323
345
|
error('css variable use/declare should be stable in the component lifecycle, or you can set [enable-var] with true.')
|
|
324
346
|
}
|
|
325
|
-
// apply var
|
|
347
|
+
// apply css var
|
|
326
348
|
const varContextRef = useRef({})
|
|
327
349
|
if (enableVarRef.current) {
|
|
350
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
328
351
|
const varContext = useContext(VarContext)
|
|
329
|
-
const newVarContext =
|
|
352
|
+
const newVarContext = extendObject({}, varContext, externalVarContext, varStyle)
|
|
330
353
|
// 缓存比较newVarContext是否发生变化
|
|
331
354
|
if (diffAndCloneA(varContextRef.current, newVarContext).diff) {
|
|
332
355
|
varContextRef.current = newVarContext
|
|
@@ -334,70 +357,86 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { enableV
|
|
|
334
357
|
transformVar(normalStyle, varKeyPaths, varContextRef.current)
|
|
335
358
|
}
|
|
336
359
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
360
|
+
// apply unocss var
|
|
361
|
+
if (unoVarKeyPaths.length) {
|
|
362
|
+
transformVar(normalStyle, unoVarKeyPaths, unoVarStyle)
|
|
341
363
|
}
|
|
342
364
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
365
|
+
const { clone, diff } = diffAndCloneA(normalStyle, normalStyleRef.current)
|
|
366
|
+
if (diff) {
|
|
367
|
+
normalStyleRef.current = clone
|
|
368
|
+
normalStyleChangedRef.current = !normalStyleChangedRef.current
|
|
347
369
|
}
|
|
348
370
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
371
|
+
const memoResult = useMemo(() => {
|
|
372
|
+
// transform can be memoized
|
|
373
|
+
function envVisitor ({ value, keyPath }: VisitorArg) {
|
|
374
|
+
if (envUseRegExp.test(value)) {
|
|
375
|
+
envKeyPaths.push(keyPath.slice())
|
|
376
|
+
}
|
|
355
377
|
}
|
|
356
|
-
}
|
|
357
378
|
|
|
358
|
-
|
|
359
|
-
|
|
379
|
+
function calcVisitor ({ value, keyPath }: VisitorArg) {
|
|
380
|
+
if (calcUseRegExp.test(value)) {
|
|
381
|
+
calcKeyPaths.push(keyPath.slice())
|
|
382
|
+
}
|
|
383
|
+
}
|
|
360
384
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
385
|
+
function percentVisitor ({ key, value, keyPath }: VisitorArg) {
|
|
386
|
+
if (hasOwn(selfPercentRule, key) && PERCENT_REGEX.test(value)) {
|
|
387
|
+
hasSelfPercent = true
|
|
388
|
+
percentKeyPaths.push(keyPath.slice())
|
|
389
|
+
} else if ((key === 'fontSize' || key === 'lineHeight') && PERCENT_REGEX.test(value)) {
|
|
390
|
+
percentKeyPaths.push(keyPath.slice())
|
|
391
|
+
}
|
|
392
|
+
}
|
|
369
393
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
394
|
+
// traverse env & calc & percent
|
|
395
|
+
traverseStyle(normalStyle, [envVisitor, percentVisitor, calcVisitor])
|
|
396
|
+
|
|
397
|
+
const percentConfig = {
|
|
398
|
+
width,
|
|
399
|
+
height,
|
|
400
|
+
fontSize: normalStyle.fontSize,
|
|
401
|
+
parentWidth,
|
|
402
|
+
parentHeight,
|
|
403
|
+
parentFontSize
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// apply env
|
|
407
|
+
transformEnv(normalStyle, envKeyPaths, navigation)
|
|
408
|
+
// apply percent
|
|
409
|
+
transformPercent(normalStyle, percentKeyPaths, percentConfig)
|
|
410
|
+
// apply calc
|
|
411
|
+
transformCalc(normalStyle, calcKeyPaths, (value: string, key: string) => {
|
|
412
|
+
if (PERCENT_REGEX.test(value)) {
|
|
413
|
+
const resolved = resolvePercent(value, key, percentConfig)
|
|
414
|
+
return typeof resolved === 'number' ? resolved : 0
|
|
383
415
|
} else {
|
|
384
|
-
|
|
385
|
-
|
|
416
|
+
const formatted = global.__formatValue(value)
|
|
417
|
+
if (typeof formatted === 'number') {
|
|
418
|
+
return formatted
|
|
419
|
+
} else {
|
|
420
|
+
warn('calc() only support number, px, rpx, % temporarily.')
|
|
421
|
+
return 0
|
|
422
|
+
}
|
|
386
423
|
}
|
|
424
|
+
})
|
|
425
|
+
// transform number enum stringify
|
|
426
|
+
transformStringify(normalStyle)
|
|
427
|
+
|
|
428
|
+
return {
|
|
429
|
+
normalStyle,
|
|
430
|
+
hasSelfPercent
|
|
387
431
|
}
|
|
388
|
-
})
|
|
389
|
-
// transform number enum stringify
|
|
390
|
-
transformStringify(normalStyle)
|
|
432
|
+
}, [normalStyleChangedRef.current, width, height, parentWidth, parentHeight, parentFontSize])
|
|
391
433
|
|
|
392
|
-
return {
|
|
393
|
-
normalStyle,
|
|
394
|
-
hasSelfPercent,
|
|
434
|
+
return extendObject({
|
|
395
435
|
hasVarDec,
|
|
396
|
-
enableVarRef,
|
|
397
436
|
varContextRef,
|
|
398
437
|
setWidth,
|
|
399
438
|
setHeight
|
|
400
|
-
}
|
|
439
|
+
}, memoResult)
|
|
401
440
|
}
|
|
402
441
|
|
|
403
442
|
export interface VisitorArg {
|
|
@@ -477,7 +516,7 @@ interface LayoutConfig {
|
|
|
477
516
|
export const useLayout = ({ props, hasSelfPercent, setWidth, setHeight, onLayout, nodeRef }: LayoutConfig) => {
|
|
478
517
|
const layoutRef = useRef({})
|
|
479
518
|
const hasLayoutRef = useRef(false)
|
|
480
|
-
const layoutStyle
|
|
519
|
+
const layoutStyle = useMemo(() => { return !hasLayoutRef.current && hasSelfPercent ? HIDDEN_STYLE : {} }, [hasLayoutRef.current])
|
|
481
520
|
const layoutProps: Record<string, any> = {}
|
|
482
521
|
const enableOffset = props['enable-offset']
|
|
483
522
|
if (hasSelfPercent || onLayout || enableOffset) {
|
|
@@ -534,13 +573,14 @@ export const debounce = <T extends AnyFunc> (
|
|
|
534
573
|
): ((...args: Parameters<T>) => void) & { clear: () => void } => {
|
|
535
574
|
let timer: any
|
|
536
575
|
const wrapper = (...args: ReadonlyArray<any>) => {
|
|
537
|
-
clearTimeout(timer)
|
|
576
|
+
timer && clearTimeout(timer)
|
|
538
577
|
timer = setTimeout(() => {
|
|
539
578
|
func(...args)
|
|
540
579
|
}, delay)
|
|
541
580
|
}
|
|
542
581
|
wrapper.clear = () => {
|
|
543
|
-
clearTimeout(timer)
|
|
582
|
+
timer && clearTimeout(timer)
|
|
583
|
+
timer = null
|
|
544
584
|
}
|
|
545
585
|
return wrapper
|
|
546
586
|
}
|
|
@@ -564,8 +604,8 @@ export const useStableCallback = <T extends AnyFunc | null | undefined> (
|
|
|
564
604
|
)
|
|
565
605
|
}
|
|
566
606
|
|
|
567
|
-
export
|
|
568
|
-
const ref = useRef<T | undefined>(
|
|
607
|
+
export function usePrevious<T> (value: T): T | undefined {
|
|
608
|
+
const ref = useRef<T | undefined>()
|
|
569
609
|
const prev = ref.current
|
|
570
610
|
ref.current = value
|
|
571
611
|
return prev
|
|
@@ -610,3 +650,67 @@ export function pickStyle (styleObj: Record<string, any> = {}, pickedKeys: Array
|
|
|
610
650
|
return acc
|
|
611
651
|
}, {})
|
|
612
652
|
}
|
|
653
|
+
|
|
654
|
+
export function useHover ({ enableHover, hoverStartTime, hoverStayTime, disabled } : { enableHover: boolean, hoverStartTime: number, hoverStayTime: number, disabled?: boolean }) {
|
|
655
|
+
const enableHoverRef = useRef(enableHover)
|
|
656
|
+
if (enableHoverRef.current !== enableHover) {
|
|
657
|
+
error('[Mpx runtime error]: hover-class use should be stable in the component lifecycle.')
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
if (!enableHoverRef.current) return { isHover: false }
|
|
661
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
662
|
+
const gestureRef = useContext(ScrollViewContext).gestureRef
|
|
663
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
664
|
+
const [isHover, setIsHover] = useState(false)
|
|
665
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
666
|
+
const dataRef = useRef<{
|
|
667
|
+
startTimer?: ReturnType<typeof setTimeout>
|
|
668
|
+
stayTimer?: ReturnType<typeof setTimeout>
|
|
669
|
+
}>({})
|
|
670
|
+
|
|
671
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
672
|
+
useEffect(() => {
|
|
673
|
+
return () => {
|
|
674
|
+
dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer)
|
|
675
|
+
dataRef.current.stayTimer && clearTimeout(dataRef.current.stayTimer)
|
|
676
|
+
}
|
|
677
|
+
}, [])
|
|
678
|
+
|
|
679
|
+
const setStartTimer = () => {
|
|
680
|
+
if (disabled) return
|
|
681
|
+
dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer)
|
|
682
|
+
dataRef.current.startTimer = setTimeout(() => {
|
|
683
|
+
setIsHover(true)
|
|
684
|
+
}, +hoverStartTime)
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
const setStayTimer = () => {
|
|
688
|
+
if (disabled) return
|
|
689
|
+
dataRef.current.stayTimer && clearTimeout(dataRef.current.stayTimer)
|
|
690
|
+
dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer)
|
|
691
|
+
dataRef.current.stayTimer = setTimeout(() => {
|
|
692
|
+
setIsHover(false)
|
|
693
|
+
}, +hoverStayTime)
|
|
694
|
+
}
|
|
695
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
696
|
+
const gesture = useMemo(() => {
|
|
697
|
+
return Gesture.Pan()
|
|
698
|
+
.onTouchesDown(() => {
|
|
699
|
+
'worklet'
|
|
700
|
+
runOnJS(setStartTimer)()
|
|
701
|
+
})
|
|
702
|
+
.onTouchesUp(() => {
|
|
703
|
+
'worklet'
|
|
704
|
+
runOnJS(setStayTimer)()
|
|
705
|
+
})
|
|
706
|
+
}, [])
|
|
707
|
+
|
|
708
|
+
if (gestureRef) {
|
|
709
|
+
gesture.simultaneousWithExternalGesture(gestureRef)
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
return {
|
|
713
|
+
isHover,
|
|
714
|
+
gesture
|
|
715
|
+
}
|
|
716
|
+
}
|