@mpxjs/webpack-plugin 2.9.59 → 2.9.62

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 (106) hide show
  1. package/lib/platform/style/wx/index.js +314 -254
  2. package/lib/platform/template/wx/component-config/checkbox-group.js +8 -0
  3. package/lib/platform/template/wx/component-config/checkbox.js +8 -0
  4. package/lib/platform/template/wx/component-config/cover-image.js +15 -0
  5. package/lib/platform/template/wx/component-config/cover-view.js +9 -0
  6. package/lib/platform/template/wx/component-config/form.js +13 -1
  7. package/lib/platform/template/wx/component-config/icon.js +8 -0
  8. package/lib/platform/template/wx/component-config/index.js +5 -1
  9. package/lib/platform/template/wx/component-config/label.js +15 -0
  10. package/lib/platform/template/wx/component-config/movable-area.js +18 -1
  11. package/lib/platform/template/wx/component-config/movable-view.js +18 -1
  12. package/lib/platform/template/wx/component-config/navigator.js +8 -0
  13. package/lib/platform/template/wx/component-config/picker-view-column.js +8 -0
  14. package/lib/platform/template/wx/component-config/picker-view.js +18 -2
  15. package/lib/platform/template/wx/component-config/picker.js +14 -1
  16. package/lib/platform/template/wx/component-config/radio-group.js +8 -0
  17. package/lib/platform/template/wx/component-config/radio.js +8 -0
  18. package/lib/platform/template/wx/component-config/root-portal.js +15 -0
  19. package/lib/platform/template/wx/component-config/switch.js +8 -0
  20. package/lib/platform/template/wx/component-config/unsupported.js +1 -3
  21. package/lib/react/processScript.js +2 -0
  22. package/lib/runtime/components/react/context.ts +38 -0
  23. package/lib/runtime/components/react/dist/context.js +7 -0
  24. package/lib/runtime/components/react/dist/getInnerListeners.js +22 -11
  25. package/lib/runtime/components/react/dist/mpx-button.jsx +67 -45
  26. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +81 -0
  27. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +152 -0
  28. package/lib/runtime/components/react/dist/mpx-form.jsx +59 -0
  29. package/lib/runtime/components/react/dist/mpx-icon.jsx +51 -0
  30. package/lib/runtime/components/react/dist/mpx-image/index.jsx +17 -22
  31. package/lib/runtime/components/react/dist/mpx-image/svg.jsx +0 -1
  32. package/lib/runtime/components/react/dist/mpx-input.jsx +38 -16
  33. package/lib/runtime/components/react/dist/mpx-label.jsx +63 -0
  34. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +46 -0
  35. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +346 -0
  36. package/lib/runtime/components/react/dist/mpx-navigator.jsx +35 -0
  37. package/lib/runtime/components/react/dist/mpx-picker/date.jsx +69 -0
  38. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +138 -0
  39. package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +139 -0
  40. package/lib/runtime/components/react/dist/mpx-picker/region.jsx +90 -0
  41. package/lib/runtime/components/react/dist/mpx-picker/regionData.js +6099 -0
  42. package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +76 -0
  43. package/lib/runtime/components/react/dist/mpx-picker/time.jsx +244 -0
  44. package/lib/runtime/components/react/dist/mpx-picker/type.js +1 -0
  45. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +15 -0
  46. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +68 -0
  47. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +79 -0
  48. package/lib/runtime/components/react/dist/mpx-radio.jsx +169 -0
  49. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +11 -0
  50. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +66 -50
  51. package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +206 -147
  52. package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +9 -7
  53. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +3 -3
  54. package/lib/runtime/components/react/dist/mpx-switch.jsx +76 -0
  55. package/lib/runtime/components/react/dist/mpx-text.jsx +7 -19
  56. package/lib/runtime/components/react/dist/mpx-textarea.jsx +1 -1
  57. package/lib/runtime/components/react/dist/mpx-view.jsx +326 -96
  58. package/lib/runtime/components/react/dist/mpx-web-view.jsx +9 -15
  59. package/lib/runtime/components/react/dist/types/common.js +1 -0
  60. package/lib/runtime/components/react/dist/useNodesRef.js +3 -8
  61. package/lib/runtime/components/react/dist/utils.js +82 -14
  62. package/lib/runtime/components/react/getInnerListeners.ts +25 -13
  63. package/lib/runtime/components/react/mpx-button.tsx +87 -67
  64. package/lib/runtime/components/react/mpx-checkbox-group.tsx +147 -0
  65. package/lib/runtime/components/react/mpx-checkbox.tsx +245 -0
  66. package/lib/runtime/components/react/mpx-form.tsx +89 -0
  67. package/lib/runtime/components/react/mpx-icon.tsx +103 -0
  68. package/lib/runtime/components/react/mpx-image/index.tsx +20 -32
  69. package/lib/runtime/components/react/mpx-image/svg.tsx +2 -2
  70. package/lib/runtime/components/react/mpx-input.tsx +54 -26
  71. package/lib/runtime/components/react/mpx-label.tsx +115 -0
  72. package/lib/runtime/components/react/mpx-movable-area.tsx +67 -0
  73. package/lib/runtime/components/react/mpx-movable-view.tsx +425 -0
  74. package/lib/runtime/components/react/mpx-navigator.tsx +67 -0
  75. package/lib/runtime/components/react/mpx-picker/date.tsx +83 -0
  76. package/lib/runtime/components/react/mpx-picker/index.tsx +155 -0
  77. package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +153 -0
  78. package/lib/runtime/components/react/mpx-picker/region.tsx +104 -0
  79. package/lib/runtime/components/react/mpx-picker/regionData.ts +6101 -0
  80. package/lib/runtime/components/react/mpx-picker/selector.tsx +92 -0
  81. package/lib/runtime/components/react/mpx-picker/time.tsx +274 -0
  82. package/lib/runtime/components/react/mpx-picker/type.ts +107 -0
  83. package/lib/runtime/components/react/mpx-picker-view-column.tsx +28 -0
  84. package/lib/runtime/components/react/mpx-picker-view.tsx +104 -0
  85. package/lib/runtime/components/react/mpx-radio-group.tsx +147 -0
  86. package/lib/runtime/components/react/mpx-radio.tsx +246 -0
  87. package/lib/runtime/components/react/mpx-root-portal.tsx +25 -0
  88. package/lib/runtime/components/react/mpx-scroll-view.tsx +82 -58
  89. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +203 -156
  90. package/lib/runtime/components/react/mpx-swiper/index.tsx +12 -13
  91. package/lib/runtime/components/react/mpx-swiper/type.ts +11 -4
  92. package/lib/runtime/components/react/mpx-swiper-item.tsx +5 -3
  93. package/lib/runtime/components/react/mpx-switch.tsx +127 -0
  94. package/lib/runtime/components/react/mpx-text.tsx +52 -68
  95. package/lib/runtime/components/react/mpx-textarea.tsx +2 -2
  96. package/lib/runtime/components/react/mpx-view.tsx +373 -140
  97. package/lib/runtime/components/react/mpx-web-view.tsx +24 -28
  98. package/lib/runtime/components/react/types/common.ts +12 -0
  99. package/lib/runtime/components/react/types/getInnerListeners.ts +2 -1
  100. package/lib/runtime/components/react/types/global.d.ts +4 -0
  101. package/lib/runtime/components/react/useNodesRef.ts +3 -8
  102. package/lib/runtime/components/react/utils.ts +93 -15
  103. package/lib/runtime/optionProcessor.js +19 -17
  104. package/lib/template-compiler/compiler.js +56 -41
  105. package/lib/template-compiler/gen-node-react.js +7 -7
  106. package/package.json +6 -3
