@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,8 @@
|
|
|
7
7
|
import { View, StyleSheet, Image } from 'react-native';
|
|
8
8
|
import { useRef, useState, useEffect, forwardRef } from 'react';
|
|
9
9
|
import useInnerProps from './getInnerListeners';
|
|
10
|
+
import Animated from 'react-native-reanimated';
|
|
11
|
+
import useAnimationHooks from './useAnimationHooks';
|
|
10
12
|
import useNodesRef from './useNodesRef';
|
|
11
13
|
import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout } from './utils';
|
|
12
14
|
import LinearGradient from 'react-native-linear-gradient';
|
|
@@ -39,6 +41,16 @@ const applyHandlers = (handlers, args) => {
|
|
|
39
41
|
handler(...args);
|
|
40
42
|
}
|
|
41
43
|
};
|
|
44
|
+
const normalizeStyle = (style = {}) => {
|
|
45
|
+
['backgroundSize', 'backgroundPosition'].forEach(name => {
|
|
46
|
+
if (style[name] && typeof style[name] === 'string') {
|
|
47
|
+
if (style[name].trim()) {
|
|
48
|
+
style[name] = style[name].split(' ');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
return style;
|
|
53
|
+
};
|
|
42
54
|
const isPercent = (val) => typeof val === 'string' && PERCENT_REGEX.test(val);
|
|
43
55
|
const isBackgroundSizeKeyword = (val) => typeof val === 'string' && /^cover|contain$/.test(val);
|
|
44
56
|
const isNeedLayout = (preImageInfo) => {
|
|
@@ -405,7 +417,7 @@ function normalizeBackgroundSize(backgroundSize, type) {
|
|
|
405
417
|
return sizeList;
|
|
406
418
|
}
|
|
407
419
|
function preParseImage(imageStyle) {
|
|
408
|
-
const { backgroundImage = '', backgroundSize = ['auto'], backgroundPosition = [0, 0] } = imageStyle || {};
|
|
420
|
+
const { backgroundImage = '', backgroundSize = ['auto'], backgroundPosition = [0, 0] } = normalizeStyle(imageStyle) || {};
|
|
409
421
|
const { type, src, linearInfo } = parseBgImage(backgroundImage);
|
|
410
422
|
return {
|
|
411
423
|
src,
|
|
@@ -487,8 +499,8 @@ function wrapImage(imageStyle) {
|
|
|
487
499
|
};
|
|
488
500
|
setImageSizeWidth(sizeInfo.current.width);
|
|
489
501
|
setImageSizeHeight(sizeInfo.current.height);
|
|
490
|
-
setShow(true);
|
|
491
502
|
}
|
|
503
|
+
setShow(true);
|
|
492
504
|
}
|
|
493
505
|
else if (sizeInfo.current) {
|
|
494
506
|
setLayoutInfoWidth(width);
|
|
@@ -498,7 +510,7 @@ function wrapImage(imageStyle) {
|
|
|
498
510
|
setShow(true);
|
|
499
511
|
}
|
|
500
512
|
};
|
|
501
|
-
return <View key='backgroundImage' {...needLayout ? { onLayout } : null} style={{ ...StyleSheet.absoluteFillObject,
|
|
513
|
+
return <View key='backgroundImage' {...needLayout ? { onLayout } : null} style={{ ...StyleSheet.absoluteFillObject, overflow: 'hidden' }}>
|
|
502
514
|
{show && type === 'linear' && <LinearGradient useAngle={true} {...imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current)}/>}
|
|
503
515
|
{show && type === 'image' && <Image {...imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current)}/>}
|
|
504
516
|
</View>;
|
|
@@ -517,7 +529,7 @@ function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backg
|
|
|
517
529
|
}
|
|
518
530
|
const _View = forwardRef((viewProps, ref) => {
|
|
519
531
|
const { textProps, innerProps: props = {} } = splitProps(viewProps);
|
|
520
|
-
let { style = {}, 'hover-style': hoverStyle, 'hover-start-time': hoverStartTime = 50, 'hover-stay-time': hoverStayTime = 400, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'enable-background': enableBackground, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
|
|
532
|
+
let { style = {}, 'hover-style': hoverStyle, 'hover-start-time': hoverStartTime = 50, 'hover-stay-time': hoverStayTime = 400, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'enable-background': enableBackground, 'enable-animation': enableAnimation, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, animation } = props;
|
|
521
533
|
const [isHover, setIsHover] = useState(false);
|
|
522
534
|
// 默认样式
|
|
523
535
|
const defaultStyle = {
|
|
@@ -547,7 +559,8 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
547
559
|
if (enableBackgroundRef.current !== enableBackground) {
|
|
548
560
|
throw new Error('[Mpx runtime error]: background use should be stable in the component lifecycle, or you can set [enable-background] with true.');
|
|
549
561
|
}
|
|
550
|
-
const
|
|
562
|
+
const nodeRef = useRef(null);
|
|
563
|
+
useNodesRef(props, ref, nodeRef, {
|
|
551
564
|
defaultStyle
|
|
552
565
|
});
|
|
553
566
|
const dataRef = useRef({});
|
|
@@ -581,9 +594,10 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
581
594
|
setStayTimer();
|
|
582
595
|
}
|
|
583
596
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
|
|
597
|
+
const viewStyle = Object.assign({}, innerStyle, layoutStyle);
|
|
584
598
|
const innerProps = useInnerProps(props, {
|
|
585
599
|
ref: nodeRef,
|
|
586
|
-
style:
|
|
600
|
+
style: viewStyle,
|
|
587
601
|
...layoutProps,
|
|
588
602
|
...(hoverStyle && {
|
|
589
603
|
bindtouchstart: onTouchStart,
|
|
@@ -597,15 +611,31 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
597
611
|
], {
|
|
598
612
|
layoutRef
|
|
599
613
|
});
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
614
|
+
enableAnimation = enableAnimation || !!animation;
|
|
615
|
+
const enableAnimationRef = useRef(enableAnimation);
|
|
616
|
+
if (enableAnimationRef.current !== enableAnimation) {
|
|
617
|
+
throw new Error('[Mpx runtime error]: animation use should be stable in the component lifecycle, or you can set [enable-animation] with true.');
|
|
618
|
+
}
|
|
619
|
+
const finalStyle = enableAnimation
|
|
620
|
+
? useAnimationHooks({
|
|
621
|
+
animation,
|
|
622
|
+
style: viewStyle
|
|
623
|
+
})
|
|
624
|
+
: viewStyle;
|
|
625
|
+
const childNode = wrapWithChildren(props, {
|
|
626
|
+
hasVarDec,
|
|
627
|
+
enableBackground: enableBackgroundRef.current,
|
|
628
|
+
textStyle,
|
|
629
|
+
backgroundStyle,
|
|
630
|
+
varContext: varContextRef.current,
|
|
631
|
+
textProps
|
|
632
|
+
});
|
|
633
|
+
return animation?.actions?.length
|
|
634
|
+
? (<Animated.View {...innerProps} style={finalStyle}>
|
|
635
|
+
{childNode}
|
|
636
|
+
</Animated.View>)
|
|
637
|
+
: (<View {...innerProps}>
|
|
638
|
+
{childNode}
|
|
609
639
|
</View>);
|
|
610
640
|
});
|
|
611
641
|
_View.displayName = 'mpx-view';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { forwardRef, useEffect } from 'react';
|
|
1
|
+
import { forwardRef, 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';
|
|
@@ -6,7 +6,7 @@ import { promisify, redirectTo, navigateTo, navigateBack, reLaunch, switchTab }
|
|
|
6
6
|
import { WebView } from 'react-native-webview';
|
|
7
7
|
import useNodesRef from './useNodesRef';
|
|
8
8
|
const _WebView = forwardRef((props, ref) => {
|
|
9
|
-
const { src, bindmessage = noop, bindload = noop, binderror = noop } = props;
|
|
9
|
+
const { src = '', bindmessage = noop, bindload = noop, binderror = noop } = props;
|
|
10
10
|
if (props.style) {
|
|
11
11
|
warn('The web-view component does not support the style prop.');
|
|
12
12
|
}
|
|
@@ -17,7 +17,8 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
17
17
|
top: 0,
|
|
18
18
|
bottom: 0
|
|
19
19
|
};
|
|
20
|
-
const
|
|
20
|
+
const webViewRef = useRef(null);
|
|
21
|
+
useNodesRef(props, ref, webViewRef, {
|
|
21
22
|
defaultStyle: defaultWebViewStyle
|
|
22
23
|
});
|
|
23
24
|
const _messageList = [];
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { Easing, useSharedValue, withTiming, useAnimatedStyle, withSequence, withDelay, makeMutable, cancelAnimation } from 'react-native-reanimated';
|
|
3
|
+
// 微信 timingFunction 和 RN Easing 对应关系
|
|
4
|
+
const EasingKey = {
|
|
5
|
+
linear: Easing.linear,
|
|
6
|
+
ease: Easing.ease,
|
|
7
|
+
'ease-in': Easing.in(Easing.ease),
|
|
8
|
+
'ease-in-out': Easing.inOut(Easing.ease),
|
|
9
|
+
'ease-out': Easing.out(Easing.ease)
|
|
10
|
+
// 'step-start': '',
|
|
11
|
+
// 'step-end': ''
|
|
12
|
+
};
|
|
13
|
+
const TransformInitial = {
|
|
14
|
+
// matrix: 0,
|
|
15
|
+
// matrix3d: 0,
|
|
16
|
+
rotate: '0deg',
|
|
17
|
+
rotateX: '0deg',
|
|
18
|
+
rotateY: '0deg',
|
|
19
|
+
rotateZ: '0deg',
|
|
20
|
+
// rotate3d:[0,0,0]
|
|
21
|
+
scale: 1,
|
|
22
|
+
// scale3d: [1, 1, 1],
|
|
23
|
+
scaleX: 1,
|
|
24
|
+
scaleY: 1,
|
|
25
|
+
// scaleZ: 1,
|
|
26
|
+
skew: 0,
|
|
27
|
+
skewX: '0deg',
|
|
28
|
+
skewY: '0deg',
|
|
29
|
+
translate: 0,
|
|
30
|
+
// translate3d: 0,
|
|
31
|
+
translateX: 0,
|
|
32
|
+
translateY: 0
|
|
33
|
+
// translateZ: 0,
|
|
34
|
+
};
|
|
35
|
+
// 动画默认初始值
|
|
36
|
+
const InitialValue = Object.assign({
|
|
37
|
+
opacity: 1,
|
|
38
|
+
backgroundColor: 'transparent',
|
|
39
|
+
width: 0,
|
|
40
|
+
height: 0,
|
|
41
|
+
top: 0,
|
|
42
|
+
right: 0,
|
|
43
|
+
bottom: 0,
|
|
44
|
+
left: 0,
|
|
45
|
+
transformOrigin: ['50%', '50%', 0]
|
|
46
|
+
}, TransformInitial);
|
|
47
|
+
const TransformOrigin = 'transformOrigin';
|
|
48
|
+
// deg 角度
|
|
49
|
+
// const isDeg = (key: RuleKey) => ['rotateX', 'rotateY', 'rotateZ', 'rotate', 'skewX', 'skewY'].includes(key)
|
|
50
|
+
// 背景色
|
|
51
|
+
// const isBg = (key: RuleKey) => key === 'backgroundColor'
|
|
52
|
+
// transform
|
|
53
|
+
const isTransform = (key) => Object.keys(TransformInitial).includes(key);
|
|
54
|
+
export default function useAnimationHooks(props) {
|
|
55
|
+
const { style: originalStyle = {}, animation } = props;
|
|
56
|
+
// id 标识
|
|
57
|
+
const id = animation?.id || -1;
|
|
58
|
+
// 有动画样式的 style key
|
|
59
|
+
const animatedStyleKeys = useSharedValue([]);
|
|
60
|
+
const animatedKeys = useRef({});
|
|
61
|
+
// ** 全量 style prop sharedValue
|
|
62
|
+
// 不能做增量的原因:
|
|
63
|
+
// 1 尝试用 useRef,但 useAnimatedStyle 访问后的 ref 不能在增加新的值,被冻结
|
|
64
|
+
// 2 尝试用 useSharedValue,因为实际触发的 style prop 需要是 sharedValue 才能驱动动画,若外层 shareValMap 也是 sharedValue,动画无法驱动。
|
|
65
|
+
const shareValMap = useMemo(() => {
|
|
66
|
+
return Object.keys(InitialValue).reduce((valMap, key) => {
|
|
67
|
+
const defaultVal = getInitialVal(key, isTransform(key));
|
|
68
|
+
valMap[key] = makeMutable(defaultVal);
|
|
69
|
+
return valMap;
|
|
70
|
+
}, {});
|
|
71
|
+
}, []);
|
|
72
|
+
// ** 获取动画样式prop & 驱动动画
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (id === -1)
|
|
75
|
+
return;
|
|
76
|
+
// 更新动画样式 key map
|
|
77
|
+
animatedKeys.current = getAnimatedStyleKeys();
|
|
78
|
+
const keys = Object.keys(animatedKeys.current);
|
|
79
|
+
animatedStyleKeys.value = formatAnimatedKeys([TransformOrigin, ...keys]);
|
|
80
|
+
// 驱动动画
|
|
81
|
+
createAnimation(keys);
|
|
82
|
+
}, [id]);
|
|
83
|
+
// ** 清空动画
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
return () => {
|
|
86
|
+
Object.values(shareValMap).forEach((value) => {
|
|
87
|
+
cancelAnimation(value);
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
}, []);
|
|
91
|
+
// 根据 animation action 创建&驱动动画 key => wi
|
|
92
|
+
function createAnimation(animatedKeys = []) {
|
|
93
|
+
const actions = animation?.actions || [];
|
|
94
|
+
const sequence = {};
|
|
95
|
+
const lastValueMap = {};
|
|
96
|
+
actions.forEach(({ animatedOption, rules, transform }, index) => {
|
|
97
|
+
const { delay, duration, timingFunction, transformOrigin } = animatedOption;
|
|
98
|
+
const easing = EasingKey[timingFunction] || Easing.inOut(Easing.quad);
|
|
99
|
+
let needSetCallback = true;
|
|
100
|
+
const setTransformOrigin = (finished) => {
|
|
101
|
+
'worklet';
|
|
102
|
+
// 动画结束后设置下一次transformOrigin
|
|
103
|
+
if (finished) {
|
|
104
|
+
if (index < actions.length - 1) {
|
|
105
|
+
const transformOrigin = actions[index + 1].animatedOption?.transformOrigin;
|
|
106
|
+
transformOrigin && (shareValMap[TransformOrigin].value = transformOrigin);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
if (index === 0) {
|
|
111
|
+
// 设置当次中心
|
|
112
|
+
shareValMap[TransformOrigin].value = transformOrigin;
|
|
113
|
+
}
|
|
114
|
+
// 添加每个key的多次step动画
|
|
115
|
+
animatedKeys.forEach(key => {
|
|
116
|
+
let toVal = (rules.get(key) || transform.get(key));
|
|
117
|
+
// key不存在,第一轮取shareValMap[key]value,非第一轮取上一轮的
|
|
118
|
+
if (!toVal) {
|
|
119
|
+
toVal = index > 0 ? lastValueMap[key] : shareValMap[key].value;
|
|
120
|
+
}
|
|
121
|
+
const animation = getAnimation({ key, value: toVal }, { delay, duration, easing }, needSetCallback ? setTransformOrigin : undefined);
|
|
122
|
+
needSetCallback = false;
|
|
123
|
+
if (!sequence[key]) {
|
|
124
|
+
sequence[key] = [animation];
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
sequence[key].push(animation);
|
|
128
|
+
}
|
|
129
|
+
// 更新一下 lastValueMap
|
|
130
|
+
lastValueMap[key] = toVal;
|
|
131
|
+
});
|
|
132
|
+
// 赋值驱动动画
|
|
133
|
+
animatedKeys.forEach((key) => {
|
|
134
|
+
const animations = sequence[key];
|
|
135
|
+
shareValMap[key].value = withSequence(...animations);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// 创建单个animation
|
|
140
|
+
function getAnimation({ key, value }, { delay, duration, easing }, callback) {
|
|
141
|
+
const animation = typeof callback === 'function'
|
|
142
|
+
? withTiming(value, { duration, easing }, callback)
|
|
143
|
+
: withTiming(value, { duration, easing });
|
|
144
|
+
return delay ? withDelay(delay, animation) : animation;
|
|
145
|
+
}
|
|
146
|
+
// 获取初始值(prop style or 默认值)
|
|
147
|
+
function getInitialVal(key, isTransform = false) {
|
|
148
|
+
if (isTransform && originalStyle.transform?.length) {
|
|
149
|
+
let initialVal = InitialValue[key];
|
|
150
|
+
// 仅支持 { transform: [{rotateX: '45deg'}, {rotateZ: '0.785398rad'}] } 格式的初始样式
|
|
151
|
+
originalStyle.transform.forEach(item => {
|
|
152
|
+
if (item[key] !== undefined)
|
|
153
|
+
initialVal = item[key];
|
|
154
|
+
});
|
|
155
|
+
return initialVal;
|
|
156
|
+
}
|
|
157
|
+
return originalStyle[key] === undefined ? InitialValue[key] : originalStyle[key];
|
|
158
|
+
}
|
|
159
|
+
// 循环 animation actions 获取所有有动画的 style prop name
|
|
160
|
+
function getAnimatedStyleKeys() {
|
|
161
|
+
return (animation?.actions || []).reduce((keyMap, action) => {
|
|
162
|
+
const { rules, transform } = action;
|
|
163
|
+
const ruleArr = [...rules.keys(), ...transform.keys()];
|
|
164
|
+
ruleArr.forEach(key => {
|
|
165
|
+
if (!keyMap[key])
|
|
166
|
+
keyMap[key] = true;
|
|
167
|
+
});
|
|
168
|
+
return keyMap;
|
|
169
|
+
}, animatedKeys.current);
|
|
170
|
+
}
|
|
171
|
+
// animated key transform 格式化
|
|
172
|
+
function formatAnimatedKeys(keys = []) {
|
|
173
|
+
const animatedKeys = [];
|
|
174
|
+
const transforms = [];
|
|
175
|
+
keys.forEach(key => {
|
|
176
|
+
if (isTransform(key)) {
|
|
177
|
+
transforms.push(key);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
animatedKeys.push(key);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
if (transforms.length)
|
|
184
|
+
animatedKeys.push(transforms);
|
|
185
|
+
return animatedKeys;
|
|
186
|
+
}
|
|
187
|
+
// transform 数组转对象
|
|
188
|
+
function getTransformObj() {
|
|
189
|
+
'worklet';
|
|
190
|
+
const transforms = originalStyle.transform || [];
|
|
191
|
+
return transforms.reduce((transformObj, item) => {
|
|
192
|
+
return Object.assign(transformObj, item);
|
|
193
|
+
}, {});
|
|
194
|
+
}
|
|
195
|
+
// ** 生成动画样式
|
|
196
|
+
return useAnimatedStyle(() => {
|
|
197
|
+
// console.info(`useAnimatedStyle styles=`, originalStyle)
|
|
198
|
+
return animatedStyleKeys.value.reduce((styles, key) => {
|
|
199
|
+
// console.info('getAnimationStyles', key, shareValMap[key].value)
|
|
200
|
+
if (Array.isArray(key)) {
|
|
201
|
+
const transformStyle = getTransformObj();
|
|
202
|
+
key.forEach((transformKey) => {
|
|
203
|
+
transformStyle[transformKey] = shareValMap[transformKey].value;
|
|
204
|
+
});
|
|
205
|
+
styles.transform = Object.entries(transformStyle).map(([key, value]) => {
|
|
206
|
+
return { [key]: value };
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
styles[key] = shareValMap[key].value;
|
|
211
|
+
}
|
|
212
|
+
return styles;
|
|
213
|
+
}, Object.assign({}, originalStyle));
|
|
214
|
+
});
|
|
215
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useRef, useImperativeHandle } from 'react';
|
|
2
|
-
export default function useNodesRef(props, ref, instance = {}) {
|
|
3
|
-
const nodeRef = useRef(null);
|
|
2
|
+
export default function useNodesRef(props, ref, nodeRef, instance = {}) {
|
|
4
3
|
const _props = useRef(null);
|
|
5
4
|
_props.current = props;
|
|
6
5
|
useImperativeHandle(ref, () => {
|
|
@@ -14,7 +13,4 @@ export default function useNodesRef(props, ref, instance = {}) {
|
|
|
14
13
|
}
|
|
15
14
|
};
|
|
16
15
|
});
|
|
17
|
-
return {
|
|
18
|
-
nodeRef
|
|
19
|
-
};
|
|
20
16
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useEffect, useRef, isValidElement, useContext, useState, Children, cloneElement } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { isObject, hasOwn, diffAndCloneA, error, warn } from '@mpxjs/utils';
|
|
2
|
+
import { isObject, hasOwn, diffAndCloneA, error, warn, getFocusedNavigation } from '@mpxjs/utils';
|
|
4
3
|
import { VarContext } from './context';
|
|
5
4
|
import { ExpressionParser, parseFunc, ReplaceSource } from './parser';
|
|
5
|
+
import { initialWindowMetrics } from 'react-native-safe-area-context';
|
|
6
6
|
export const TEXT_STYLE_REGEX = /color|font.*|text.*|letterSpacing|lineHeight|includeFontPadding|writingDirection/;
|
|
7
7
|
export const PERCENT_REGEX = /^\s*-?\d+(\.\d+)?%\s*$/;
|
|
8
8
|
export const URL_REGEX = /^\s*url\(["']?(.*?)["']?\)\s*$/;
|
|
@@ -12,18 +12,24 @@ export const DEFAULT_FONT_SIZE = 16;
|
|
|
12
12
|
export const DEFAULT_UNLAY_STYLE = {
|
|
13
13
|
opacity: 0
|
|
14
14
|
};
|
|
15
|
-
export function rpx(value) {
|
|
16
|
-
const { width } = Dimensions.get('screen');
|
|
17
|
-
// rn 单位 dp = 1(css)px = 1 物理像素 * pixelRatio(像素比)
|
|
18
|
-
// px = rpx * (750 / 屏幕宽度)
|
|
19
|
-
return value * width / 750;
|
|
20
|
-
}
|
|
21
|
-
const rpxRegExp = /^\s*(-?\d+(\.\d+)?)rpx\s*$/;
|
|
22
|
-
const pxRegExp = /^\s*(-?\d+(\.\d+)?)(px)?\s*$/;
|
|
23
|
-
const hairlineRegExp = /^\s*hairlineWidth\s*$/;
|
|
24
15
|
const varDecRegExp = /^--.*/;
|
|
25
16
|
const varUseRegExp = /var\(/;
|
|
26
17
|
const calcUseRegExp = /calc\(/;
|
|
18
|
+
const envUseRegExp = /env\(/;
|
|
19
|
+
const safeAreaInsetMap = {
|
|
20
|
+
'safe-area-inset-top': 'top',
|
|
21
|
+
'safe-area-inset-right': 'right',
|
|
22
|
+
'safe-area-inset-bottom': 'bottom',
|
|
23
|
+
'safe-area-inset-left': 'left'
|
|
24
|
+
};
|
|
25
|
+
function getSafeAreaInset(name) {
|
|
26
|
+
const navigation = getFocusedNavigation();
|
|
27
|
+
const insets = {
|
|
28
|
+
...initialWindowMetrics?.insets,
|
|
29
|
+
...navigation?.insets
|
|
30
|
+
};
|
|
31
|
+
return insets[safeAreaInsetMap[name]];
|
|
32
|
+
}
|
|
27
33
|
export function omit(obj, fields) {
|
|
28
34
|
const shallowCopy = Object.assign({}, obj);
|
|
29
35
|
for (let i = 0; i < fields.length; i += 1) {
|
|
@@ -81,7 +87,8 @@ export const getRestProps = (transferProps = {}, originProps = {}, deletePropsKe
|
|
|
81
87
|
export function isText(ele) {
|
|
82
88
|
if (isValidElement(ele)) {
|
|
83
89
|
const displayName = ele.type?.displayName;
|
|
84
|
-
|
|
90
|
+
const isCustomText = ele.type?.isCustomText;
|
|
91
|
+
return displayName === 'mpx-text' || displayName === 'Text' || !!isCustomText;
|
|
85
92
|
}
|
|
86
93
|
return false;
|
|
87
94
|
}
|
|
@@ -131,20 +138,6 @@ const parentHeightPercentRule = {
|
|
|
131
138
|
top: true,
|
|
132
139
|
bottom: true
|
|
133
140
|
};
|
|
134
|
-
// todo calc时处理角度和时间等单位
|
|
135
|
-
function formatValue(value) {
|
|
136
|
-
let matched;
|
|
137
|
-
if ((matched = pxRegExp.exec(value))) {
|
|
138
|
-
return +matched[1];
|
|
139
|
-
}
|
|
140
|
-
else if ((matched = rpxRegExp.exec(value))) {
|
|
141
|
-
return rpx(+matched[1]);
|
|
142
|
-
}
|
|
143
|
-
else if (hairlineRegExp.test(value)) {
|
|
144
|
-
return StyleSheet.hairlineWidth;
|
|
145
|
-
}
|
|
146
|
-
return value;
|
|
147
|
-
}
|
|
148
141
|
function resolvePercent(value, key, percentConfig) {
|
|
149
142
|
if (!(typeof value === 'string' && PERCENT_REGEX.test(value)))
|
|
150
143
|
return value;
|
|
@@ -196,11 +189,11 @@ function resolveVar(input, varContext) {
|
|
|
196
189
|
varValue = '' + resolveVar(varValue, varContext);
|
|
197
190
|
}
|
|
198
191
|
else {
|
|
199
|
-
varValue = '' +
|
|
192
|
+
varValue = '' + global.__formatValue(varValue);
|
|
200
193
|
}
|
|
201
194
|
replaced.replace(start, end - 1, varValue);
|
|
202
195
|
});
|
|
203
|
-
return
|
|
196
|
+
return global.__formatValue(replaced.source());
|
|
204
197
|
}
|
|
205
198
|
function transformVar(styleObj, varKeyPaths, varContext) {
|
|
206
199
|
varKeyPaths.forEach((varKeyPath) => {
|
|
@@ -209,6 +202,21 @@ function transformVar(styleObj, varKeyPaths, varContext) {
|
|
|
209
202
|
});
|
|
210
203
|
});
|
|
211
204
|
}
|
|
205
|
+
function transformEnv(styleObj, envKeyPaths) {
|
|
206
|
+
envKeyPaths.forEach((envKeyPath) => {
|
|
207
|
+
setStyle(styleObj, envKeyPath, ({ target, key, value }) => {
|
|
208
|
+
const parsed = parseFunc(value, 'env');
|
|
209
|
+
const replaced = new ReplaceSource(value);
|
|
210
|
+
parsed.forEach(({ start, end, args }) => {
|
|
211
|
+
const name = args[0];
|
|
212
|
+
const fallback = args[1] || '';
|
|
213
|
+
const value = '' + (getSafeAreaInset(name) ?? global.__formatValue(fallback));
|
|
214
|
+
replaced.replace(start, end - 1, value);
|
|
215
|
+
});
|
|
216
|
+
target[key] = global.__formatValue(replaced.source());
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
}
|
|
212
220
|
function transformCalc(styleObj, calcKeyPaths, formatter) {
|
|
213
221
|
calcKeyPaths.forEach((calcKeyPath) => {
|
|
214
222
|
setStyle(styleObj, calcKeyPath, ({ target, key, value }) => {
|
|
@@ -226,7 +234,7 @@ function transformCalc(styleObj, calcKeyPaths, formatter) {
|
|
|
226
234
|
error(`calc(${exp}) parse error.`, undefined, e);
|
|
227
235
|
}
|
|
228
236
|
});
|
|
229
|
-
target[key] =
|
|
237
|
+
target[key] = global.__formatValue(replaced.source());
|
|
230
238
|
});
|
|
231
239
|
});
|
|
232
240
|
}
|
|
@@ -239,6 +247,7 @@ export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext
|
|
|
239
247
|
const varKeyPaths = [];
|
|
240
248
|
const percentKeyPaths = [];
|
|
241
249
|
const calcKeyPaths = [];
|
|
250
|
+
const envKeyPaths = [];
|
|
242
251
|
const [width, setWidth] = useState(0);
|
|
243
252
|
const [height, setHeight] = useState(0);
|
|
244
253
|
function varVisitor({ key, value, keyPath }) {
|
|
@@ -277,6 +286,11 @@ export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext
|
|
|
277
286
|
}
|
|
278
287
|
transformVar(normalStyle, varKeyPaths, varContextRef.current);
|
|
279
288
|
}
|
|
289
|
+
function envVisitor({ value, keyPath }) {
|
|
290
|
+
if (envUseRegExp.test(value)) {
|
|
291
|
+
envKeyPaths.push(keyPath.slice());
|
|
292
|
+
}
|
|
293
|
+
}
|
|
280
294
|
function calcVisitor({ value, keyPath }) {
|
|
281
295
|
if (calcUseRegExp.test(value)) {
|
|
282
296
|
calcKeyPaths.push(keyPath.slice());
|
|
@@ -287,12 +301,12 @@ export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext
|
|
|
287
301
|
hasSelfPercent = true;
|
|
288
302
|
percentKeyPaths.push(keyPath.slice());
|
|
289
303
|
}
|
|
290
|
-
else if (key === 'fontSize' || key === 'lineHeight') {
|
|
304
|
+
else if ((key === 'fontSize' || key === 'lineHeight') && PERCENT_REGEX.test(value)) {
|
|
291
305
|
percentKeyPaths.push(keyPath.slice());
|
|
292
306
|
}
|
|
293
307
|
}
|
|
294
|
-
// traverse calc & percent
|
|
295
|
-
traverseStyle(normalStyle, [percentVisitor, calcVisitor]);
|
|
308
|
+
// traverse env & calc & percent
|
|
309
|
+
traverseStyle(normalStyle, [envVisitor, percentVisitor, calcVisitor]);
|
|
296
310
|
const percentConfig = {
|
|
297
311
|
width,
|
|
298
312
|
height,
|
|
@@ -301,6 +315,8 @@ export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext
|
|
|
301
315
|
parentHeight,
|
|
302
316
|
parentFontSize
|
|
303
317
|
};
|
|
318
|
+
// apply env
|
|
319
|
+
transformEnv(normalStyle, envKeyPaths);
|
|
304
320
|
// apply percent
|
|
305
321
|
transformPercent(normalStyle, percentKeyPaths, percentConfig);
|
|
306
322
|
// apply calc
|
|
@@ -310,7 +326,7 @@ export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext
|
|
|
310
326
|
return typeof resolved === 'number' ? resolved : 0;
|
|
311
327
|
}
|
|
312
328
|
else {
|
|
313
|
-
const formatted =
|
|
329
|
+
const formatted = global.__formatValue(value);
|
|
314
330
|
if (typeof formatted === 'number') {
|
|
315
331
|
return formatted;
|
|
316
332
|
}
|
|
@@ -358,12 +374,9 @@ export function traverseStyle(styleObj, visitors) {
|
|
|
358
374
|
}
|
|
359
375
|
traverse(styleObj);
|
|
360
376
|
}
|
|
361
|
-
export function setStyle(styleObj, keyPath, setter
|
|
377
|
+
export function setStyle(styleObj, keyPath, setter) {
|
|
362
378
|
let target = styleObj;
|
|
363
|
-
const firstKey = keyPath[0];
|
|
364
379
|
const lastKey = keyPath[keyPath.length - 1];
|
|
365
|
-
if (needClone)
|
|
366
|
-
target[firstKey] = diffAndCloneA(target[firstKey]).clone;
|
|
367
380
|
for (let i = 0; i < keyPath.length - 1; i++) {
|
|
368
381
|
target = target[keyPath[i]];
|
|
369
382
|
if (!target)
|
|
@@ -297,7 +297,9 @@ const Button = forwardRef<HandlerRef<View, ButtonProps>, ButtonProps>((buttonPro
|
|
|
297
297
|
setHeight
|
|
298
298
|
} = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
299
299
|
|
|
300
|
-
const
|
|
300
|
+
const nodeRef = useRef(null)
|
|
301
|
+
|
|
302
|
+
useNodesRef(props, ref, nodeRef, { defaultStyle })
|
|
301
303
|
|
|
302
304
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef })
|
|
303
305
|
|
|
@@ -65,7 +65,9 @@ const CheckboxGroup = forwardRef<
|
|
|
65
65
|
setHeight
|
|
66
66
|
} = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
67
67
|
|
|
68
|
-
const
|
|
68
|
+
const nodeRef = useRef(null)
|
|
69
|
+
|
|
70
|
+
useNodesRef(props, ref, nodeRef, { defaultStyle })
|
|
69
71
|
|
|
70
72
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef })
|
|
71
73
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import {
|
|
8
8
|
JSX,
|
|
9
9
|
useState,
|
|
10
|
+
useRef,
|
|
10
11
|
forwardRef,
|
|
11
12
|
useEffect,
|
|
12
13
|
ReactNode,
|
|
@@ -141,7 +142,9 @@ const Checkbox = forwardRef<HandlerRef<View, CheckboxProps>, CheckboxProps>(
|
|
|
141
142
|
setHeight
|
|
142
143
|
} = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
143
144
|
|
|
144
|
-
const
|
|
145
|
+
const nodeRef = useRef(null)
|
|
146
|
+
|
|
147
|
+
useNodesRef(props, ref, nodeRef, {
|
|
145
148
|
defaultStyle,
|
|
146
149
|
change: onChange
|
|
147
150
|
})
|
|
@@ -51,7 +51,8 @@ const _Form = forwardRef<HandlerRef<View, FormProps>, FormProps>((fromProps: For
|
|
|
51
51
|
|
|
52
52
|
const { textStyle, innerStyle } = splitStyle(normalStyle)
|
|
53
53
|
|
|
54
|
-
const
|
|
54
|
+
const formRef = useRef(null)
|
|
55
|
+
useNodesRef(props, ref, formRef)
|
|
55
56
|
|
|
56
57
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: formRef })
|
|
57
58
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* ✔ size
|
|
4
4
|
* ✔ color
|
|
5
5
|
*/
|
|
6
|
-
import { JSX, forwardRef } from 'react'
|
|
6
|
+
import { JSX, forwardRef, useRef } from 'react'
|
|
7
7
|
import { Text, TextStyle, Image } from 'react-native'
|
|
8
8
|
import useInnerProps from './getInnerListeners'
|
|
9
9
|
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
@@ -75,7 +75,8 @@ const Icon = forwardRef<HandlerRef<Text, IconProps>, IconProps>(
|
|
|
75
75
|
setHeight
|
|
76
76
|
} = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
77
77
|
|
|
78
|
-
const
|
|
78
|
+
const nodeRef = useRef(null)
|
|
79
|
+
useNodesRef(props, ref, nodeRef, { defaultStyle })
|
|
79
80
|
|
|
80
81
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef })
|
|
81
82
|
|
|
@@ -135,7 +135,8 @@ const Image = forwardRef<HandlerRef<RNImage, ImageProps>, ImageProps>((props, re
|
|
|
135
135
|
overflow: 'hidden'
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
const
|
|
138
|
+
const nodeRef = useRef(null)
|
|
139
|
+
useNodesRef(props, ref, nodeRef, {
|
|
139
140
|
defaultStyle
|
|
140
141
|
})
|
|
141
142
|
|
|
@@ -192,7 +192,8 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
192
192
|
setHeight
|
|
193
193
|
} = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
194
194
|
|
|
195
|
-
const
|
|
195
|
+
const nodeRef = useRef(null)
|
|
196
|
+
useNodesRef(props, ref, nodeRef)
|
|
196
197
|
|
|
197
198
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef })
|
|
198
199
|
|
|
@@ -54,7 +54,8 @@ const Label = forwardRef<HandlerRef<View, LabelProps>, LabelProps>(
|
|
|
54
54
|
setHeight
|
|
55
55
|
} = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
56
56
|
|
|
57
|
-
const
|
|
57
|
+
const nodeRef = useRef(null)
|
|
58
|
+
useNodesRef(props, ref, nodeRef, { defaultStyle })
|
|
58
59
|
|
|
59
60
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef })
|
|
60
61
|
|