@mpxjs/webpack-plugin 2.9.62 → 2.9.65

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 (95) hide show
  1. package/lib/config.js +38 -10
  2. package/lib/index.js +1 -3
  3. package/lib/platform/style/wx/index.js +115 -66
  4. package/lib/platform/template/wx/index.js +12 -8
  5. package/lib/react/processStyles.js +1 -0
  6. package/lib/react/processTemplate.js +2 -3
  7. package/lib/react/style-helper.js +9 -7
  8. package/lib/runtime/components/react/context.ts +9 -7
  9. package/lib/runtime/components/react/dist/context.js +1 -0
  10. package/lib/runtime/components/react/dist/getInnerListeners.js +12 -1
  11. package/lib/runtime/components/react/dist/mpx-button.jsx +53 -74
  12. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +20 -18
  13. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +30 -42
  14. package/lib/runtime/components/react/dist/mpx-form.jsx +18 -15
  15. package/lib/runtime/components/react/dist/mpx-icon.jsx +15 -17
  16. package/lib/runtime/components/react/dist/mpx-image/index.jsx +36 -34
  17. package/lib/runtime/components/react/dist/mpx-image/svg.jsx +3 -1
  18. package/lib/runtime/components/react/dist/mpx-input.jsx +36 -31
  19. package/lib/runtime/components/react/dist/mpx-label.jsx +30 -37
  20. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +15 -19
  21. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +10 -9
  22. package/lib/runtime/components/react/dist/mpx-picker/date.jsx +2 -1
  23. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +11 -10
  24. package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +9 -5
  25. package/lib/runtime/components/react/dist/mpx-picker/region.jsx +13 -8
  26. package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +3 -2
  27. package/lib/runtime/components/react/dist/mpx-picker/time.jsx +22 -20
  28. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +103 -10
  29. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +149 -54
  30. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +20 -18
  31. package/lib/runtime/components/react/dist/mpx-radio.jsx +29 -43
  32. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +8 -4
  33. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +36 -27
  34. package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +141 -75
  35. package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +16 -7
  36. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +20 -11
  37. package/lib/runtime/components/react/dist/mpx-switch.jsx +18 -14
  38. package/lib/runtime/components/react/dist/mpx-text.jsx +20 -35
  39. package/lib/runtime/components/react/dist/mpx-textarea.jsx +1 -1
  40. package/lib/runtime/components/react/dist/mpx-view.jsx +296 -210
  41. package/lib/runtime/components/react/dist/mpx-web-view.jsx +11 -7
  42. package/lib/runtime/components/react/dist/parser.js +218 -0
  43. package/lib/runtime/components/react/dist/useNodesRef.js +1 -5
  44. package/lib/runtime/components/react/dist/utils.jsx +445 -0
  45. package/lib/runtime/components/react/getInnerListeners.ts +18 -8
  46. package/lib/runtime/components/react/mpx-button.tsx +83 -91
  47. package/lib/runtime/components/react/mpx-checkbox-group.tsx +50 -43
  48. package/lib/runtime/components/react/mpx-checkbox.tsx +56 -64
  49. package/lib/runtime/components/react/mpx-form.tsx +51 -22
  50. package/lib/runtime/components/react/mpx-icon.tsx +31 -27
  51. package/lib/runtime/components/react/mpx-image/index.tsx +54 -47
  52. package/lib/runtime/components/react/mpx-image/svg.tsx +5 -3
  53. package/lib/runtime/components/react/mpx-input.tsx +59 -38
  54. package/lib/runtime/components/react/mpx-label.tsx +55 -59
  55. package/lib/runtime/components/react/mpx-movable-area.tsx +40 -25
  56. package/lib/runtime/components/react/mpx-movable-view.tsx +29 -29
  57. package/lib/runtime/components/react/mpx-navigator.tsx +2 -2
  58. package/lib/runtime/components/react/mpx-picker/date.tsx +4 -4
  59. package/lib/runtime/components/react/mpx-picker/index.tsx +12 -11
  60. package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +17 -13
  61. package/lib/runtime/components/react/mpx-picker/region.tsx +23 -19
  62. package/lib/runtime/components/react/mpx-picker/selector.tsx +7 -7
  63. package/lib/runtime/components/react/mpx-picker/time.tsx +29 -31
  64. package/lib/runtime/components/react/mpx-picker/type.ts +1 -1
  65. package/lib/runtime/components/react/mpx-picker-view-column.tsx +149 -20
  66. package/lib/runtime/components/react/mpx-picker-view.tsx +180 -63
  67. package/lib/runtime/components/react/mpx-radio-group.tsx +51 -47
  68. package/lib/runtime/components/react/mpx-radio.tsx +57 -72
  69. package/lib/runtime/components/react/mpx-root-portal.tsx +10 -8
  70. package/lib/runtime/components/react/mpx-scroll-view.tsx +136 -104
  71. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +175 -96
  72. package/lib/runtime/components/react/mpx-swiper/index.tsx +21 -9
  73. package/lib/runtime/components/react/mpx-swiper/type.ts +16 -5
  74. package/lib/runtime/components/react/mpx-swiper-item.tsx +48 -14
  75. package/lib/runtime/components/react/mpx-switch.tsx +46 -24
  76. package/lib/runtime/components/react/mpx-text.tsx +38 -45
  77. package/lib/runtime/components/react/mpx-textarea.tsx +1 -1
  78. package/lib/runtime/components/react/mpx-view.tsx +401 -241
  79. package/lib/runtime/components/react/mpx-web-view.tsx +22 -22
  80. package/lib/runtime/components/react/parser.ts +245 -0
  81. package/lib/runtime/components/react/types/common.ts +4 -4
  82. package/lib/runtime/components/react/types/global.d.ts +24 -2
  83. package/lib/runtime/components/react/useNodesRef.ts +1 -7
  84. package/lib/runtime/components/react/utils.tsx +524 -0
  85. package/lib/runtime/components/web/mpx-scroll-view.vue +25 -5
  86. package/lib/style-compiler/index.js +5 -4
  87. package/lib/template-compiler/compiler.js +133 -161
  88. package/lib/template-compiler/gen-node-react.js +1 -3
  89. package/lib/utils/const.js +2 -1
  90. package/lib/web/processStyles.js +2 -1
  91. package/lib/web/processTemplate.js +2 -3
  92. package/lib/wxml/loader.js +1 -1
  93. package/package.json +7 -4
  94. package/lib/runtime/components/react/dist/utils.js +0 -148
  95. package/lib/runtime/components/react/utils.ts +0 -170
