@mpxjs/webpack-plugin 2.9.69 → 2.9.70-alpha.1

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.
Files changed (144) hide show
  1. package/README.md +1 -1
  2. package/lib/config.js +14 -0
  3. package/lib/dependencies/AddEntryDependency.js +24 -0
  4. package/lib/dependencies/ResolveDependency.js +5 -0
  5. package/lib/index.js +38 -7
  6. package/lib/json-compiler/helper.js +3 -3
  7. package/lib/loader.js +52 -0
  8. package/lib/platform/template/wx/component-config/button.js +14 -2
  9. package/lib/platform/template/wx/component-config/image.js +4 -0
  10. package/lib/platform/template/wx/component-config/input.js +5 -1
  11. package/lib/platform/template/wx/component-config/rich-text.js +4 -0
  12. package/lib/platform/template/wx/component-config/scroll-view.js +4 -0
  13. package/lib/platform/template/wx/component-config/swiper.js +1 -1
  14. package/lib/platform/template/wx/component-config/switch.js +4 -0
  15. package/lib/platform/template/wx/component-config/text.js +4 -0
  16. package/lib/platform/template/wx/component-config/textarea.js +6 -1
  17. package/lib/platform/template/wx/component-config/view.js +4 -0
  18. package/lib/platform/template/wx/index.js +127 -1
  19. package/lib/react/processTemplate.js +3 -0
  20. package/lib/resolve-loader.js +4 -1
  21. package/lib/runtime/components/react/context.ts +4 -0
  22. package/lib/runtime/components/react/dist/context.js +5 -0
  23. package/lib/runtime/components/react/dist/event.config.js +24 -24
  24. package/lib/runtime/components/react/dist/getInnerListeners.js +183 -166
  25. package/lib/runtime/components/react/dist/locale-provider.jsx +15 -0
  26. package/lib/runtime/components/react/dist/mpx-button.jsx +39 -74
  27. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +30 -12
  28. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +13 -19
  29. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +29 -38
  30. package/lib/runtime/components/react/dist/mpx-form.jsx +16 -19
  31. package/lib/runtime/components/react/dist/mpx-icon.jsx +8 -16
  32. package/lib/runtime/components/react/dist/mpx-image.jsx +295 -0
  33. package/lib/runtime/components/react/dist/mpx-input.jsx +54 -27
  34. package/lib/runtime/components/react/dist/mpx-label.jsx +15 -22
  35. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +13 -16
  36. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +14 -14
  37. package/lib/runtime/components/react/dist/mpx-navigator.jsx +2 -4
  38. package/lib/runtime/components/react/dist/mpx-picker/date.jsx +6 -2
  39. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +5 -3
  40. package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +6 -2
  41. package/lib/runtime/components/react/dist/mpx-picker/region.jsx +6 -2
  42. package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +6 -2
  43. package/lib/runtime/components/react/dist/mpx-picker/time.jsx +10 -14
  44. package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +39 -0
  45. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +126 -112
  46. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +32 -29
  47. package/lib/runtime/components/react/dist/mpx-portal/portal-consumer.jsx +23 -0
  48. package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +124 -0
  49. package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +40 -0
  50. package/lib/runtime/components/react/dist/mpx-portal.jsx +12 -0
  51. package/lib/runtime/components/react/dist/mpx-provider.jsx +31 -0
  52. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +11 -19
  53. package/lib/runtime/components/react/dist/mpx-radio.jsx +27 -42
  54. package/lib/runtime/components/react/dist/mpx-rich-text/html.js +39 -0
  55. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +62 -0
  56. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +7 -5
  57. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +62 -47
  58. package/lib/runtime/components/react/dist/mpx-simple-text.jsx +11 -0
  59. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +28 -9
  60. package/lib/runtime/components/react/dist/mpx-swiper.jsx +613 -0
  61. package/lib/runtime/components/react/dist/mpx-switch.jsx +20 -10
  62. package/lib/runtime/components/react/dist/mpx-text.jsx +11 -10
  63. package/lib/runtime/components/react/dist/mpx-textarea.jsx +8 -3
  64. package/lib/runtime/components/react/dist/mpx-view.jsx +37 -89
  65. package/lib/runtime/components/react/dist/mpx-web-view.jsx +205 -46
  66. package/lib/runtime/components/react/dist/pickerFaces.js +12 -6
  67. package/lib/runtime/components/react/dist/pickerVIewContext.js +9 -0
  68. package/lib/runtime/components/react/dist/pickerViewMask.jsx +18 -0
  69. package/lib/runtime/components/react/dist/{pickerOverlay.jsx → pickerViewOverlay.jsx} +5 -3
  70. package/lib/runtime/components/react/dist/useAnimationHooks.js +50 -12
  71. package/lib/runtime/components/react/dist/utils.jsx +83 -28
  72. package/lib/runtime/components/react/getInnerListeners.ts +35 -28
  73. package/lib/runtime/components/react/mpx-button.tsx +55 -36
  74. package/lib/runtime/components/react/mpx-canvas/index.tsx +2 -2
  75. package/lib/runtime/components/react/mpx-checkbox-group.tsx +13 -12
  76. package/lib/runtime/components/react/mpx-checkbox.tsx +28 -28
  77. package/lib/runtime/components/react/mpx-form.tsx +10 -8
  78. package/lib/runtime/components/react/mpx-icon.tsx +10 -15
  79. package/lib/runtime/components/react/mpx-image.tsx +396 -0
  80. package/lib/runtime/components/react/mpx-input.tsx +61 -33
  81. package/lib/runtime/components/react/mpx-label.tsx +14 -13
  82. package/lib/runtime/components/react/mpx-movable-area.tsx +8 -7
  83. package/lib/runtime/components/react/mpx-movable-view.tsx +1 -1
  84. package/lib/runtime/components/react/mpx-picker/date.tsx +5 -2
  85. package/lib/runtime/components/react/mpx-picker/index.tsx +3 -2
  86. package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +5 -2
  87. package/lib/runtime/components/react/mpx-picker/region.tsx +5 -2
  88. package/lib/runtime/components/react/mpx-picker/selector.tsx +5 -2
  89. package/lib/runtime/components/react/mpx-picker/time.tsx +10 -15
  90. package/lib/runtime/components/react/mpx-picker/type.ts +48 -43
  91. package/lib/runtime/components/react/mpx-picker-view-column.tsx +4 -1
  92. package/lib/runtime/components/react/mpx-picker-view.tsx +7 -1
  93. package/lib/runtime/components/react/mpx-radio-group.tsx +11 -12
  94. package/lib/runtime/components/react/mpx-radio.tsx +26 -29
  95. package/lib/runtime/components/react/mpx-scroll-view.tsx +32 -30
  96. package/lib/runtime/components/react/mpx-simple-text.tsx +18 -0
  97. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +4 -2
  98. package/lib/runtime/components/react/mpx-swiper-item.tsx +3 -2
  99. package/lib/runtime/components/react/mpx-switch.tsx +10 -8
  100. package/lib/runtime/components/react/mpx-text.tsx +6 -2
  101. package/lib/runtime/components/react/mpx-view.tsx +37 -45
  102. package/lib/runtime/components/react/mpx-web-view.tsx +25 -15
  103. package/lib/runtime/components/react/types/global.d.ts +1 -16
  104. package/lib/runtime/components/react/utils.tsx +24 -24
  105. package/lib/runtime/components/tenon/getInnerListeners.js +334 -0
  106. package/lib/runtime/components/tenon/tenon-button.vue +309 -0
  107. package/lib/runtime/components/tenon/tenon-image.vue +66 -0
  108. package/lib/runtime/components/tenon/tenon-input.vue +171 -0
  109. package/lib/runtime/components/tenon/tenon-rich-text.vue +26 -0
  110. package/lib/runtime/components/tenon/tenon-scroll-view.vue +127 -0
  111. package/lib/runtime/components/tenon/tenon-switch.vue +96 -0
  112. package/lib/runtime/components/tenon/tenon-text.vue +70 -0
  113. package/lib/runtime/components/tenon/tenon-textarea.vue +86 -0
  114. package/lib/runtime/components/tenon/tenon-view.vue +93 -0
  115. package/lib/runtime/components/web/getInnerListeners.js +6 -6
  116. package/lib/runtime/components/web/mpx-movable-view.vue +334 -344
  117. package/lib/runtime/components/web/mpx-picker-view-column.vue +75 -75
  118. package/lib/runtime/components/web/mpx-picker.vue +382 -385
  119. package/lib/runtime/components/web/mpx-web-view.vue +162 -162
  120. package/lib/runtime/optionProcessor.js +7 -16
  121. package/lib/runtime/optionProcessor.tenon.js +84 -0
  122. package/lib/runtime/utils.js +2 -0
  123. package/lib/style-compiler/index.js +1 -1
  124. package/lib/style-compiler/plugins/hm.js +20 -0
  125. package/lib/template-compiler/bind-this.js +7 -2
  126. package/lib/template-compiler/compiler.js +67 -40
  127. package/lib/template-compiler/gen-node-react.js +2 -2
  128. package/lib/tenon/index.js +112 -0
  129. package/lib/tenon/processJSON.js +352 -0
  130. package/lib/tenon/processScript.js +198 -0
  131. package/lib/tenon/processStyles.js +21 -0
  132. package/lib/tenon/processTemplate.js +125 -0
  133. package/lib/tenon/script-helper.js +223 -0
  134. package/lib/utils/env.js +6 -1
  135. package/lib/utils/get-relative-path.js +25 -0
  136. package/package.json +7 -3
  137. package/LICENSE +0 -433
  138. package/lib/runtime/components/react/dist/mpx-image/index.jsx +0 -226
  139. package/lib/runtime/components/react/dist/mpx-image/svg.jsx +0 -7
  140. package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +0 -478
  141. package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +0 -68
  142. package/lib/runtime/components/react/dist/mpx-swiper/type.js +0 -1
  143. package/lib/runtime/components/react/mpx-image/index.tsx +0 -345
  144. package/lib/runtime/components/react/mpx-image/svg.tsx +0 -22
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { StyleSheet, View } from 'react-native';
3
+ import LinearGradient from 'react-native-linear-gradient';
4
+ const _PickerViewMask = ({ itemHeight, maskContainerStyle }) => {
5
+ return (<View style={[styles.overlayContainer, maskContainerStyle]} pointerEvents={'none'}>
6
+ <LinearGradient colors={['rgba(255,255,255,1)', 'rgba(255,255,255,0.5)']} style={{ flex: 1 }}/>
7
+ <View style={{ height: itemHeight }}/>
8
+ <LinearGradient colors={['rgba(255,255,255,0.5)', 'rgba(255,255,255,1)']} style={{ flex: 1 }}/>
9
+ </View>);
10
+ };
11
+ const styles = StyleSheet.create({
12
+ overlayContainer: {
13
+ ...StyleSheet.absoluteFillObject,
14
+ zIndex: 100
15
+ }
16
+ });
17
+ _PickerViewMask.displayName = 'MpxPickerViewMask';
18
+ export default _PickerViewMask;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { StyleSheet, View } from 'react-native';
3
- const Overlay = ({ itemHeight, overlayItemStyle, overlayContainerStyle }) => {
3
+ const _PickerViewOverlay = ({ itemHeight, overlayItemStyle, overlayContainerStyle }) => {
4
4
  return (<View style={[styles.overlayContainer, overlayContainerStyle]} pointerEvents={'none'}>
5
5
  <View style={[styles.selection, { height: itemHeight }, overlayItemStyle]}/>
6
6
  </View>);
@@ -9,7 +9,8 @@ const styles = StyleSheet.create({
9
9
  overlayContainer: {
10
10
  ...StyleSheet.absoluteFillObject,
11
11
  justifyContent: 'center',
12
- alignItems: 'center'
12
+ alignItems: 'center',
13
+ zIndex: 200
13
14
  },
14
15
  selection: {
15
16
  borderTopWidth: 1,
@@ -18,4 +19,5 @@ const styles = StyleSheet.create({
18
19
  alignSelf: 'stretch'
19
20
  }
20
21
  });
21
- export default React.memo(Overlay);
22
+ _PickerViewOverlay.displayName = 'MpxPickerViewOverlay';
23
+ export default _PickerViewOverlay;
@@ -1,5 +1,6 @@
1
1
  import { useEffect, useMemo, useRef } from 'react';
2
2
  import { Easing, useSharedValue, withTiming, useAnimatedStyle, withSequence, withDelay, makeMutable, cancelAnimation } from 'react-native-reanimated';
3
+ import { error } from '@mpxjs/utils';
3
4
  // 微信 timingFunction 和 RN Easing 对应关系
4
5
  const EasingKey = {
5
6
  linear: Easing.linear,
@@ -47,12 +48,35 @@ const InitialValue = Object.assign({
47
48
  const TransformOrigin = 'transformOrigin';
48
49
  // transform
49
50
  const isTransform = (key) => Object.keys(TransformInitial).includes(key);
51
+ // 多value解析
52
+ const parseValues = (str, char = ' ') => {
53
+ let stack = 0;
54
+ let temp = '';
55
+ const result = [];
56
+ for (let i = 0; i < str.length; i++) {
57
+ if (str[i] === '(') {
58
+ stack++;
59
+ }
60
+ else if (str[i] === ')') {
61
+ stack--;
62
+ }
63
+ // 非括号内 或者 非分隔字符且非空
64
+ if (stack !== 0 || (str[i] !== char && str[i] !== ' ')) {
65
+ temp += str[i];
66
+ }
67
+ if ((stack === 0 && str[i] === char) || i === str.length - 1) {
68
+ result.push(temp);
69
+ temp = '';
70
+ }
71
+ }
72
+ return result;
73
+ };
50
74
  // parse string transform, eg: transform: 'rotateX(45deg) rotateZ(0.785398rad)'
51
75
  const parseTransform = (transformStr) => {
52
- const values = transformStr.trim().split(/\s+/);
76
+ const values = parseValues(transformStr);
53
77
  const transform = [];
54
78
  values.forEach(item => {
55
- const match = item.match(/([/\w]+)\(([^)]+)\)/);
79
+ const match = item.match(/([/\w]+)\((.+)\)/);
56
80
  if (match && match.length >= 3) {
57
81
  let key = match[1];
58
82
  const val = match[2];
@@ -73,7 +97,7 @@ const parseTransform = (transformStr) => {
73
97
  break;
74
98
  case 'matrix':
75
99
  case 'matrix3d':
76
- transform.push({ [key]: val.split(',').map(val => +val) });
100
+ transform.push({ [key]: parseValues(val, ',').map(val => +val) });
77
101
  break;
78
102
  case 'translate':
79
103
  case 'scale':
@@ -84,8 +108,8 @@ const parseTransform = (transformStr) => {
84
108
  {
85
109
  // 2 个以上的值处理
86
110
  key = key.replace('3d', '');
87
- const vals = val.split(',', key === 'rotate' ? 4 : 3);
88
- // scale(.5) === scaleX(.5) scaleY(.5) 这里处理一下
111
+ const vals = parseValues(val, ',').splice(0, key === 'rotate' ? 4 : 3);
112
+ // scale(.5) === scaleX(.5) scaleY(.5)
89
113
  if (vals.length === 1 && key === 'scale') {
90
114
  vals.push(vals[0]);
91
115
  }
@@ -109,7 +133,14 @@ const formatStyle = (style) => {
109
133
  });
110
134
  };
111
135
  export default function useAnimationHooks(props) {
112
- const { style = {}, animation } = props;
136
+ const { style = {}, animation, enableAnimation } = props;
137
+ const enableStyleAnimation = enableAnimation || !!animation;
138
+ const enableAnimationRef = useRef(enableStyleAnimation);
139
+ if (enableAnimationRef.current !== enableStyleAnimation) {
140
+ error('[Mpx runtime error]: animation use should be stable in the component lifecycle, or you can set [enable-animation] with true.');
141
+ }
142
+ if (!enableStyleAnimation)
143
+ return { enableStyleAnimation };
113
144
  const originalStyle = formatStyle(style);
114
145
  // id 标识
115
146
  const id = animation?.id || -1;
@@ -183,11 +214,14 @@ export default function useAnimationHooks(props) {
183
214
  }
184
215
  // 添加每个key的多次step动画
185
216
  animatedKeys.forEach(key => {
186
- let toVal = (rules.get(key) || transform.get(key));
187
217
  // key不存在,第一轮取shareValMap[key]value,非第一轮取上一轮的
188
- if (toVal === undefined) {
189
- toVal = index > 0 ? lastValueMap[key] : shareValMap[key].value;
190
- }
218
+ const toVal = rules.get(key) !== undefined
219
+ ? rules.get(key)
220
+ : transform.get(key) !== undefined
221
+ ? transform.get(key)
222
+ : index > 0
223
+ ? lastValueMap[key]
224
+ : shareValMap[key].value;
191
225
  const animation = getAnimation({ key, value: toVal }, { delay, duration, easing }, needSetCallback ? setTransformOrigin : undefined);
192
226
  needSetCallback = false;
193
227
  if (!sequence[key]) {
@@ -281,7 +315,7 @@ export default function useAnimationHooks(props) {
281
315
  }, {});
282
316
  }
283
317
  // ** 生成动画样式
284
- return useAnimatedStyle(() => {
318
+ const animationStyle = useAnimatedStyle(() => {
285
319
  // console.info(`useAnimatedStyle styles=`, originalStyle)
286
320
  return animatedStyleKeys.value.reduce((styles, key) => {
287
321
  // console.info('getAnimationStyles', key, shareValMap[key].value)
@@ -298,6 +332,10 @@ export default function useAnimationHooks(props) {
298
332
  styles[key] = shareValMap[key].value;
299
333
  }
300
334
  return styles;
301
- }, Object.assign({}, originalStyle));
335
+ }, {});
302
336
  });
337
+ return {
338
+ enableStyleAnimation,
339
+ animationStyle
340
+ };
303
341
  }
@@ -1,19 +1,24 @@
1
1
  import { useEffect, useCallback, useMemo, useRef, isValidElement, useContext, useState, Children, cloneElement } from 'react';
2
- import { Image } from 'react-native';
3
- import { isObject, isFunction, hasOwn, diffAndCloneA, error, warn, getFocusedNavigation } from '@mpxjs/utils';
4
- import { VarContext } from './context';
2
+ import { Image, Platform } from 'react-native';
3
+ import { isObject, isFunction, isNumber, hasOwn, diffAndCloneA, error, warn, getFocusedNavigation } 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
7
  import FastImage from '@d11/react-native-fast-image';
8
+ import { runOnJS } from 'react-native-reanimated';
9
+ import { Gesture } from 'react-native-gesture-handler';
8
10
  export const TEXT_STYLE_REGEX = /color|font.*|text.*|letterSpacing|lineHeight|includeFontPadding|writingDirection/;
9
11
  export const PERCENT_REGEX = /^\s*-?\d+(\.\d+)?%\s*$/;
10
12
  export const URL_REGEX = /^\s*url\(["']?(.*?)["']?\)\s*$/;
13
+ export const SVG_REGEXP = /https?:\/\/.*\.(?:svg)/i;
11
14
  export const BACKGROUND_REGEX = /^background(Image|Size|Repeat|Position)$/;
12
- export const TEXT_PROPS_REGEX = /ellipsizeMode|numberOfLines/;
15
+ export const TEXT_PROPS_REGEX = /ellipsizeMode|numberOfLines|allowFontScaling/;
13
16
  export const DEFAULT_FONT_SIZE = 16;
14
17
  export const HIDDEN_STYLE = {
15
18
  opacity: 0
16
19
  };
20
+ export const isIOS = Platform.OS === 'ios';
21
+ export const isAndroid = Platform.OS === 'android';
17
22
  const varDecRegExp = /^--.*/;
18
23
  const varUseRegExp = /var\(/;
19
24
  const calcUseRegExp = /calc\(/;
@@ -26,10 +31,7 @@ const safeAreaInsetMap = {
26
31
  };
27
32
  function getSafeAreaInset(name) {
28
33
  const navigation = getFocusedNavigation();
29
- const insets = {
30
- ...initialWindowMetrics?.insets,
31
- ...navigation?.insets
32
- };
34
+ const insets = extendObject({}, initialWindowMetrics?.insets, navigation?.insets);
33
35
  return insets[safeAreaInsetMap[name]];
34
36
  }
35
37
  export function omit(obj, fields) {
@@ -81,23 +83,13 @@ export const parseUrl = (cssUrl = '') => {
81
83
  return match?.[1];
82
84
  };
83
85
  export const getRestProps = (transferProps = {}, originProps = {}, deletePropsKey = []) => {
84
- return {
85
- ...transferProps,
86
- ...omit(originProps, deletePropsKey)
87
- };
86
+ return extendObject({}, transferProps, omit(originProps, deletePropsKey));
88
87
  };
89
88
  export function isText(ele) {
90
89
  if (isValidElement(ele)) {
91
90
  const displayName = ele.type?.displayName;
92
91
  const isCustomText = ele.type?.isCustomText;
93
- return displayName === 'MpxText' || displayName === 'Text' || !!isCustomText;
94
- }
95
- return false;
96
- }
97
- export function isEmbedded(ele) {
98
- if (isValidElement(ele)) {
99
- const displayName = ele.type?.displayName || '';
100
- return ['mpx-checkbox', 'mpx-radio', 'mpx-switch'].includes(displayName);
92
+ return displayName === 'MpxText' || displayName === 'MpxSimpleText' || displayName === 'Text' || !!isCustomText;
101
93
  }
102
94
  return false;
103
95
  }
@@ -240,6 +232,14 @@ function transformCalc(styleObj, calcKeyPaths, formatter) {
240
232
  });
241
233
  });
242
234
  }
235
+ const stringifyProps = ['fontWeight'];
236
+ function transformStringify(styleObj) {
237
+ stringifyProps.forEach((prop) => {
238
+ if (isNumber(styleObj[prop])) {
239
+ styleObj[prop] = '' + styleObj[prop];
240
+ }
241
+ });
242
+ }
243
243
  export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }) {
244
244
  const varStyle = {};
245
245
  const normalStyle = {};
@@ -338,6 +338,8 @@ export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext
338
338
  }
339
339
  }
340
340
  });
341
+ // transform number enum stringify
342
+ transformStringify(normalStyle);
341
343
  return {
342
344
  normalStyle,
343
345
  hasSelfPercent,
@@ -404,7 +406,7 @@ export function splitProps(props) {
404
406
  export const useLayout = ({ props, hasSelfPercent, setWidth, setHeight, onLayout, nodeRef }) => {
405
407
  const layoutRef = useRef({});
406
408
  const hasLayoutRef = useRef(false);
407
- const layoutStyle = !hasLayoutRef.current && hasSelfPercent ? HIDDEN_STYLE : {};
409
+ const layoutStyle = useMemo(() => { return !hasLayoutRef.current && hasSelfPercent ? HIDDEN_STYLE : {}; }, [hasLayoutRef.current]);
408
410
  const layoutProps = {};
409
411
  const enableOffset = props['enable-offset'];
410
412
  if (hasSelfPercent || onLayout || enableOffset) {
@@ -435,8 +437,8 @@ export function wrapChildren(props = {}, { hasVarDec, varContext, textStyle, tex
435
437
  if (textStyle || textProps) {
436
438
  children = Children.map(children, (child) => {
437
439
  if (isText(child)) {
438
- const style = { ...textStyle, ...child.props.style };
439
- return cloneElement(child, { ...textProps, style });
440
+ const style = extendObject({}, textStyle, child.props.style);
441
+ return cloneElement(child, extendObject({}, textProps, { style }));
440
442
  }
441
443
  return child;
442
444
  });
@@ -449,13 +451,14 @@ export function wrapChildren(props = {}, { hasVarDec, varContext, textStyle, tex
449
451
  export const debounce = (func, delay) => {
450
452
  let timer;
451
453
  const wrapper = (...args) => {
452
- clearTimeout(timer);
454
+ timer && clearTimeout(timer);
453
455
  timer = setTimeout(() => {
454
456
  func(...args);
455
457
  }, delay);
456
458
  };
457
459
  wrapper.clear = () => {
458
- clearTimeout(timer);
460
+ timer && clearTimeout(timer);
461
+ timer = null;
459
462
  };
460
463
  return wrapper;
461
464
  };
@@ -483,9 +486,7 @@ export function flatGesture(gestures = []) {
483
486
  return gesture?.current ? [gesture] : [];
484
487
  })) || [];
485
488
  }
486
- export function extendObject(...args) {
487
- return Object.assign({}, ...args);
488
- }
489
+ export const extendObject = Object.assign;
489
490
  export function getCurrentPage(pageId) {
490
491
  if (!global.getCurrentPages)
491
492
  return;
@@ -504,3 +505,57 @@ export function pickStyle(styleObj = {}, pickedKeys, callback) {
504
505
  return acc;
505
506
  }, {});
506
507
  }
508
+ export function useHoverStyle({ hoverStyle, hoverStartTime, hoverStayTime, disabled }) {
509
+ const enableHoverStyle = !!hoverStyle;
510
+ const enableHoverStyleRef = useRef(enableHoverStyle);
511
+ if (enableHoverStyleRef.current !== enableHoverStyle) {
512
+ throw new Error('[Mpx runtime error]: hover-class use should be stable in the component lifecycle.');
513
+ }
514
+ if (!enableHoverStyle)
515
+ return { enableHoverStyle };
516
+ const gestureRef = useContext(ScrollViewContext).gestureRef;
517
+ const [isHover, setIsHover] = useState(false);
518
+ const dataRef = useRef({});
519
+ useEffect(() => {
520
+ return () => {
521
+ dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer);
522
+ dataRef.current.stayTimer && clearTimeout(dataRef.current.stayTimer);
523
+ };
524
+ }, []);
525
+ const setStartTimer = () => {
526
+ dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer);
527
+ dataRef.current.startTimer = setTimeout(() => {
528
+ setIsHover(true);
529
+ }, +hoverStartTime);
530
+ };
531
+ const setStayTimer = () => {
532
+ dataRef.current.stayTimer && clearTimeout(dataRef.current.stayTimer);
533
+ dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer);
534
+ dataRef.current.stayTimer = setTimeout(() => {
535
+ setIsHover(false);
536
+ }, +hoverStayTime);
537
+ };
538
+ const gesture = useMemo(() => {
539
+ return Gesture.Pan()
540
+ .onTouchesDown(() => {
541
+ 'worklet';
542
+ if (disabled)
543
+ return;
544
+ runOnJS(setStartTimer)();
545
+ })
546
+ .onTouchesUp(() => {
547
+ 'worklet';
548
+ if (disabled)
549
+ return;
550
+ runOnJS(setStayTimer)();
551
+ });
552
+ }, [disabled]);
553
+ if (gestureRef) {
554
+ gesture.simultaneousWithExternalGesture(gestureRef);
555
+ }
556
+ return {
557
+ isHover,
558
+ gesture,
559
+ enableHoverStyle
560
+ };
561
+ }
@@ -1,6 +1,6 @@
1
1
  import { useRef } from 'react'
2
- import { collectDataset } from '@mpxjs/utils'
3
- import { omit } from './utils'
2
+ import { hasOwn, collectDataset } from '@mpxjs/utils'
3
+ import { omit, extendObject } from './utils'
4
4
  import eventConfigMap from './event.config'
5
5
  import {
6
6
  Props,
@@ -29,17 +29,22 @@ const getTouchEvent = (
29
29
  } = nativeEvent
30
30
  const { id } = props
31
31
  const { layoutRef } = config
32
- return {
33
- ...event,
34
- type,
35
- timeStamp: timestamp,
36
- currentTarget: {
37
- ...(event.currentTarget || {}),
32
+
33
+ const currentTarget = extendObject(
34
+ {},
35
+ event.currentTarget,
36
+ {
38
37
  id: id || '',
39
38
  dataset: collectDataset(props),
40
39
  offsetLeft: layoutRef?.current?.offsetLeft || 0,
41
40
  offsetTop: layoutRef?.current?.offsetTop || 0
42
- },
41
+ }
42
+ )
43
+
44
+ return extendObject({}, event, {
45
+ type,
46
+ timeStamp: timestamp,
47
+ currentTarget,
43
48
  detail: {
44
49
  x: pageX,
45
50
  y: pageY
@@ -65,7 +70,7 @@ const getTouchEvent = (
65
70
  persist: event.persist,
66
71
  stopPropagation: event.stopPropagation,
67
72
  preventDefault: event.preventDefault
68
- }
73
+ })
69
74
  }
70
75
 
71
76
  export const getCustomEvent = (
@@ -74,21 +79,20 @@ export const getCustomEvent = (
74
79
  { detail = {}, layoutRef }: { detail?: Record<string, unknown>; layoutRef: LayoutRef },
75
80
  props: Props = {}
76
81
  ) => {
77
- return {
78
- ...oe,
82
+ const targetInfo = extendObject({}, oe.target, {
83
+ id: props.id || '',
84
+ dataset: collectDataset(props),
85
+ offsetLeft: layoutRef?.current?.offsetLeft || 0,
86
+ offsetTop: layoutRef?.current?.offsetTop || 0
87
+ })
88
+ return extendObject({}, oe, {
79
89
  type,
80
90
  detail,
81
- target: {
82
- ...(oe.target || {}),
83
- id: props.id || '',
84
- dataset: collectDataset(props),
85
- offsetLeft: layoutRef?.current?.offsetLeft || 0,
86
- offsetTop: layoutRef?.current?.offsetTop || 0
87
- },
91
+ target: targetInfo,
88
92
  persist: oe.persist,
89
93
  stopPropagation: oe.stopPropagation,
90
94
  preventDefault: oe.preventDefault
91
- }
95
+ })
92
96
  }
93
97
 
94
98
  const useInnerProps = (
@@ -129,10 +133,10 @@ const useInnerProps = (
129
133
  ...userRemoveProps
130
134
  ]
131
135
 
132
- propsRef.current = { ...props, ...additionalProps }
136
+ propsRef.current = extendObject({}, props, additionalProps)
133
137
 
134
138
  for (const key in eventConfigMap) {
135
- if (propsRef.current[key]) {
139
+ if (hasOwn(propsRef.current, key)) {
136
140
  eventConfig[key] = eventConfigMap[key]
137
141
  }
138
142
  }
@@ -275,9 +279,11 @@ const useInnerProps = (
275
279
 
276
280
  const events: Record<string, (e: NativeTouchEvent) => void> = {}
277
281
 
278
- const transformedEventKeys: string[] = []
282
+ let transformedEventKeys: string[] = []
279
283
  for (const key in eventConfig) {
280
- transformedEventKeys.push(...eventConfig[key])
284
+ if (propsRef.current[key]) {
285
+ transformedEventKeys = transformedEventKeys.concat(eventConfig[key])
286
+ }
281
287
  }
282
288
 
283
289
  const finalEventKeys = [...new Set(transformedEventKeys)]
@@ -290,9 +296,10 @@ const useInnerProps = (
290
296
 
291
297
  const rawEventKeys = Object.keys(eventConfig)
292
298
 
293
- return {
294
- ...events,
295
- ...omit(propsRef.current, [...rawEventKeys, ...removeProps])
296
- }
299
+ return extendObject(
300
+ {},
301
+ events,
302
+ omit(propsRef.current, [...rawEventKeys, ...removeProps])
303
+ )
297
304
  }
298
305
  export default useInnerProps
@@ -45,7 +45,7 @@ import {
45
45
  NativeSyntheticEvent
46
46
  } from 'react-native'
47
47
  import { warn } from '@mpxjs/utils'
48
- import { getCurrentPage, splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren } from './utils'
48
+ import { getCurrentPage, splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren, extendObject } from './utils'
49
49
  import useInnerProps, { getCustomEvent } from './getInnerListeners'
50
50
  import useNodesRef, { HandlerRef } from './useNodesRef'
51
51
  import { RouteContext, FormContext } from './context'
@@ -181,11 +181,14 @@ const Loading = ({ alone = false }: { alone: boolean }): JSX.Element => {
181
181
  }
182
182
  }, [])
183
183
 
184
- const loadingStyle = {
185
- ...styles.loading,
186
- transform: [{ rotate }],
187
- marginRight: alone ? 0 : 5
188
- }
184
+ const loadingStyle = extendObject(
185
+ {},
186
+ styles.loading,
187
+ {
188
+ transform: [{ rotate }],
189
+ marginRight: alone ? 0 : 5
190
+ }
191
+ )
189
192
 
190
193
  return <Animated.Image testID="loading" style={loadingStyle} source={{ uri: LOADING_IMAGE_URI }} />
191
194
  }
@@ -274,28 +277,28 @@ const Button = forwardRef<HandlerRef<View, ButtonProps>, ButtonProps>((buttonPro
274
277
  backgroundColor: plain ? 'transparent' : normalBackgroundColor
275
278
  }
276
279
 
277
- const defaultViewStyle = {
278
- ...styles.button,
279
- ...(isMiniSize && styles.buttonMini),
280
- ...viewStyle
281
- }
280
+ const defaultViewStyle = extendObject(
281
+ {},
282
+ styles.button,
283
+ isMiniSize ? styles.buttonMini : null,
284
+ viewStyle
285
+ )
282
286
 
283
- const defaultTextStyle = {
284
- ...styles.text,
285
- ...(isMiniSize && styles.textMini),
286
- color: plain ? plainTextColor : normalTextColor
287
- }
287
+ const defaultTextStyle = extendObject(
288
+ {},
289
+ styles.text,
290
+ isMiniSize ? styles.textMini : {},
291
+ { color: plain ? plainTextColor : normalTextColor }
292
+ )
288
293
 
289
- const defaultStyle = {
290
- ...defaultViewStyle,
291
- ...defaultTextStyle
292
- }
294
+ const defaultStyle = extendObject({}, defaultViewStyle, defaultTextStyle)
293
295
 
294
- const styleObj = {
295
- ...defaultStyle,
296
- ...style,
297
- ...(applyHoverEffect && hoverStyle)
298
- }
296
+ const styleObj = extendObject(
297
+ {},
298
+ defaultStyle,
299
+ style,
300
+ applyHoverEffect ? hoverStyle : {}
301
+ )
299
302
 
300
303
  const {
301
304
  hasSelfPercent,
@@ -308,11 +311,11 @@ const Button = forwardRef<HandlerRef<View, ButtonProps>, ButtonProps>((buttonPro
308
311
 
309
312
  const nodeRef = useRef(null)
310
313
 
311
- useNodesRef(props, ref, nodeRef, { defaultStyle })
314
+ useNodesRef(props, ref, nodeRef, { style: normalStyle })
312
315
 
313
316
  const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef })
314
317
 
315
- const { textStyle, backgroundStyle, innerStyle } = splitStyle(normalStyle)
318
+ const { textStyle, backgroundStyle, innerStyle = {} } = splitStyle(normalStyle)
316
319
 
317
320
  if (backgroundStyle) {
318
321
  warn('Button does not support background image-related styles!')
@@ -408,15 +411,31 @@ const Button = forwardRef<HandlerRef<View, ButtonProps>, ButtonProps>((buttonPro
408
411
 
409
412
  const innerProps = useInnerProps(
410
413
  props,
411
- {
412
- ref: nodeRef,
413
- style: { ...innerStyle, ...layoutStyle },
414
- ...layoutProps,
415
- bindtouchstart: onTouchStart,
416
- bindtouchend: onTouchEnd,
417
- bindtap: onTap
418
- },
419
- [],
414
+ extendObject(
415
+ {
416
+ ref: nodeRef,
417
+ style: extendObject({}, innerStyle, layoutStyle)
418
+ },
419
+ layoutProps,
420
+ {
421
+ bindtouchstart: (bindtouchstart || !disabled) && onTouchStart,
422
+ bindtouchend: (bindtouchend || !disabled) && onTouchEnd,
423
+ bindtap: !disabled && onTap
424
+ }
425
+ ),
426
+ [
427
+ 'disabled',
428
+ 'size',
429
+ 'type',
430
+ 'plain',
431
+ 'loading',
432
+ 'hover-class',
433
+ 'hover-style',
434
+ 'hover-start-time',
435
+ 'hover-stay-time',
436
+ 'open-type',
437
+ 'form-type'
438
+ ],
420
439
  {
421
440
  layoutRef,
422
441
  disableTap: disabled
@@ -73,7 +73,7 @@ const _Canvas = forwardRef<HandlerRef<CanvasProps & View, CanvasProps>, CanvasPr
73
73
  hasSelfPercent,
74
74
  setWidth,
75
75
  setHeight
76
- } = useTransformStyle(extendObject(style, stylesheet.container), {
76
+ } = useTransformStyle(extendObject({}, style, stylesheet.container), {
77
77
  enableVar,
78
78
  externalVarContext,
79
79
  parentFontSize,
@@ -93,7 +93,7 @@ const _Canvas = forwardRef<HandlerRef<CanvasProps & View, CanvasProps>, CanvasPr
93
93
  const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef })
94
94
  const innerProps = useInnerProps(props, {
95
95
  ref: nodeRef,
96
- style: extendObject(normalStyle, layoutStyle, { opacity: isLoaded ? 1 : 0 }),
96
+ style: extendObject({}, normalStyle, layoutStyle, { opacity: isLoaded ? 1 : 0 }),
97
97
  ...layoutProps
98
98
  }, [], {
99
99
  layoutRef
@@ -19,7 +19,7 @@ import { warn } from '@mpxjs/utils'
19
19
  import { FormContext, FormFieldValue, CheckboxGroupContext, GroupValue } from './context'
20
20
  import useInnerProps, { getCustomEvent } from './getInnerListeners'
21
21
  import useNodesRef, { HandlerRef } from './useNodesRef'
22
- import { useLayout, useTransformStyle, wrapChildren } from './utils'
22
+ import { useLayout, useTransformStyle, wrapChildren, extendObject } from './utils'
23
23
 
24
24
  export interface CheckboxGroupProps {
25
25
  name: string
@@ -64,10 +64,7 @@ const CheckboxGroup = forwardRef<
64
64
  flexWrap: 'wrap'
65
65
  }
66
66
 
67
- const styleObj = {
68
- ...defaultStyle,
69
- ...style
70
- }
67
+ const styleObj = extendObject({}, defaultStyle, style)
71
68
 
72
69
  const {
73
70
  hasSelfPercent,
@@ -80,7 +77,7 @@ const CheckboxGroup = forwardRef<
80
77
 
81
78
  const nodeRef = useRef(null)
82
79
 
83
- useNodesRef(props, ref, nodeRef, { defaultStyle })
80
+ useNodesRef(props, ref, nodeRef, { style: normalStyle })
84
81
 
85
82
  const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef })
86
83
 
@@ -119,12 +116,16 @@ const CheckboxGroup = forwardRef<
119
116
 
120
117
  const innerProps = useInnerProps(
121
118
  props,
122
- {
123
- ref: nodeRef,
124
- style: { ...normalStyle, ...layoutStyle },
125
- ...layoutProps
126
- },
127
- [],
119
+ extendObject(
120
+ {
121
+ ref: nodeRef,
122
+ style: extendObject({}, normalStyle, layoutStyle)
123
+ },
124
+ layoutProps
125
+ ),
126
+ [
127
+ 'name'
128
+ ],
128
129
  {
129
130
  layoutRef
130
131
  }