@@ -3,30 +3,18 @@
3
3
  * ✘ space
4
4
  * ✘ decode
5
5
  */
6
- import { Text, StyleSheet } from 'react-native';
6
+ import { Text } from 'react-native';
7
7
  import { useRef, useEffect, forwardRef } from 'react';
8
8
  import useInnerProps from './getInnerListeners';
9
- // @ts-ignore
10
9
  import useNodesRef from './useNodesRef'; // 引入辅助函数
11
- import { PERCENT_REGEX } from './utils';
12
- const DEFAULT_STYLE = {
13
- fontSize: 16
14
- };
15
- const transformStyle = (styleObj) => {
16
- let { lineHeight } = styleObj;
17
- if (typeof lineHeight === 'string' && PERCENT_REGEX.test(lineHeight)) {
18
- lineHeight = (parseFloat(lineHeight) / 100) * (styleObj.fontSize || DEFAULT_STYLE.fontSize);
19
- styleObj.lineHeight = lineHeight;
20
- }
21
- };
10
+ import { transformTextStyle, DEFAULT_STYLE } from './utils';
22
11
  const _Text = forwardRef((props, ref) => {
23
- const { style = [], children, selectable, 'enable-offset': enableOffset, 'user-select': userSelect, 'disable-default-style': disableDefaultStyle = false, } = props;
12
+ const { style = {}, children, selectable, 'enable-offset': enableOffset, 'user-select': userSelect, 'disable-default-style': disableDefaultStyle = false, } = props;
24
13
  const layoutRef = useRef({});
25
- const styleObj = StyleSheet.flatten(style);
26
14
  let defaultStyle = {};
27
15
  if (!disableDefaultStyle) {
28
16
  defaultStyle = DEFAULT_STYLE;
29
- transformStyle(styleObj);
17
+ transformTextStyle(style);
30
18
  }
31
19
  const { nodeRef } = useNodesRef(props, ref, {
32
20
  defaultStyle
@@ -59,9 +47,9 @@ const _Text = forwardRef((props, ref) => {
59
47
  };
60
48
  }
61
49
  }, []);
62
- return (<Text style={{ ...defaultStyle, ...styleObj }} selectable={!!selectable || !!userSelect} {...innerProps}>
63
- {children}
64
- </Text>);
50
+ return (<Text style={{ ...defaultStyle, ...style }} selectable={!!selectable || !!userSelect} {...innerProps}>
51
+ {children}
52
+ </Text>);
65
53
  });