@@ -4,26 +4,74 @@
4
4
  * ✔ hover-start-time
5
5
  * ✔ hover-stay-time
6
6
  */
7
- import { View, Text, StyleSheet, Image } from 'react-native';
7
+ import { View, StyleSheet, Image } from 'react-native';
8
8
  import { useRef, useState, useEffect, forwardRef } from 'react';
9
9
  import useInnerProps from './getInnerListeners';
10
10
  import useNodesRef from './useNodesRef';
11
- import { parseUrl, PERCENT_REGEX, isText, every, normalizeStyle, splitStyle, splitProps, throwReactWarning, transformTextStyle } from './utils';
11
+ import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout } from './utils';
12
+ import LinearGradient from 'react-native-linear-gradient';
13
+ const linearMap = new Map([
14
+ ['top', 0],
15
+ ['bottom', 180],
16
+ ['left', 270],
17
+ ['right', 90]
18
+ ]);
19
+ // 对角线角度
20
+ const diagonalAngleMap = {
21
+ 'top right': (width, height) => {
22
+ return Math.acos((width / 2) /
23
+ (Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)) / 2));
24
+ },
25
+ 'right top': (width, height) => { return diagonalAngleMap['top right'](width, height); },
26
+ 'bottom right': (width, height) => Math.PI - diagonalAngleMap['top right'](width, height),
27
+ 'right bottom': (width, height) => { return diagonalAngleMap['bottom right'](width, height); },
28
+ 'bottom left': (width, height) => Math.PI + diagonalAngleMap['top right'](width, height),
29
+ 'left bottom': (width, height) => { return diagonalAngleMap['bottom left'](width, height); },
30
+ 'top left': (width, height) => (2 * Math.PI) - diagonalAngleMap['top right'](width, height),
31
+ 'left top': (width, height) => { return diagonalAngleMap['top left'](width, height); }
32
+ };
33
+ // 弧度转化为角度的公式
34
+ function radToAngle(r) {
35
+ return r * 180 / Math.PI;
36
+ }
12
37
  const applyHandlers = (handlers, args) => {
13
- for (let handler of handlers) {
38
+ for (const handler of handlers) {
14
39
  handler(...args);
15
40
  }
16
41
  };
17
- const checkNeedLayout = (style) => {
18
- const [width, height] = style.sizeList;
19
- const bp = style.backgroundPosition;
42
+ const normalizeStyle = (style = {}) => {
43
+ ['backgroundSize', 'backgroundPosition'].forEach(name => {
44
+ if (style[name] && typeof style[name] === 'string') {
45
+ if (style[name].trim()) {
46
+ style[name] = style[name].split(' ');
47
+ }
48
+ }
49
+ });
50
+ return style;
51
+ };
52
+ const isPercent = (val) => typeof val === 'string' && PERCENT_REGEX.test(val);
53
+ const isBackgroundSizeKeyword = (val) => typeof val === 'string' && /^cover|contain$/.test(val);
54
+ const isNeedLayout = (preImageInfo) => {
55
+ const { sizeList, backgroundPosition, linearInfo } = preImageInfo;
56
+ const [width, height] = sizeList;
57
+ const bp = backgroundPosition;
20
58
  // 含有百分号,center 需计算布局
21
- const containPercentSymbol = typeof bp[1] === 'string' && PERCENT_REGEX.test(bp[1]) || typeof bp[3] === 'string' && PERCENT_REGEX.test(bp[3]);
59
+ return isBackgroundSizeKeyword(width) ||
60
+ (isPercent(height) && width === 'auto') ||
61
+ (isPercent(width) && height === 'auto') ||
62
+ isPercent(bp[1]) ||
63
+ isPercent(bp[3]) ||
64
+ isDiagonalAngle(linearInfo);
65
+ };
66
+ const checkNeedLayout = (preImageInfo) => {
67
+ const { sizeList } = preImageInfo;
68
+ const [width] = sizeList;
69
+ // 在渐变的时候,background-size的cover,contain, auto属性值,转化为100%, needLayout计算逻辑和原来保持一致,needImageSize始终为false
22
70
  return {
23
71
  // 是否开启layout的计算
24
- needLayout: typeof width === 'string' && /^cover|contain$/.test(width) || (typeof height === 'string' && PERCENT_REGEX.test(height) && width === 'auto') || (typeof width === 'string' && PERCENT_REGEX.test(width) && height === 'auto') || containPercentSymbol,
72
+ needLayout: isNeedLayout(preImageInfo),
25
73
  // 是否开启原始宽度的计算
26
- needImageSize: typeof width === 'string' && /^cover|contain$/.test(width) || style.sizeList.includes('auto')
74
+ needImageSize: isBackgroundSizeKeyword(width) || sizeList.includes('auto')
27
75
  };
28
76
  };
29
77
  /**
@@ -32,11 +80,12 @@ const checkNeedLayout = (style) => {
32
80
  * ratio - 原始图片的宽高比
33
81
  * **/
34
82
  function calculateSize(h, ratio, lh, reverse = false) {
35
- let height = 0, width = 0;
83
+ let height = 0;
84
+ let width = 0;
36
85
  if (typeof lh === 'boolean') {
37
86
  reverse = lh;
38
87
  }
39
- if (typeof h === 'string' && PERCENT_REGEX.test(h)) { // auto px/rpx
88
+ if (isPercent(h)) { // auto px/rpx
40
89
  if (!lh)
41
90
  return null;
42
91
  height = (parseFloat(h) / 100) * lh;
@@ -61,22 +110,31 @@ function calculateSizePosition(h, ch, val) {
61
110
  if (!h || !ch)
62
111
  return 0;
63
112
  // 百分比需要单独的计算
64
- if (typeof h === 'string' && PERCENT_REGEX.test(h)) {
113
+ if (isPercent(h)) {
65
114
  h = ch * parseFloat(h) / 100;
66
115
  }
67
116
  // (container width - image width) * (position x%) = (x offset value)
68
117
  return (ch - h) * parseFloat(val) / 100;
69
118
  }
119
+ /**
120
+ * 获取图片的展示宽高
121
+ * h - 用户设置的高度
122
+ * lh - 容器的高度
123
+ * **/
124
+ const calcPercent = (h, lh) => {
125
+ return isPercent(h) ? parseFloat(h) / 100 * lh : +h;
126
+ };
70
127
  function backgroundPosition(imageProps, preImageInfo, imageSize, layoutInfo) {
71
128
  const bps = preImageInfo.backgroundPosition;
72
129
  if (bps.length === 0)
73
130
  return;
74
- let style = {};
75
- let imageStyle = imageProps.style || {};
131
+ const style = {};
132
+ const imageStyle = imageProps.style || {};
76
133
  for (let i = 0; i < bps.length; i += 2) {
77
- let key = bps[i], val = bps[i + 1];
134
+ const key = bps[i];
135
+ const val = bps[i + 1];
78
136
  // 需要获取 图片宽度 和 容器的宽度 进行计算
79
- if (typeof val === 'string' && PERCENT_REGEX.test(val)) {
137
+ if (isPercent(val)) {
80
138
  if (i === 0) {
81
139
  style[key] = calculateSizePosition(imageStyle.width, layoutInfo?.width, val);
82
140
  }
@@ -95,7 +153,7 @@ function backgroundPosition(imageProps, preImageInfo, imageSize, layoutInfo) {
95
153
  }
96
154
  // background-size 转换
97
155
  function backgroundSize(imageProps, preImageInfo, imageSize, layoutInfo) {
98
- let sizeList = preImageInfo.sizeList;
156
+ const sizeList = preImageInfo.sizeList;
99
157
  if (!sizeList)
100
158
  return;
101
159
  const { width: layoutWidth, height: layoutHeight } = layoutInfo || {};
@@ -105,13 +163,13 @@ function backgroundSize(imageProps, preImageInfo, imageSize, layoutInfo) {
105
163
  // 枚举值
106
164
  if (typeof width === 'string' && ['cover', 'contain'].includes(width)) {
107
165
  if (layoutInfo && imageSize) {
108
- let layoutRatio = layoutWidth / imageSizeWidth;
109
- let eleRatio = imageSizeWidth / imageSizeHeight;
166
+ const layoutRatio = layoutWidth / imageSizeWidth;
167
+ const eleRatio = imageSizeWidth / imageSizeHeight;
110
168
  // 容器宽高比 大于 图片的宽高比,依据宽度作为基准,否则以高度为基准
111
- if (layoutRatio <= eleRatio && width === 'contain' || layoutRatio >= eleRatio && width === 'cover') {
169
+ if ((layoutRatio <= eleRatio && width === 'contain') || (layoutRatio >= eleRatio && width === 'cover')) {
112
170
  dimensions = calculateSize(layoutWidth, imageSizeHeight / imageSizeWidth, true);
113
171
  }
114
- else if (layoutRatio > eleRatio && width === 'contain' || layoutRatio < eleRatio && width === 'cover') {
172
+ else if ((layoutRatio > eleRatio && width === 'contain') || (layoutRatio < eleRatio && width === 'cover')) {
115
173
  dimensions = calculateSize(layoutHeight, imageSizeWidth / imageSizeHeight);
116
174
  }
117
175
  }
@@ -143,8 +201,8 @@ function backgroundSize(imageProps, preImageInfo, imageSize, layoutInfo) {
143
201
  // 数值类型设置为 stretch
144
202
  imageProps.style.resizeMode = 'stretch';
145
203
  dimensions = {
146
- width: typeof width === 'string' && PERCENT_REGEX.test(width) ? width : +width,
147
- height: typeof height === 'string' && PERCENT_REGEX.test(height) ? height : +height
204
+ width: isPercent(width) ? width : +width,
205
+ height: isPercent(height) ? height : +height
148
206
  };
149
207
  }
150
208
  }
@@ -156,7 +214,27 @@ function backgroundSize(imageProps, preImageInfo, imageSize, layoutInfo) {
156
214
  }
157
215
  // background-image转换为source
158
216
  function backgroundImage(imageProps, preImageInfo) {
159
- imageProps.src = preImageInfo.src;
217
+ if (preImageInfo.src) {
218
+ imageProps.src = preImageInfo.src;
219
+ }
220
+ }
221
+ // 渐变的转换
222
+ function linearGradient(imageProps, preImageInfo, imageSize, layoutInfo) {
223
+ const { type, linearInfo } = preImageInfo;
224
+ const { colors = [], locations, direction = '' } = linearInfo || {};
225
+ const { width, height } = imageSize || {};
226
+ if (type !== 'linear')
227
+ return;
228
+ // 角度计算
229
+ let angle = +(linearMap.get(direction) || direction.match(/(-?\d+(\.\d+)?)deg/)?.[1] || 180) % 360;
230
+ // 对角线角度计算
231
+ if (layoutInfo && diagonalAngleMap[direction] && imageSize && linearInfo) {
232
+ angle = radToAngle(diagonalAngleMap[direction](width, height)) || 180;
233
+ }
234
+ // 赋值
235
+ imageProps.colors = colors;
236
+ imageProps.locations = locations;
237
+ imageProps.angle = angle;
160
238
  }
161
239
  const imageStyleToProps = (preImageInfo, imageSize, layoutInfo) => {
162
240
  // 初始化
@@ -165,11 +243,10 @@ const imageStyleToProps = (preImageInfo, imageSize, layoutInfo) => {
165
243
  resizeMode: 'cover',
166
244
  position: 'absolute'
167
245
  // ...StyleSheet.absoluteFillObject
168
- }
246
+ },
247
+ colors: []
169
248
  };
170
- applyHandlers([backgroundSize, backgroundImage, backgroundPosition], [imageProps, preImageInfo, imageSize, layoutInfo]);
171
- if (!imageProps?.src)
172
- return null;
249
+ applyHandlers([backgroundSize, backgroundImage, backgroundPosition, linearGradient], [imageProps, preImageInfo, imageSize, layoutInfo]);
173
250
  return imageProps;
174
251
  };
175
252
  function isHorizontal(val) {
@@ -246,59 +323,162 @@ function normalizeBackgroundPosition(parts) {
246
323
  }
247
324
  return [hStart, hOffset, vStart, vOffset];
248
325
  }
326
+ /**
327
+ *
328
+ * calcSteps - 计算起始位置和终点位置之间的差值
329
+ * startVal - 起始位置距离
330
+ * endVal - 终点位置距离
331
+ * len - 数量
332
+ * **/
333
+ function calcSteps(startVal, endVal, len) {
334
+ const diffVal = endVal - startVal;
335
+ const step = diffVal / len;
336
+ const newArr = [];
337
+ for (let i = 1; i < len; i++) {
338
+ const val = startVal + step * i;
339
+ newArr.push(+val.toFixed(2));
340
+ }
341
+ return newArr;
342
+ }
343
+ function parseLinearGradient(text) {
344
+ let linearText = text.trim().match(/linear-gradient\((.*)\)/)?.[1];
345
+ if (!linearText)
346
+ return;
347
+ // 添加默认的角度
348
+ if (!/^to|^-?\d+deg/.test(linearText)) {
349
+ linearText = '180deg ,' + linearText;
350
+ }
351
+ else {
352
+ linearText = linearText.replace('to', '');
353
+ }
354
+ // 把 0deg, red 10%, blue 20% 解析为 ['0deg', 'red, 10%', 'blue, 20%']
355
+ const [direction, ...colorList] = linearText.split(/,(?![^(#]*\))/);
356
+ // 记录需要填充起点的起始位置
357
+ let startIdx = 0;
358
+ let startVal = 0;
359
+ // 把 ['red, 10%', 'blue, 20%']解析为 [[red, 10%], [blue, 20%]]
360
+ const linearInfo = colorList.map(item => item.trim().split(/(?<!,)\s+/))
361
+ .reduce((prev, cur, idx, self) => {
362
+ const { colors, locations } = prev;
363
+ const [color, val] = cur;
364
+ let numberVal = parseFloat(val) / 100;
365
+ // 处理渐变默认值
366
+ if (idx === 0) {
367
+ numberVal = numberVal || 0;
368
+ }
369
+ else if (self.length - 1 === idx) {
370
+ numberVal = numberVal || 1;
371
+ }
372
+ // 出现缺省值时进行填充
373
+ if (idx - startIdx > 1 && !isNaN(numberVal)) {
374
+ locations.push(...calcSteps(startVal, numberVal, idx - startIdx));
375
+ }
376
+ if (!isNaN(numberVal)) {
377
+ startIdx = idx;
378
+ startVal = numberVal;
379
+ }
380
+ // 添加color的数组
381
+ colors.push(color.trim());
382
+ !isNaN(numberVal) && locations.push(numberVal);
383
+ return prev;
384
+ }, { colors: [], locations: [] });
385
+ return {
386
+ ...linearInfo,
387
+ direction: direction.trim()
388
+ };
389
+ }
390
+ function parseBgImage(text) {
391
+ if (!text)
392
+ return {};
393
+ const src = parseUrl(text);
394
+ if (src)
395
+ return { src, type: 'image' };
396
+ const linearInfo = parseLinearGradient(text);
397
+ if (!linearInfo)
398
+ return {};
399
+ return {
400
+ linearInfo,
401
+ type: 'linear'
402
+ };
403
+ }
404
+ function normalizeBackgroundSize(backgroundSize, type) {
405
+ const sizeList = backgroundSize.slice();
406
+ if (sizeList.length === 1)
407
+ sizeList.push('auto');
408
+ if (type === 'linear') {
409
+ // 处理当使用渐变的时候,background-size出现cover, contain, auto,当作100%处理
410
+ for (const i in sizeList) {
411
+ const val = sizeList[i];
412
+ sizeList[i] = /^cover|contain|auto$/.test(val) ? '100%' : val;
413
+ }
414
+ }
415
+ return sizeList;
416
+ }
249
417
  function preParseImage(imageStyle) {
250
- const { backgroundImage, backgroundSize = ['auto'], backgroundPosition = [0, 0] } = imageStyle || {};
251
- const src = parseUrl(backgroundImage);
252
- let sizeList = backgroundSize.slice();
253
- sizeList.length === 1 && sizeList.push('auto');
418
+ const { backgroundImage = '', backgroundSize = ['auto'], backgroundPosition = [0, 0] } = normalizeStyle(imageStyle) || {};
419
+ const { type, src, linearInfo } = parseBgImage(backgroundImage);
254
420
  return {
255
421
  src,
256
- sizeList,
422
+ linearInfo,
423
+ type,
424
+ sizeList: normalizeBackgroundSize(backgroundSize, type),
257
425
  backgroundPosition: normalizeBackgroundPosition(backgroundPosition)
258
426
  };
259
427
  }
428
+ function isDiagonalAngle(linearInfo) {
429
+ return !!(linearInfo?.direction && diagonalAngleMap[linearInfo.direction]);
430
+ }
260
431
  function wrapImage(imageStyle) {
261
- const [show, setShow] = useState(false);
432
+ // 预处理数据
433
+ const preImageInfo = preParseImage(imageStyle);
434
+ // 预解析
435
+ const { src, sizeList, type } = preImageInfo;
436
+ // 判断是否可挂载onLayout
437
+ const { needLayout, needImageSize } = checkNeedLayout(preImageInfo);
438
+ const [show, setShow] = useState(((type === 'image' && !!src) || type === 'linear') && !needLayout && !needImageSize);
262
439
  const [, setImageSizeWidth] = useState(null);
263
440
  const [, setImageSizeHeight] = useState(null);
264
441
  const [, setLayoutInfoWidth] = useState(null);
265
442
  const [, setLayoutInfoHeight] = useState(null);
266
443
  const sizeInfo = useRef(null);
267
444
  const layoutInfo = useRef(null);
268
- // 预解析
269
- const preImageInfo = preParseImage(imageStyle);
270
- // 判断是否可挂载onLayout
271
- const { needLayout, needImageSize } = checkNeedLayout(preImageInfo);
272
- const { src } = preImageInfo;
273
445
  useEffect(() => {
446
+ sizeInfo.current = null;
447
+ if (type === 'linear') {
448
+ if (!needLayout)
449
+ setShow(true);
450
+ return;
451
+ }
274
452
  if (!src) {
275
453
  setShow(false);
276
- sizeInfo.current = null;
277
- layoutInfo.current = null;
278
454
  return;
455
+ // 一开始未出现,数据改变时出现
279
456
  }
280
- if (!needImageSize) {
457
+ else if (!(needLayout || needImageSize)) {
281
458
  setShow(true);
282
459
  return;
283
460
  }
284
- Image.getSize(src, (width, height) => {
285
- sizeInfo.current = {
286
- width,
287
- height
288
- };
289
- //1. 当需要绑定onLayout 2. 获取到布局信息
290
- if (!needLayout || layoutInfo.current) {
291
- setImageSizeWidth(width);
292
- setImageSizeHeight(height);
293
- if (layoutInfo.current) {
294
- setLayoutInfoWidth(layoutInfo.current.width);
295
- setLayoutInfoHeight(layoutInfo.current.height);
461
+ if (needImageSize) {
462
+ Image.getSize(src, (width, height) => {
463
+ sizeInfo.current = {
464
+ width,
465
+ height
466
+ };
467
+ // 1. 当需要绑定onLayout 2. 获取到布局信息
468
+ if (!needLayout || layoutInfo.current) {
469
+ setImageSizeWidth(width);
470
+ setImageSizeHeight(height);
471
+ if (layoutInfo.current) {
472
+ setLayoutInfoWidth(layoutInfo.current.width);
473
+ setLayoutInfoHeight(layoutInfo.current.height);
474
+ }
475
+ setShow(true);
296
476
  }
297
- setShow(true);
298
- }
299
- });
300
- }, [preImageInfo?.src]);
301
- if (!preImageInfo?.src)
477
+ });
478
+ }
479
+ // type 添加type 处理无渐变 有渐变的场景
480
+ }, [src, type]);
481
+ if (!type)
302
482
  return null;
303
483
  const onLayout = (res) => {
304
484
  const { width, height } = res?.nativeEvent?.layout || {};
@@ -309,6 +489,16 @@ function wrapImage(imageStyle) {
309
489
  if (!needImageSize) {
310
490
  setLayoutInfoWidth(width);
311
491
  setLayoutInfoHeight(height);
492
+ // 有渐变角度的时候,才触发渲染组件
493
+ if (type === 'linear') {
494
+ sizeInfo.current = {
495
+ width: calcPercent(sizeList[0], width),
496
+ height: calcPercent(sizeList[1], height)
497
+ };
498
+ setImageSizeWidth(sizeInfo.current.width);
499
+ setImageSizeHeight(sizeInfo.current.height);
500
+ }
501
+ setShow(true);
312
502
  }
313
503
  else if (sizeInfo.current) {
314
504
  setLayoutInfoWidth(width);
@@ -318,92 +508,57 @@ function wrapImage(imageStyle) {
318
508
  setShow(true);
319
509
  }
320
510
  };
321
- return <View key='viewBgImg' {...needLayout ? { onLayout } : null} style={{ ...StyleSheet.absoluteFillObject, width: '100%', height: '100%', overflow: 'hidden' }}>
322
- {show && <Image {...imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current)}/>}
511
+ return <View key='backgroundImage' {...needLayout ? { onLayout } : null} style={{ ...StyleSheet.absoluteFillObject, overflow: 'hidden' }}>
512
+ {show && type === 'linear' && <LinearGradient useAngle={true} {...imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current)}/>}
513
+ {show && type === 'image' && <Image {...imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current)}/>}
323
514
  </View>;
324
515
  }
325
- function wrapChildren(children, props, textStyle, imageStyle) {
326
- const { textProps } = splitProps(props);
327
- const { 'enable-background-image': enableBackgroundImage } = props;
328
- if (every(children, (child) => isText(child))) {
329
- if (textStyle || textProps) {
330
- transformTextStyle(textStyle);
331
- children = <Text key='viewTextWrap' style={textStyle} {...(textProps || {})}>{children}</Text>;
332
- }
333
- }
334
- else {
335
- if (textStyle)
336
- throwReactWarning('[Mpx runtime warn]: Text style will be ignored unless every child of the view is Text node!');
337
- }
516
+ function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backgroundStyle, varContext, textProps }) {
517
+ const children = wrapChildren(props, {
518
+ hasVarDec,
519
+ varContext,
520
+ textStyle,
521
+ textProps
522
+ });
338
523
  return [
339
- enableBackgroundImage ? wrapImage(imageStyle) : null,
524
+ enableBackground ? wrapImage(backgroundStyle) : null,
340
525
  children
341
526
  ];
342
527
  }
343
- const _View = forwardRef((props, ref) => {
344
- const combinationStyleProps = [{
345
- key: 'transform',
346
- rules: {
347
- width: 'translateX',
348
- height: 'translateY'
349
- }
350
- }, {
351
- key: 'borderTopLeftRadius',
352
- rules: {
353
- width: 'borderTopLeftRadius'
354
- }
355
- }, {
356
- key: 'borderBottomLeftRadius',
357
- rules: {
358
- width: 'borderBottomLeftRadius'
359
- }
360
- }, {
361
- key: 'borderBottomRightRadius',
362
- rules: {
363
- height: 'borderBottomRightRadius'
364
- }
365
- }, {
366
- key: 'borderTopRightRadius',
367
- rules: {
368
- height: 'borderTopRightRadius'
369
- }
370
- }];
371
- const { style = {}, children, hoverStyle, 'hover-start-time': hoverStartTime = 50, 'hover-stay-time': hoverStayTime = 400, 'enable-offset': enableOffset, } = props;
528
+ const _View = forwardRef((viewProps, ref) => {
529
+ const { textProps, innerProps: props = {} } = splitProps(viewProps);
530
+ 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;
372
531
  const [isHover, setIsHover] = useState(false);
373
- let transformStyle = {};
374
- const [containerWidth, setContainerWidth] = useState(0);
375
- const [containerHeight, setContainerHeight] = useState(0);
376
- const layoutRef = useRef({});
377
- // 打平 style 数组
378
- const styleObj = normalizeStyle(style);
379
532
  // 默认样式
380
533
  const defaultStyle = {
381
534
  // flex 布局相关的默认样式
382
- ...styleObj.display === 'flex' && {
535
+ ...style.display === 'flex' && {
383
536
  flexDirection: 'row',
384
537
  flexBasis: 'auto',
385
538
  flexShrink: 1,
386
539
  flexWrap: 'nowrap'
387
540
  }
388
541
  };
389
- const hasPercentStyle = combinationStyleProps.some(({ key, rules }) => {
390
- return Object.entries(rules).some(([dimension, transformKey]) => {
391
- const transformItemValue = styleObj[key];
392
- if (transformItemValue) {
393
- if (Array.isArray(transformItemValue)) {
394
- const transformValue = transformItemValue.find((item) => item.hasOwnProperty(transformKey));
395
- return transformValue && PERCENT_REGEX.test(transformValue[transformKey]);
396
- }
397
- else if (typeof transformItemValue === 'string') {
398
- return PERCENT_REGEX.test(transformItemValue);
399
- }
400
- }
401
- });
542
+ const styleObj = {
543
+ ...defaultStyle,
544
+ ...style,
545
+ ...(isHover ? hoverStyle : null)
546
+ };
547
+ const { normalStyle, hasSelfPercent, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, {
548
+ enableVar,
549
+ externalVarContext,
550
+ parentFontSize,
551
+ parentWidth,
552
+ parentHeight
402
553
  });
403
- if (hasPercentStyle) {
404
- transformStyle = percentTransform(combinationStyleProps, { width: containerWidth, height: containerHeight });
554
+ const { textStyle, backgroundStyle, innerStyle } = splitStyle(normalStyle);
555
+ enableBackground = enableBackground || !!backgroundStyle;
556
+ const enableBackgroundRef = useRef(enableBackground);
557
+ if (enableBackgroundRef.current !== enableBackground) {
558
+ throw new Error('[Mpx runtime error]: background use should be stable in the component lifecycle, or you can set [enable-background] with true.');
405
559
  }
406
- const { nodeRef } = useNodesRef(props, ref, {
560
+ const nodeRef = useRef(null);
561
+ useNodesRef(props, ref, nodeRef, {
407
562
  defaultStyle
408
563
  });
409
564
  const dataRef = useRef({});
@@ -436,101 +591,32 @@ const _View = forwardRef((props, ref) => {
436
591
  bindtouchend && bindtouchend(e);
437
592
  setStayTimer();
438
593
  }
439
- function percentTransform(style, { width, height }) {
440
- const styleMap = {};
441
- style.forEach((styleItem) => {
442
- const transformItemValue = styleObj[styleItem.key];
443
- if (Array.isArray(transformItemValue)) {
444
- const transformStyle = [];
445
- styleObj[styleItem.key].forEach((transformItem) => {
446
- const rules = styleItem.rules;
447
- for (const type in rules) {
448
- const value = transformItem[rules[type]];
449
- if (value !== undefined) {
450
- if (PERCENT_REGEX.test(value)) {
451
- const percentage = parseFloat(value) / 100;
452
- if (type === 'height' && height) {
453
- transformStyle.push({ [rules[type]]: percentage * height });
454
- }
455
- else if (type === 'width' && width) {
456
- transformStyle.push({ [rules[type]]: percentage * width });
457
- }
458
- else {
459
- transformStyle.push({ [rules[type]]: 0 });
460
- }
461
- }
462
- else {
463
- transformStyle.push(transformItem);
464
- }
465
- }
466
- }
467
- });
468
- styleMap[styleItem.key] = transformStyle;
469
- }
470
- else if (typeof transformItemValue === 'string') {
471
- const rules = styleItem.rules;
472
- for (const type in rules) {
473
- if (transformItemValue) {
474
- if (PERCENT_REGEX.test(transformItemValue)) {
475
- const percentage = parseFloat(transformItemValue) / 100;
476
- if (type === 'height' && height) {
477
- styleMap[styleItem.key] = percentage * height;
478
- }
479
- else if (type === 'width' && width) {
480
- styleMap[styleItem.key] = percentage * width;
481
- }
482
- else {
483
- styleMap[styleItem.key] = 0;
484
- }
485
- }
486
- else {
487
- styleMap[styleItem.key] = transformItemValue;
488
- }
489
- }
490
- }
491
- }
492
- });
493
- return styleMap;
494
- }
495
- const onLayout = (res) => {
496
- if (hasPercentStyle) {
497
- const { width, height } = res?.nativeEvent?.layout || {};
498
- setContainerWidth(width || 0);
499
- setContainerHeight(height || 0);
500
- }
501
- if (enableOffset) {
502
- nodeRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
503
- layoutRef.current = { x, y, width, height, offsetLeft, offsetTop };
504
- });
505
- }
506
- };
507
- const { textStyle, imageStyle, innerStyle } = splitStyle({
508
- ...defaultStyle,
509
- ...styleObj,
510
- ...(isHover ? hoverStyle : null)
511
- });
512
- const needLayout = enableOffset || hasPercentStyle;
594
+ const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
513
595
  const innerProps = useInnerProps(props, {
514
596
  ref: nodeRef,
515
- ...needLayout ? { onLayout } : {},
597
+ style: { ...innerStyle, ...layoutStyle },
598
+ ...layoutProps,
516
599
  ...(hoverStyle && {
517
600
  bindtouchstart: onTouchStart,
518
601
  bindtouchend: onTouchEnd
519
602
  })
520
603
  }, [
521
- 'style',
522
- 'children',
523
604
  'hover-start-time',
524
605
  'hover-stay-time',
525
- 'hoverStyle',
526
- 'hover-class',
527
- 'enable-offset',
528
- 'enable-background-image'
606
+ 'hover-style',
607
+ 'hover-class'
529
608
  ], {
530
609
  layoutRef
531
610
  });
532
- return (<View {...innerProps} style={{ ...innerStyle, ...transformStyle }}>
533
- {wrapChildren(children, props, textStyle, imageStyle)}
611
+ return (<View {...innerProps}>
612
+ {wrapWithChildren(props, {
613
+ hasVarDec,
614
+ enableBackground: enableBackgroundRef.current,
615
+ textStyle,
616
+ backgroundStyle,
617
+ varContext: varContextRef.current,
618
+ textProps
619
+ })}
534
620
  </View>);
535
621
  });
536
622
  _View.displayName = 'mpx-view';