66
54
  _Text.displayName = 'mpx-text';
67
55
  export default _Text;
@@ -9,7 +9,7 @@
9
9
  * ✘ show-confirm-bar
10
10
  * ✔ bindlinechange: No `heightRpx` info.
11
11
  */
12
- import React, { forwardRef } from 'react';
12
+ import { forwardRef } from 'react';
13
13
  import { Keyboard } from 'react-native';
14
14
  import Input from './mpx-input';
15
15
  import { omit } from './utils';
@@ -6,26 +6,9 @@
6
6
  */
7
7
  import { View, Text, StyleSheet, Image } from 'react-native';
8
8
  import { useRef, useState, useEffect, forwardRef } from 'react';
9
- // @ts-ignore
10
9
  import useInnerProps from './getInnerListeners';
11
- // @ts-ignore
12
- import useNodesRef from './useNodesRef'; // 引入辅助函数
13
- import { parseUrl, TEXT_STYLE_REGEX, PERCENT_REGEX, isText } from './utils';
14
- const IMAGE_STYLE_REGEX = /^background(Image|Size|Repeat|Position)$/;
15
- function groupBy(style, callback, group = {}) {
16
- let groupKey = '';
17
- for (let key in style) {
18
- if (style.hasOwnProperty(key)) { // 确保处理对象自身的属性
19
- let val = style[key];
20
- groupKey = callback(key, val);
21
- if (!group[groupKey]) {
22
- group[groupKey] = {};
23
- }
24
- group[groupKey][key] = val;
25
- }
26
- }
27
- return group;
28
- }
10
+ import useNodesRef from './useNodesRef';
11
+ import { parseUrl, PERCENT_REGEX, isText, every, normalizeStyle, splitStyle, splitProps, throwReactWarning, transformTextStyle } from './utils';
29
12
  const applyHandlers = (handlers, args) => {
30
13
  for (let handler of handlers) {
31
14
  handler(...args);
@@ -33,19 +16,30 @@ const applyHandlers = (handlers, args) => {
33
16
  };
34
17
  const checkNeedLayout = (style) => {
35
18
  const [width, height] = style.sizeList;
36
- return (PERCENT_REGEX.test(`${height}`) && width === 'auto') || (PERCENT_REGEX.test(`${width}`) && height === 'auto');
19
+ const bp = style.backgroundPosition;
20
+ // 含有百分号,center 需计算布局
21
+ const containPercentSymbol = typeof bp[1] === 'string' && PERCENT_REGEX.test(bp[1]) || typeof bp[3] === 'string' && PERCENT_REGEX.test(bp[3]);
22
+ return {
23
+ // 是否开启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,
25
+ // 是否开启原始宽度的计算
26
+ needImageSize: typeof width === 'string' && /^cover|contain$/.test(width) || style.sizeList.includes('auto')
27
+ };
37
28
  };
38
29
  /**
39
- * h - 用户设置的高度
40
- * lh - 容器的高度
41
- * ratio - 原始图片的宽高比
42
- * **/
43
- function calculateSize(h, lh, ratio) {
44
- let height, width;
45
- if (PERCENT_REGEX.test(`${h}`)) { // auto px/rpx
30
+ * h - 用户设置的高度
31
+ * lh - 容器的高度
32
+ * ratio - 原始图片的宽高比
33
+ * **/
34
+ function calculateSize(h, ratio, lh, reverse = false) {
35
+ let height = 0, width = 0;
36
+ if (typeof lh === 'boolean') {
37
+ reverse = lh;
38
+ }
39
+ if (typeof h === 'string' && PERCENT_REGEX.test(h)) { // auto px/rpx
46
40
  if (!lh)
47
41
  return null;
48
- height = (parseFloat(`${h}`) / 100) * lh;
42
+ height = (parseFloat(h) / 100) * lh;
49
43
  width = height * ratio;
50
44
  }
51
45
  else { // 2. auto px/rpx - 根据比例计算
@@ -53,8 +47,50 @@ function calculateSize(h, lh, ratio) {
53
47
  width = height * ratio;
54
48
  }
55
49
  return {
56
- width,
57
- height
50
+ width: reverse ? height : width,
51
+ height: reverse ? width : height
52
+ };
53
+ }
54
+ /**
55
+ * 用户设置百分比后,转换为偏移量
56
+ * h - 用户设置图片的高度
57
+ * ch - 容器的高度
58
+ * val - 用户设置的百分比
59
+ * **/
60
+ function calculateSizePosition(h, ch, val) {
61
+ if (!h || !ch)
62
+ return 0;
63
+ // 百分比需要单独的计算
64
+ if (typeof h === 'string' && PERCENT_REGEX.test(h)) {
65
+ h = ch * parseFloat(h) / 100;
66
+ }
67
+ // (container width - image width) * (position x%) = (x offset value)
68
+ return (ch - h) * parseFloat(val) / 100;
69
+ }
70
+ function backgroundPosition(imageProps, preImageInfo, imageSize, layoutInfo) {
71
+ const bps = preImageInfo.backgroundPosition;
72
+ if (bps.length === 0)
73
+ return;
74
+ let style = {};
75
+ let imageStyle = imageProps.style || {};
76
+ for (let i = 0; i < bps.length; i += 2) {
77
+ let key = bps[i], val = bps[i + 1];
78
+ // 需要获取 图片宽度 和 容器的宽度 进行计算
79
+ if (typeof val === 'string' && PERCENT_REGEX.test(val)) {
80
+ if (i === 0) {
81
+ style[key] = calculateSizePosition(imageStyle.width, layoutInfo?.width, val);
82
+ }
83
+ else {
84
+ style[key] = calculateSizePosition(imageStyle.height, layoutInfo?.height, val);
85
+ }
86
+ }
87
+ else {
88
+ style[key] = val;
89
+ }
90
+ }
91
+ imageProps.style = {
92
+ ...imageProps.style,
93
+ ...style
58
94
  };
59
95
  }
60
96
  // background-size 转换
@@ -62,51 +98,61 @@ function backgroundSize(imageProps, preImageInfo, imageSize, layoutInfo) {
62
98
  let sizeList = preImageInfo.sizeList;
63
99
  if (!sizeList)
64
100
  return;
101
+ const { width: layoutWidth, height: layoutHeight } = layoutInfo || {};
102
+ const { width: imageSizeWidth, height: imageSizeHeight } = imageSize || {};
103
+ const [width, height] = sizeList;
104
+ let dimensions = { width: 0, height: 0 };
65
105
  // 枚举值
66
- if (['cover', 'contain'].includes(`${sizeList[0]}`)) {
67
- imageProps.style.resizeMode = sizeList[0];
106
+ if (typeof width === 'string' && ['cover', 'contain'].includes(width)) {
107
+ if (layoutInfo && imageSize) {
108
+ let layoutRatio = layoutWidth / imageSizeWidth;
109
+ let eleRatio = imageSizeWidth / imageSizeHeight;
110
+ // 容器宽高比 大于 图片的宽高比,依据宽度作为基准,否则以高度为基准
111
+ if (layoutRatio <= eleRatio && width === 'contain' || layoutRatio >= eleRatio && width === 'cover') {
112
+ dimensions = calculateSize(layoutWidth, imageSizeHeight / imageSizeWidth, true);
113
+ }
114
+ else if (layoutRatio > eleRatio && width === 'contain' || layoutRatio < eleRatio && width === 'cover') {
115
+ dimensions = calculateSize(layoutHeight, imageSizeWidth / imageSizeHeight);
116
+ }
117
+ }
68
118
  }
69
119
  else {
70
- const [width, height] = sizeList;
71
- let newWidth = 0, newHeight = 0;
72
- const { width: imageSizeWidth, height: imageSizeHeight } = imageSize || {};
73
120
  if (width === 'auto' && height === 'auto') { // 均为auto
74
121
  if (!imageSize)
75
122
  return;
76
- newHeight = imageSizeHeight;
77
- newWidth = imageSizeWidth;
123
+ dimensions = {
124
+ width: imageSizeWidth,
125
+ height: imageSizeHeight
126
+ };
78
127
  }
79
128
  else if (width === 'auto') { // auto px/rpx/%
80
129
  if (!imageSize)
81
130
  return;
82
- const dimensions = calculateSize(height, layoutInfo?.height, imageSizeWidth / imageSizeHeight);
131
+ dimensions = calculateSize(height, imageSizeWidth / imageSizeHeight, layoutInfo?.height);
83
132
  if (!dimensions)
84
133
  return;
85
- newWidth = dimensions.width;
86
- newHeight = dimensions.height;
87
134
  }
88
135
  else if (height === 'auto') { // auto px/rpx/%
89
136
  if (!imageSize)
90
137
  return;
91
- const dimensions = calculateSize(width, layoutInfo?.width, imageSizeHeight / imageSizeWidth);
138
+ dimensions = calculateSize(width, imageSizeHeight / imageSizeWidth, layoutInfo?.width, true);
92
139
  if (!dimensions)
93
140
  return;
94
- newHeight = dimensions.width;
95
- newWidth = dimensions.height;
96
141
  }
97
142
  else { // 数值类型 ImageStyle
98
143
  // 数值类型设置为 stretch
99
144
  imageProps.style.resizeMode = 'stretch';
100
- newWidth = PERCENT_REGEX.test(`${width}`) ? width : +width;
101
- newHeight = PERCENT_REGEX.test(`${width}`) ? height : +height;
145
+ dimensions = {
146
+ width: typeof width === 'string' && PERCENT_REGEX.test(width) ? width : +width,
147
+ height: typeof height === 'string' && PERCENT_REGEX.test(height) ? height : +height
148
+ };
102
149
  }
103
- // 样式合并
104
- imageProps.style = {
105
- ...imageProps.style,
106
- width: newWidth,
107
- height: newHeight
108
- };
109
150
  }
151
+ // 样式合并
152
+ imageProps.style = {
153
+ ...imageProps.style,
154
+ ...dimensions
155
+ };
110
156
  }
111
157
  // background-image转换为source
112
158
  function backgroundImage(imageProps, preImageInfo) {
@@ -117,22 +163,98 @@ const imageStyleToProps = (preImageInfo, imageSize, layoutInfo) => {
117
163
  const imageProps = {
118
164
  style: {
119
165
  resizeMode: 'cover',
120
- ...StyleSheet.absoluteFillObject
166
+ position: 'absolute'
167
+ // ...StyleSheet.absoluteFillObject
121
168
  }
122
169
  };
123
- applyHandlers([backgroundSize, backgroundImage], [imageProps, preImageInfo, imageSize, layoutInfo]);
170
+ applyHandlers([backgroundSize, backgroundImage, backgroundPosition], [imageProps, preImageInfo, imageSize, layoutInfo]);
124
171
  if (!imageProps?.src)
125
172
  return null;
126
173
  return imageProps;
127
174
  };
175
+ function isHorizontal(val) {
176
+ return typeof val === 'string' && /^(left|right)$/.test(val);
177
+ }
178
+ function isVertical(val) {
179
+ return typeof val === 'string' && /^(top|bottom)$/.test(val);
180
+ }
181
+ function normalizeBackgroundPosition(parts) {
182
+ if (parts.length === 0)
183
+ return [];
184
+ // 定义默认值
185
+ let hStart = 'left';
186
+ let hOffset = 0;
187
+ let vStart = 'top';
188
+ let vOffset = 0;
189
+ if (parts.length === 4)
190
+ return parts;
191
+ // 归一化
192
+ if (parts.length === 1) {
193
+ // 1. center
194
+ // 2. 2px - hOffset, vOffset(center) - center为50%
195
+ // 3. 10% - hOffset, vOffset(center) - center为50%
196
+ // 4. left - hStart, vOffset(center) - center为50%
197
+ // 5. top - hOffset(center), vStart - center为50%
198
+ if (isHorizontal(parts[0])) {
199
+ hStart = parts[0];
200
+ vOffset = '50%';
201
+ }
202
+ else if (isVertical(parts[0])) {
203
+ vStart = parts[0];
204
+ hOffset = '50%';
205
+ }
206
+ else {
207
+ hOffset = parts[0];
208
+ vOffset = '50%';
209
+ }
210
+ }
211
+ else if (parts.length === 2) {
212
+ // 1. center center - hOffset, vOffset
213
+ // 2. 10px center - hOffset, vStart
214
+ // 3. left center - hStart, vOffset
215
+ // 4. right center - hStart, vOffset
216
+ // 5. 第一位是 left right 覆盖的是 hStart
217
+ // center, 100% 正常的px 覆盖的是 hOffset
218
+ // 第二位是 top bottom 覆盖的是 vStart
219
+ // center, 100% 覆盖的是 vOffset
220
+ //
221
+ // 水平方向
222
+ if (isHorizontal(parts[0])) {
223
+ hStart = parts[0];
224
+ }
225
+ else { // center, 100% 正常的px 覆盖的是 hOffset
226
+ hOffset = parts[0];
227
+ }
228
+ // 垂直方向
229
+ if (isVertical(parts[1])) {
230
+ vStart = parts[1];
231
+ }
232
+ else { // center, 100% 正常的px 覆盖的是 hOffset
233
+ vOffset = parts[1];
234
+ }
235
+ }
236
+ else if (parts.length === 3) {
237
+ // 1. center top 10px / top 10px center 等价 - center为50%
238
+ // 2. right 10px center / center right 10px 等价 - center为50%
239
+ // 2. bottom 50px right
240
+ if (typeof parts[0] === 'string' && typeof parts[1] === 'string' && /^left|bottom|right|top$/.test(parts[0]) && /^left|bottom|right|top$/.test(parts[1])) {
241
+ [hStart, vStart, vOffset] = parts;
242
+ }
243
+ else {
244
+ [hStart, hOffset, vStart] = parts;
245
+ }
246
+ }
247
+ return [hStart, hOffset, vStart, vOffset];
248
+ }
128
249
  function preParseImage(imageStyle) {
129
- const { backgroundImage, backgroundSize = ["auto"] } = imageStyle || {};
250
+ const { backgroundImage, backgroundSize = ['auto'], backgroundPosition = [0, 0] } = imageStyle || {};
130
251
  const src = parseUrl(backgroundImage);
131
252
  let sizeList = backgroundSize.slice();
132
- sizeList.length === 1 && sizeList.push(sizeList[0]);
253
+ sizeList.length === 1 && sizeList.push('auto');
133
254
  return {
134
255
  src,
135
- sizeList
256
+ sizeList,
257
+ backgroundPosition: normalizeBackgroundPosition(backgroundPosition)
136
258
  };
137
259
  }
138
260
  function wrapImage(imageStyle) {
@@ -146,8 +268,8 @@ function wrapImage(imageStyle) {
146
268
  // 预解析
147
269
  const preImageInfo = preParseImage(imageStyle);
148
270
  // 判断是否可挂载onLayout
149
- const needLayout = checkNeedLayout(preImageInfo);
150
- const { src, sizeList } = preImageInfo;
271
+ const { needLayout, needImageSize } = checkNeedLayout(preImageInfo);
272
+ const { src } = preImageInfo;
151
273
  useEffect(() => {
152
274
  if (!src) {
153
275
  setShow(false);
@@ -155,7 +277,7 @@ function wrapImage(imageStyle) {
155
277
  layoutInfo.current = null;
156
278
  return;
157
279
  }
158
- if (!sizeList.includes('auto')) {
280
+ if (!needImageSize) {
159
281
  setShow(true);
160
282
  return;
161
283
  }
@@ -184,11 +306,15 @@ function wrapImage(imageStyle) {
184
306
  width,
185
307
  height
186
308
  };
187
- if (sizeInfo.current) {
188
- setImageSizeWidth(sizeInfo.current.width);
189
- setImageSizeHeight(sizeInfo.current.height);
309
+ if (!needImageSize) {
310
+ setLayoutInfoWidth(width);
311
+ setLayoutInfoHeight(height);
312
+ }
313
+ else if (sizeInfo.current) {
190
314
  setLayoutInfoWidth(width);
191
315
  setLayoutInfoHeight(height);
316
+ setImageSizeWidth(sizeInfo.current.width);
317
+ setImageSizeHeight(sizeInfo.current.height);
192
318
  setShow(true);
193
319
  }
194
320
  };
@@ -196,38 +322,60 @@ function wrapImage(imageStyle) {
196
322
  {show && <Image {...imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current)}/>}
197
323
  </View>;
198
324
  }
199
- function splitStyle(styles) {
200
- return groupBy(styles, (key) => {
201
- if (TEXT_STYLE_REGEX.test(key))
202
- return 'textStyle';
203
- else if (IMAGE_STYLE_REGEX.test(key))
204
- return 'imageStyle';
205
- return 'innerStyle';
206
- }, {});
207
- }
208
- function every(children, callback) {
209
- return children.every((child) => callback(child));
210
- }
211
- function wrapChildren(children, textStyle, imageStyle) {
212
- children = Array.isArray(children) ? children : [children];
325
+ function wrapChildren(children, props, textStyle, imageStyle) {
326
+ const { textProps } = splitProps(props);
327
+ const { 'enable-background-image': enableBackgroundImage } = props;
213
328
  if (every(children, (child) => isText(child))) {
214
- children = [<Text key='viewTextWrap' style={textStyle}>{children}</Text>];
329
+ if (textStyle || textProps) {
330
+ transformTextStyle(textStyle);
331
+ children = <Text key='viewTextWrap' style={textStyle} {...(textProps || {})}>{children}</Text>;
332
+ }
215
333
  }
216
334
  else {
217
335
  if (textStyle)
218
- console.warn('Text style will be ignored unless every child of the view is Text node!');
336
+ throwReactWarning('[Mpx runtime warn]: Text style will be ignored unless every child of the view is Text node!');
219
337
  }
220
338
  return [
221
- wrapImage(imageStyle),
222
- ...children
339
+ enableBackgroundImage ? wrapImage(imageStyle) : null,
340
+ children
223
341
  ];
224
342
  }
225
343
  const _View = forwardRef((props, ref) => {
226
- const { style = [], children, hoverStyle, 'hover-start-time': hoverStartTime = 50, 'hover-stay-time': hoverStayTime = 400, 'enable-offset': enableOffset } = props;
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;
227
372
  const [isHover, setIsHover] = useState(false);
373
+ let transformStyle = {};
374
+ const [containerWidth, setContainerWidth] = useState(0);
375
+ const [containerHeight, setContainerHeight] = useState(0);
228
376
  const layoutRef = useRef({});
229
377
  // 打平 style 数组
230
- const styleObj = StyleSheet.flatten(style);
378
+ const styleObj = normalizeStyle(style);
231
379
  // 默认样式
232
380
  const defaultStyle = {
233
381
  // flex 布局相关的默认样式
@@ -238,6 +386,23 @@ const _View = forwardRef((props, ref) => {
238
386
  flexWrap: 'nowrap'
239
387
  }
240
388
  };
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
+ });
402
+ });
403
+ if (hasPercentStyle) {
404
+ transformStyle = percentTransform(combinationStyleProps, { width: containerWidth, height: containerHeight });
405
+ }
241
406
  const { nodeRef } = useNodesRef(props, ref, {
242
407
  defaultStyle
243
408
  });
@@ -251,14 +416,14 @@ const _View = forwardRef((props, ref) => {
251
416
  const setStartTimer = () => {
252
417
  dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer);
253
418
  dataRef.current.startTimer = setTimeout(() => {
254
- setIsHover(() => true);
419
+ setIsHover(true);
255
420
  }, +hoverStartTime);
256
421
  };
257
422
  const setStayTimer = () => {
258
423
  dataRef.current.stayTimer && clearTimeout(dataRef.current.stayTimer);
259
424
  dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer);
260
425
  dataRef.current.stayTimer = setTimeout(() => {
261
- setIsHover(() => false);
426
+ setIsHover(false);
262
427
  }, +hoverStayTime);
263
428
  };
264
429
  function onTouchStart(e) {
@@ -271,19 +436,83 @@ const _View = forwardRef((props, ref) => {
271
436
  bindtouchend && bindtouchend(e);
272
437
  setStayTimer();
273
438
  }
274
- const onLayout = () => {
275
- nodeRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
276
- layoutRef.current = { x, y, width, height, offsetLeft, offsetTop };
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
+ }
277
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
+ }
278
506
  };
279
- const { textStyle, imageStyle, innerStyle } = splitStyle(StyleSheet.flatten([
280
- defaultStyle,
281
- styleObj,
282
- ...(isHover ? hoverStyle : [])
283
- ]));
507
+ const { textStyle, imageStyle, innerStyle } = splitStyle({
508
+ ...defaultStyle,
509
+ ...styleObj,
510
+ ...(isHover ? hoverStyle : null)
511
+ });
512
+ const needLayout = enableOffset || hasPercentStyle;
284
513
  const innerProps = useInnerProps(props, {
285
514
  ref: nodeRef,
286
- ...enableOffset ? { onLayout } : {},
515
+ ...needLayout ? { onLayout } : {},
287
516
  ...(hoverStyle && {
288
517
  bindtouchstart: onTouchStart,
289
518
  bindtouchend: onTouchEnd
@@ -295,12 +524,13 @@ const _View = forwardRef((props, ref) => {
295
524
  'hover-stay-time',
296
525
  'hoverStyle',
297
526
  'hover-class',
298
- 'enable-offset'
527
+ 'enable-offset',
528
+ 'enable-background-image'
299
529
  ], {
300
530
  layoutRef
301
531
  });
302
- return (<View {...innerProps} style={innerStyle}>
303
- {wrapChildren(children, textStyle, imageStyle)}
532
+ return (<View {...innerProps} style={{ ...innerStyle, ...transformStyle }}>
533
+ {wrapChildren(children, props, textStyle, imageStyle)}
304
534
  </View>);
305
535
  });
306
536
  _View.displayName = 'mpx-view';
@@ -7,22 +7,17 @@ import { promisify, redirectTo, navigateTo, navigateBack, reLaunch, switchTab }
7
7
  // @ts-ignore
8
8
  import { WebView } from 'react-native-webview';
9
9
  import useNodesRef from './useNodesRef';
10
- import { StyleSheet } from 'react-native';
11
10
  const _WebView = forwardRef((props, ref) => {
12
11
  const { src, bindmessage = noop, bindload = noop, binderror = noop } = props;
13
- const defaultWebViewStyle = [
14
- {
15
- position: 'absolute',
16
- left: 0,
17
- right: 0,
18
- top: 0,
19
- bottom: 0
20
- }
21
- ];
12
+ const defaultWebViewStyle = {
13
+ position: 'absolute',
14
+ left: 0,
15
+ right: 0,
16
+ top: 0,
17
+ bottom: 0
18
+ };
22
19
  const { nodeRef: webViewRef } = useNodesRef(props, ref, {
23
- defaultStyle: StyleSheet.flatten([
24
- ...defaultWebViewStyle
25
- ])
20
+ defaultStyle: defaultWebViewStyle
26
21
  });
27
22
  const _messageList = [];
28
23
  const handleUnload = () => {
@@ -106,9 +101,8 @@ const _WebView = forwardRef((props, ref) => {
106
101
  }
107
102
  });
108
103
  };
109
- // @ts-ignore
110
104
  return (<Portal>
111
- <WebView style={[...defaultWebViewStyle]} source={{ uri: src }} ref={webViewRef} onLoad={_load} onError={_error} onMessage={_message} javaScriptEnabled={true}></WebView>
105
+ <WebView style={defaultWebViewStyle} source={{ uri: src }} ref={webViewRef} onLoad={_load} onError={_error} onMessage={_message} javaScriptEnabled={true}></WebView>
112
106
  </Portal>);
113
107
  });
114
108
  _WebView.displayName = 'mpx-web-view';
@@ -0,0 +1 @@
1
+ export {};