@mpxjs/webpack-plugin 2.10.24 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +4 -1
- package/lib/platform/style/wx/index.js +417 -120
- package/lib/platform/template/wx/component-config/picker.js +0 -6
- package/lib/react/style-helper.js +6 -6
- package/lib/resolver/AddEnvPlugin.js +1 -1
- package/lib/resolver/AddModePlugin.js +1 -1
- package/lib/resolver/ExtendComponentsPlugin.js +68 -0
- package/lib/runtime/components/extends/section-list.mpx +14 -0
- package/lib/runtime/components/react/animationHooks/index.ts +7 -3
- package/lib/runtime/components/react/dist/animationHooks/index.d.ts +0 -2
- package/lib/runtime/components/react/dist/animationHooks/index.js +6 -1
- package/lib/runtime/components/react/dist/event.config.d.ts +2 -6
- package/lib/runtime/components/react/dist/event.config.js +28 -24
- package/lib/runtime/components/react/dist/getInnerListeners.d.ts +1 -1
- package/lib/runtime/components/react/dist/getInnerListeners.js +74 -56
- package/lib/runtime/components/react/dist/mpx-button.d.ts +1 -2
- package/lib/runtime/components/react/dist/mpx-button.jsx +16 -9
- package/lib/runtime/components/react/dist/mpx-camera.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-camera.jsx +36 -5
- package/lib/runtime/components/react/dist/mpx-canvas/index.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +1 -3
- package/lib/runtime/components/react/dist/mpx-canvas/utils.d.ts +1 -1
- package/lib/runtime/components/react/dist/mpx-checkbox-group.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +3 -4
- package/lib/runtime/components/react/dist/mpx-checkbox.d.ts +1 -2
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +8 -9
- package/lib/runtime/components/react/dist/mpx-form.d.ts +1 -2
- package/lib/runtime/components/react/dist/mpx-form.jsx +5 -5
- package/lib/runtime/components/react/dist/mpx-icon/index.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-icon/index.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-image.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-image.jsx +59 -43
- package/lib/runtime/components/react/dist/mpx-inline-text.jsx +13 -4
- package/lib/runtime/components/react/dist/mpx-input.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-input.jsx +16 -8
- package/lib/runtime/components/react/dist/mpx-label.d.ts +1 -2
- package/lib/runtime/components/react/dist/mpx-label.jsx +5 -6
- package/lib/runtime/components/react/dist/mpx-movable-area.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +3 -3
- package/lib/runtime/components/react/dist/mpx-movable-view.d.ts +1 -2
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +6 -6
- package/lib/runtime/components/react/dist/mpx-nav.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +72 -23
- package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-picker/type.d.ts +4 -0
- package/lib/runtime/components/react/dist/mpx-picker-view/index.d.ts +1 -1
- package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +10 -14
- package/lib/runtime/components/react/dist/mpx-picker-view/pickerVIewContext.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-picker-view/pickerVIewContext.js +0 -5
- package/lib/runtime/components/react/dist/mpx-picker-view-column/index.d.ts +1 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column/index.jsx +34 -14
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItem.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItem.jsx +4 -5
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItemLite.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItemLite.jsx +3 -5
- package/lib/runtime/components/react/dist/mpx-popup/index.d.ts +5 -4
- package/lib/runtime/components/react/dist/mpx-popup/index.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-popup/popupBase.jsx +3 -2
- package/lib/runtime/components/react/dist/mpx-progress.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-progress.jsx +1 -3
- package/lib/runtime/components/react/dist/mpx-radio-group.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +3 -4
- package/lib/runtime/components/react/dist/mpx-radio.d.ts +1 -2
- package/lib/runtime/components/react/dist/mpx-radio.jsx +8 -9
- package/lib/runtime/components/react/dist/mpx-rich-text/index.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +1 -3
- package/lib/runtime/components/react/dist/mpx-scroll-view.d.ts +1 -2
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +6 -6
- package/lib/runtime/components/react/dist/mpx-section-list.d.ts +51 -0
- package/lib/runtime/components/react/dist/mpx-section-list.jsx +376 -0
- package/lib/runtime/components/react/dist/mpx-simple-text.jsx +37 -19
- package/lib/runtime/components/react/dist/mpx-simple-view.d.ts +4 -1
- package/lib/runtime/components/react/dist/mpx-simple-view.jsx +11 -4
- package/lib/runtime/components/react/dist/mpx-slider.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-slider.jsx +6 -7
- package/lib/runtime/components/react/dist/mpx-sticky-header.d.ts +1 -2
- package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +5 -5
- package/lib/runtime/components/react/dist/mpx-sticky-section.d.ts +1 -2
- package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +6 -6
- package/lib/runtime/components/react/dist/mpx-swiper-item.d.ts +1 -2
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +5 -5
- package/lib/runtime/components/react/dist/mpx-swiper.d.ts +1 -2
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +4 -8
- package/lib/runtime/components/react/dist/mpx-switch.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-switch.jsx +1 -3
- package/lib/runtime/components/react/dist/mpx-text.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-text.jsx +43 -25
- package/lib/runtime/components/react/dist/mpx-video.d.ts +0 -2
- package/lib/runtime/components/react/dist/mpx-video.jsx +4 -5
- package/lib/runtime/components/react/dist/mpx-view.d.ts +2 -2
- package/lib/runtime/components/react/dist/mpx-view.jsx +214 -114
- package/lib/runtime/components/react/dist/mpx-web-view.d.ts +2 -1
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +5 -1
- package/lib/runtime/components/react/dist/namedColorSet.d.ts +2 -0
- package/lib/runtime/components/react/dist/namedColorSet.js +149 -0
- package/lib/runtime/components/react/dist/utils.d.ts +71 -70
- package/lib/runtime/components/react/dist/utils.jsx +1295 -456
- package/lib/runtime/components/react/event.config.ts +32 -25
- package/lib/runtime/components/react/getInnerListeners.ts +84 -60
- package/lib/runtime/components/react/mpx-button.tsx +18 -18
- package/lib/runtime/components/react/mpx-camera.tsx +40 -8
- package/lib/runtime/components/react/mpx-canvas/index.tsx +5 -7
- package/lib/runtime/components/react/mpx-canvas/utils.tsx +3 -1
- package/lib/runtime/components/react/mpx-checkbox-group.tsx +2 -8
- package/lib/runtime/components/react/mpx-checkbox.tsx +9 -13
- package/lib/runtime/components/react/mpx-form.tsx +6 -8
- package/lib/runtime/components/react/mpx-icon/index.tsx +1 -5
- package/lib/runtime/components/react/mpx-image.tsx +66 -58
- package/lib/runtime/components/react/mpx-inline-text.tsx +13 -4
- package/lib/runtime/components/react/mpx-input.tsx +19 -12
- package/lib/runtime/components/react/mpx-label.tsx +6 -10
- package/lib/runtime/components/react/mpx-movable-area.tsx +3 -5
- package/lib/runtime/components/react/mpx-movable-view.tsx +7 -9
- package/lib/runtime/components/react/mpx-nav.tsx +1 -1
- package/lib/runtime/components/react/mpx-picker/index.tsx +100 -29
- package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +3 -3
- package/lib/runtime/components/react/mpx-picker/selector.tsx +1 -1
- package/lib/runtime/components/react/mpx-picker/type.ts +4 -0
- package/lib/runtime/components/react/mpx-picker-view/index.tsx +17 -24
- package/lib/runtime/components/react/mpx-picker-view/pickerVIewContext.ts +0 -9
- package/lib/runtime/components/react/mpx-picker-view-column/index.tsx +44 -23
- package/lib/runtime/components/react/mpx-picker-view-column/pickerViewColumnItem.tsx +1 -9
- package/lib/runtime/components/react/mpx-picker-view-column/pickerViewColumnItemLite.tsx +0 -9
- package/lib/runtime/components/react/mpx-popup/index.tsx +7 -3
- package/lib/runtime/components/react/mpx-popup/popupBase.tsx +3 -2
- package/lib/runtime/components/react/mpx-progress.tsx +0 -6
- package/lib/runtime/components/react/mpx-radio-group.tsx +2 -8
- package/lib/runtime/components/react/mpx-radio.tsx +9 -13
- package/lib/runtime/components/react/mpx-rich-text/index.tsx +0 -6
- package/lib/runtime/components/react/mpx-scroll-view.tsx +7 -9
- package/lib/runtime/components/react/mpx-section-list.tsx +557 -0
- package/lib/runtime/components/react/mpx-simple-text.tsx +36 -25
- package/lib/runtime/components/react/mpx-simple-view.tsx +17 -5
- package/lib/runtime/components/react/mpx-slider.tsx +15 -13
- package/lib/runtime/components/react/mpx-sticky-header.tsx +6 -8
- package/lib/runtime/components/react/mpx-sticky-section.tsx +7 -9
- package/lib/runtime/components/react/mpx-swiper-item.tsx +6 -7
- package/lib/runtime/components/react/mpx-swiper.tsx +5 -11
- package/lib/runtime/components/react/mpx-switch.tsx +0 -6
- package/lib/runtime/components/react/mpx-text.tsx +45 -36
- package/lib/runtime/components/react/mpx-video.tsx +3 -8
- package/lib/runtime/components/react/mpx-view.tsx +235 -129
- package/lib/runtime/components/react/mpx-web-view.tsx +12 -6
- package/lib/runtime/components/react/namedColorSet.ts +150 -0
- package/lib/runtime/components/react/types/getInnerListeners.d.ts +21 -1
- package/lib/runtime/components/react/types/global.d.ts +1 -0
- package/lib/runtime/components/react/utils.tsx +1352 -550
- package/lib/runtime/i18n.wxs +15 -9
- package/lib/style-compiler/strip-conditional.js +19 -4
- package/lib/template-compiler/compiler.js +6 -0
- package/package.json +6 -6
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* ✔ hover-stay-time
|
|
6
6
|
*/
|
|
7
7
|
import { View, StyleSheet, Image } from 'react-native';
|
|
8
|
-
import { useRef, useState, useEffect, forwardRef, createElement } from 'react';
|
|
8
|
+
import { useRef, useState, useEffect, useMemo, forwardRef, createElement } from 'react';
|
|
9
9
|
import useInnerProps from './getInnerListeners';
|
|
10
10
|
import Animated from 'react-native-reanimated';
|
|
11
11
|
import useAnimationHooks from './animationHooks/index';
|
|
12
12
|
import useNodesRef from './useNodesRef';
|
|
13
|
-
import { parseUrl,
|
|
14
|
-
import { error,
|
|
13
|
+
import { parseUrl, percentRegExp, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout, renderImage, pickStyle, extendObject, useHover, useTextPassThrough } from './utils';
|
|
14
|
+
import { error, warn, hasOwn } from '@mpxjs/utils';
|
|
15
15
|
import * as perf from '@mpxjs/perf';
|
|
16
16
|
import LinearGradient from 'react-native-linear-gradient';
|
|
17
17
|
import { GestureDetector } from 'react-native-gesture-handler';
|
|
@@ -22,6 +22,18 @@ const linearMap = new Map([
|
|
|
22
22
|
['left', 270],
|
|
23
23
|
['right', 90]
|
|
24
24
|
]);
|
|
25
|
+
const FLEX_DEFAULT_STYLE = {
|
|
26
|
+
flexDirection: 'row',
|
|
27
|
+
flexBasis: 'auto',
|
|
28
|
+
flexShrink: 1,
|
|
29
|
+
flexWrap: 'nowrap'
|
|
30
|
+
};
|
|
31
|
+
// 用户传入 flex shorthand 时使用的精简版(裁掉 flexBasis/flexShrink)
|
|
32
|
+
// 避免 number 形式 flex:1 被 default flexBasis:'auto' 反向覆盖
|
|
33
|
+
const FLEX_DEFAULT_STYLE_TRIMMED = {
|
|
34
|
+
flexDirection: 'row',
|
|
35
|
+
flexWrap: 'nowrap'
|
|
36
|
+
};
|
|
25
37
|
// 对角线角度
|
|
26
38
|
const diagonalAngleMap = {
|
|
27
39
|
'top right': (width, height) => {
|
|
@@ -40,22 +52,35 @@ const diagonalAngleMap = {
|
|
|
40
52
|
function radToAngle(r) {
|
|
41
53
|
return r * 180 / Math.PI;
|
|
42
54
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
55
|
+
// === linear-gradient 解析相关正则(模块级,一次创建) ===
|
|
56
|
+
// CSS <angle> 支持 deg/turn/rad/grad 四种单位,统一归一为 deg
|
|
57
|
+
// https://www.w3.org/TR/css-values-3/#angles
|
|
58
|
+
const angleRegExp = /^\s*(-?\d+(?:\.\d+)?)(deg|turn|rad|grad)\b/;
|
|
59
|
+
const gradientToRegExp = /^to\b\s*/;
|
|
60
|
+
// 入口形态:仅在含 linear-gradient 时走解析;提取括号内内容
|
|
61
|
+
const linearGradientRegExp = /linear-gradient\((.*)\)/;
|
|
62
|
+
// 顶层逗号切分(忽略 () / # 内部的逗号)
|
|
63
|
+
const topLevelCommaRegExp = /,(?![^(#]*\))/;
|
|
64
|
+
// 色标内空白切分(忽略色函数里的逗号边界)
|
|
65
|
+
const stopWhitespaceRegExp = /(?<!,)\s+/;
|
|
66
|
+
// 色标位置仅支持 `<n>%` 或裸 `0`(CSS 允许 0 作为唯一无单位 length)
|
|
67
|
+
// 其它单位(px/rpx/em/vw/...)当前无法在不依赖 layout 的情况下归一为百分比,统一拒绝
|
|
68
|
+
const validStopPosRegExp = /^-?\d+(?:\.\d+)?%$|^0$/;
|
|
69
|
+
// color hint 检测:色标 token 仅含一个分量且以数字/正负号/小数点开头
|
|
70
|
+
const colorHintLeadingRegExp = /^[-+.\d]/;
|
|
71
|
+
function normalizeAngle(raw) {
|
|
72
|
+
const m = raw.match(angleRegExp);
|
|
73
|
+
if (!m)
|
|
74
|
+
return undefined;
|
|
75
|
+
const n = +m[1];
|
|
76
|
+
switch (m[2]) {
|
|
77
|
+
case 'turn': return n * 360;
|
|
78
|
+
case 'rad': return radToAngle(n);
|
|
79
|
+
case 'grad': return n * 0.9;
|
|
80
|
+
default: return n; // deg
|
|
46
81
|
}
|
|
47
|
-
}
|
|
48
|
-
const
|
|
49
|
-
['backgroundSize', 'backgroundPosition'].forEach(name => {
|
|
50
|
-
if (style[name] && typeof style[name] === 'string') {
|
|
51
|
-
if (style[name].trim()) {
|
|
52
|
-
style[name] = style[name].split(' ');
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
return style;
|
|
57
|
-
};
|
|
58
|
-
const isPercent = (val) => typeof val === 'string' && PERCENT_REGEX.test(val);
|
|
82
|
+
}
|
|
83
|
+
const isPercent = (val) => typeof val === 'string' && percentRegExp.test(val);
|
|
59
84
|
const isBackgroundSizeKeyword = (val) => typeof val === 'string' && /^cover|contain$/.test(val);
|
|
60
85
|
const isNeedLayout = (preImageInfo) => {
|
|
61
86
|
const { sizeList, backgroundPosition, linearInfo, type } = preImageInfo;
|
|
@@ -167,13 +192,13 @@ function backgroundSize(imageProps, preImageInfo, imageSize, layoutInfo) {
|
|
|
167
192
|
// 枚举值
|
|
168
193
|
if (typeof width === 'string' && ['cover', 'contain'].includes(width)) {
|
|
169
194
|
if (layoutInfo && imageSize) {
|
|
170
|
-
const
|
|
171
|
-
const
|
|
172
|
-
// 容器宽高比
|
|
173
|
-
if ((
|
|
195
|
+
const containerRatio = layoutWidth / layoutHeight;
|
|
196
|
+
const imageRatio = imageSizeWidth / imageSizeHeight;
|
|
197
|
+
// 容器宽高比 小于等于 图片宽高比:contain 按宽缩放,cover 按高缩放
|
|
198
|
+
if ((containerRatio <= imageRatio && width === 'contain') || (containerRatio >= imageRatio && width === 'cover')) {
|
|
174
199
|
dimensions = calculateSize(layoutWidth, imageSizeHeight / imageSizeWidth, true);
|
|
175
200
|
}
|
|
176
|
-
else if ((
|
|
201
|
+
else if ((containerRatio > imageRatio && width === 'contain') || (containerRatio < imageRatio && width === 'cover')) {
|
|
177
202
|
dimensions = calculateSize(layoutHeight, imageSizeWidth / imageSizeHeight);
|
|
178
203
|
}
|
|
179
204
|
}
|
|
@@ -238,7 +263,17 @@ function linearGradient(imageProps, preImageInfo, imageSize, layoutInfo) {
|
|
|
238
263
|
if (type !== 'linear')
|
|
239
264
|
return;
|
|
240
265
|
// 角度计算
|
|
241
|
-
|
|
266
|
+
// 注意:不要用 `linearMap.get(direction) || ...`,因为 'top' 映射为 0 是 falsy 值,
|
|
267
|
+
// 会被误判为未命中并落到默认 180deg
|
|
268
|
+
let angle;
|
|
269
|
+
if (linearMap.has(direction)) {
|
|
270
|
+
angle = linearMap.get(direction);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
const normalized = normalizeAngle(direction);
|
|
274
|
+
angle = normalized !== undefined ? normalized : 180;
|
|
275
|
+
}
|
|
276
|
+
angle = angle % 360;
|
|
242
277
|
// 对角线角度计算
|
|
243
278
|
if (layoutInfo && diagonalAngleMap[direction] && imageSize && linearInfo) {
|
|
244
279
|
angle = radToAngle(diagonalAngleMap[direction](width, height)) || 180;
|
|
@@ -249,16 +284,29 @@ function linearGradient(imageProps, preImageInfo, imageSize, layoutInfo) {
|
|
|
249
284
|
imageProps.angle = angle;
|
|
250
285
|
}
|
|
251
286
|
const imageStyleToProps = (preImageInfo, imageSize, layoutInfo) => {
|
|
252
|
-
|
|
287
|
+
const { type } = preImageInfo;
|
|
253
288
|
const imageProps = {
|
|
254
|
-
resizeMode: 'cover',
|
|
255
289
|
style: {
|
|
256
290
|
position: 'absolute'
|
|
257
291
|
// ...StyleSheet.absoluteFillObject
|
|
258
|
-
}
|
|
259
|
-
colors: []
|
|
292
|
+
}
|
|
260
293
|
};
|
|
261
|
-
|
|
294
|
+
if (type === 'image') {
|
|
295
|
+
imageProps.resizeMode = 'cover';
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
imageProps.colors = [];
|
|
299
|
+
}
|
|
300
|
+
backgroundSize(imageProps, preImageInfo, imageSize, layoutInfo);
|
|
301
|
+
if (preImageInfo.backgroundPosition.length) {
|
|
302
|
+
backgroundPosition(imageProps, preImageInfo, imageSize, layoutInfo);
|
|
303
|
+
}
|
|
304
|
+
if (type === 'image') {
|
|
305
|
+
backgroundImage(imageProps, preImageInfo);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
linearGradient(imageProps, preImageInfo, imageSize, layoutInfo);
|
|
309
|
+
}
|
|
262
310
|
return imageProps;
|
|
263
311
|
};
|
|
264
312
|
function isHorizontal(val) {
|
|
@@ -364,24 +412,61 @@ function calcSteps(startVal, endVal, len) {
|
|
|
364
412
|
}
|
|
365
413
|
return newArr;
|
|
366
414
|
}
|
|
415
|
+
// 返回值约定:
|
|
416
|
+
// - LinearInfo 解析成功
|
|
417
|
+
// - null 已识别为 linear-gradient 但内部已通过 error/warn 报错,外部不要再报
|
|
418
|
+
// - undefined 不是 linear-gradient 形态,外部按"不支持的 background-image"处理
|
|
367
419
|
function parseLinearGradient(text) {
|
|
368
|
-
let linearText = text.trim().match(
|
|
420
|
+
let linearText = text.trim().match(linearGradientRegExp)?.[1];
|
|
369
421
|
if (!linearText)
|
|
370
422
|
return;
|
|
371
|
-
//
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
linearText = linearText.replace('to', '');
|
|
423
|
+
// 多重渐变 / 多重背景:linearGradientRegExp 用了贪婪 `.*`,多渐变时括号内
|
|
424
|
+
// 会贪到下一段 `linear-gradient(`,单段则一定不含;用 includes 一次判断即可
|
|
425
|
+
if (linearText.includes('linear-gradient(')) {
|
|
426
|
+
error(`[mpx-view] background-image 暂不支持多重渐变 (multi gradients),已丢弃,原值: ${text}`);
|
|
427
|
+
return null;
|
|
377
428
|
}
|
|
378
429
|
// 把 0deg, red 10%, blue 20% 解析为 ['0deg', 'red, 10%', 'blue, 20%']
|
|
379
|
-
|
|
430
|
+
if (gradientToRegExp.test(linearText)) {
|
|
431
|
+
linearText = linearText.replace(gradientToRegExp, '');
|
|
432
|
+
}
|
|
433
|
+
else if (!angleRegExp.test(linearText)) {
|
|
434
|
+
linearText = '180deg ,' + linearText;
|
|
435
|
+
}
|
|
436
|
+
const [direction, ...colorList] = linearText.split(topLevelCommaRegExp);
|
|
380
437
|
// 记录需要填充起点的起始位置
|
|
381
438
|
let startIdx = 0;
|
|
382
439
|
let startVal = 0;
|
|
383
440
|
// 把 ['red, 10%', 'blue, 20%']解析为 [[red, 10%], [blue, 20%]]
|
|
384
|
-
|
|
441
|
+
// 双位置语法展开:['red', '0%', '50%'] → [['red', '0%'], ['red', '50%']]
|
|
442
|
+
// 等价于 CSS Images Level 4 中 `red 0% 50%` ≡ `red 0%, red 50%`
|
|
443
|
+
// 同步对不支持的写法做拦截:color hint(仅一个位置 token)、非百分比位置(px/rpx 等)
|
|
444
|
+
const linearInfo = colorList
|
|
445
|
+
.map(item => item.trim().split(stopWhitespaceRegExp))
|
|
446
|
+
.reduce((acc, parts) => {
|
|
447
|
+
// color hint: 例如 `linear-gradient(red, 30%, blue)` 中的 `30%`
|
|
448
|
+
// 该 token 仅含一个位置值、无颜色;当前实现无法做颜色采样,直接丢弃
|
|
449
|
+
if (parts.length === 1 && colorHintLeadingRegExp.test(parts[0])) {
|
|
450
|
+
warn(`[mpx-view] linear-gradient 暂不支持 color hint 写法 [${parts[0]}],已丢弃该色标`);
|
|
451
|
+
return acc;
|
|
452
|
+
}
|
|
453
|
+
const [color, ...positions] = parts;
|
|
454
|
+
if (positions.length === 0) {
|
|
455
|
+
acc.push([color]);
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
for (const pos of positions) {
|
|
459
|
+
if (!validStopPosRegExp.test(pos)) {
|
|
460
|
+
warn(`[mpx-view] linear-gradient 色标位置仅支持百分比 [${color} ${pos}] 已丢弃位置,仅保留颜色`);
|
|
461
|
+
acc.push([color]);
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
acc.push([color, pos]);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return acc;
|
|
469
|
+
}, [])
|
|
385
470
|
.reduce((prev, cur, idx, self) => {
|
|
386
471
|
const { colors, locations } = prev;
|
|
387
472
|
const [color, val] = cur;
|
|
@@ -406,6 +491,11 @@ function parseLinearGradient(text) {
|
|
|
406
491
|
!isNaN(numberVal) && locations.push(numberVal);
|
|
407
492
|
return prev;
|
|
408
493
|
}, { colors: [], locations: [] });
|
|
494
|
+
// 色标全部被丢弃或不足以构成渐变(至少 2 个颜色),降级返回
|
|
495
|
+
if (linearInfo.colors.length < 2) {
|
|
496
|
+
error(`[mpx-view] linear-gradient 至少需要 2 个有效色标,已丢弃,原值: ${text}`);
|
|
497
|
+
return null;
|
|
498
|
+
}
|
|
409
499
|
return extendObject({}, linearInfo, {
|
|
410
500
|
direction: direction.trim()
|
|
411
501
|
});
|
|
@@ -417,13 +507,19 @@ function parseBgImage(text) {
|
|
|
417
507
|
if (src)
|
|
418
508
|
return { src, type: 'image' };
|
|
419
509
|
const linearInfo = parseLinearGradient(text);
|
|
420
|
-
if (!linearInfo)
|
|
510
|
+
if (!linearInfo) {
|
|
511
|
+
// null 表示 parseLinearGradient 内部已报错,外部不要重复;undefined 才属于未识别形态
|
|
512
|
+
if (linearInfo === undefined) {
|
|
513
|
+
error(`[mpx-view] background-image 暂不支持 ${text},已丢弃,仅支持 url(...) / linear-gradient(...)。`);
|
|
514
|
+
}
|
|
421
515
|
return {};
|
|
516
|
+
}
|
|
422
517
|
return {
|
|
423
518
|
linearInfo,
|
|
424
519
|
type: 'linear'
|
|
425
520
|
};
|
|
426
521
|
}
|
|
522
|
+
export const __parseBgImageForTest = (text) => parseBgImage(text);
|
|
427
523
|
function normalizeBackgroundSize(backgroundSize, type) {
|
|
428
524
|
const sizeList = backgroundSize.slice();
|
|
429
525
|
if (sizeList.length === 1)
|
|
@@ -439,17 +535,6 @@ function normalizeBackgroundSize(backgroundSize, type) {
|
|
|
439
535
|
return global.__formatValue(val);
|
|
440
536
|
});
|
|
441
537
|
}
|
|
442
|
-
function preParseImage(imageStyle) {
|
|
443
|
-
const { backgroundImage = '', backgroundSize = ['auto'], backgroundPosition = [0, 0] } = normalizeStyle(imageStyle) || {};
|
|
444
|
-
const { type, src, linearInfo } = parseBgImage(backgroundImage);
|
|
445
|
-
return {
|
|
446
|
-
src,
|
|
447
|
-
linearInfo,
|
|
448
|
-
type,
|
|
449
|
-
sizeList: normalizeBackgroundSize(backgroundSize, type),
|
|
450
|
-
backgroundPosition: normalizeBackgroundPosition(backgroundPosition)
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
538
|
function isDiagonalAngle(linearInfo) {
|
|
454
539
|
return !!(linearInfo?.direction && diagonalAngleMap[linearInfo.direction]);
|
|
455
540
|
}
|
|
@@ -470,19 +555,39 @@ function inheritStyle(innerStyle = {}) {
|
|
|
470
555
|
: undefined);
|
|
471
556
|
}
|
|
472
557
|
function useWrapImage(imageStyle, innerStyle, enableFastImage) {
|
|
473
|
-
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
const
|
|
558
|
+
const backgroundImage = imageStyle?.backgroundImage;
|
|
559
|
+
const backgroundSize = imageStyle?.backgroundSize;
|
|
560
|
+
const backgroundPosition = imageStyle?.backgroundPosition;
|
|
561
|
+
const parsedImageInfo = useMemo(() => parseBgImage(backgroundImage), [backgroundImage]);
|
|
562
|
+
const { src, type } = parsedImageInfo;
|
|
563
|
+
const backgroundSizeKey = Array.isArray(backgroundSize) ? backgroundSize.join('|') : backgroundSize;
|
|
564
|
+
const sizeList = useMemo(() => normalizeBackgroundSize(backgroundSize ?? ['auto'], type), [backgroundSizeKey, type]);
|
|
565
|
+
const backgroundPositionKey = Array.isArray(backgroundPosition) ? backgroundPosition.join('|') : backgroundPosition;
|
|
566
|
+
const bgPosition = useMemo(() => normalizeBackgroundPosition(backgroundPosition ?? [0, 0]), [backgroundPositionKey]);
|
|
567
|
+
const preImageInfo = useMemo(() => extendObject({}, parsedImageInfo, { sizeList, backgroundPosition: bgPosition }), [parsedImageInfo, sizeList, bgPosition]);
|
|
477
568
|
// 判断是否可挂载onLayout
|
|
478
569
|
const { needLayout, needImageSize } = checkNeedLayout(preImageInfo);
|
|
479
570
|
const [show, setShow] = useState(((type === 'image' && !!src) || type === 'linear') && !needLayout && !needImageSize);
|
|
480
|
-
const [,
|
|
481
|
-
const [, setImageSizeHeight] = useState(null);
|
|
482
|
-
const [, setLayoutInfoWidth] = useState(null);
|
|
483
|
-
const [, setLayoutInfoHeight] = useState(null);
|
|
571
|
+
const [version, setVersion] = useState(0);
|
|
484
572
|
const sizeInfo = useRef(null);
|
|
485
573
|
const layoutInfo = useRef(null);
|
|
574
|
+
const sizeCacheRef = useRef(new Map());
|
|
575
|
+
// sizeInfo / layoutInfo / setVersion 都是稳定引用,闭包整个生命周期只分配一次
|
|
576
|
+
const { bumpVersion, setImageSize, setLayoutInfo } = useMemo(() => ({
|
|
577
|
+
bumpVersion: () => setVersion(version => version + 1),
|
|
578
|
+
setImageSize: (width, height) => {
|
|
579
|
+
if (sizeInfo.current?.width === width && sizeInfo.current?.height === height)
|
|
580
|
+
return false;
|
|
581
|
+
sizeInfo.current = { width, height };
|
|
582
|
+
return true;
|
|
583
|
+
},
|
|
584
|
+
setLayoutInfo: (width, height) => {
|
|
585
|
+
if (layoutInfo.current?.width === width && layoutInfo.current?.height === height)
|
|
586
|
+
return false;
|
|
587
|
+
layoutInfo.current = { width, height };
|
|
588
|
+
return true;
|
|
589
|
+
}
|
|
590
|
+
}), []);
|
|
486
591
|
useEffect(() => {
|
|
487
592
|
sizeInfo.current = null;
|
|
488
593
|
if (type === 'linear') {
|
|
@@ -500,67 +605,67 @@ function useWrapImage(imageStyle, innerStyle, enableFastImage) {
|
|
|
500
605
|
return;
|
|
501
606
|
}
|
|
502
607
|
if (needImageSize) {
|
|
608
|
+
const cached = sizeCacheRef.current.get(src);
|
|
609
|
+
if (cached) {
|
|
610
|
+
const imageSizeChanged = setImageSize(cached.width, cached.height);
|
|
611
|
+
if (!needLayout || layoutInfo.current) {
|
|
612
|
+
imageSizeChanged && bumpVersion();
|
|
613
|
+
setShow(true);
|
|
614
|
+
}
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
let cancelled = false;
|
|
503
618
|
Image.getSize(src, (width, height) => {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
619
|
+
// cache 仍然填上,避免下次同 src 再发一次请求
|
|
620
|
+
sizeCacheRef.current.set(src, { width, height });
|
|
621
|
+
if (cancelled)
|
|
622
|
+
return;
|
|
623
|
+
const imageSizeChanged = setImageSize(width, height);
|
|
508
624
|
// 1. 当需要绑定onLayout 2. 获取到布局信息
|
|
509
625
|
if (!needLayout || layoutInfo.current) {
|
|
510
|
-
|
|
511
|
-
setImageSizeHeight(height);
|
|
512
|
-
if (layoutInfo.current) {
|
|
513
|
-
setLayoutInfoWidth(layoutInfo.current.width);
|
|
514
|
-
setLayoutInfoHeight(layoutInfo.current.height);
|
|
515
|
-
}
|
|
626
|
+
imageSizeChanged && bumpVersion();
|
|
516
627
|
setShow(true);
|
|
517
628
|
}
|
|
518
629
|
});
|
|
630
|
+
return () => { cancelled = true; };
|
|
519
631
|
}
|
|
520
632
|
// type 添加type 处理无渐变 有渐变的场景
|
|
521
|
-
}, [src, type]);
|
|
633
|
+
}, [src, type, needLayout, needImageSize]);
|
|
634
|
+
const imageProps = useMemo(() => imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current), [preImageInfo, version]);
|
|
522
635
|
if (!type)
|
|
523
636
|
return null;
|
|
524
637
|
const onLayout = (res) => {
|
|
525
638
|
const { width, height } = res?.nativeEvent?.layout || {};
|
|
526
|
-
layoutInfo.current
|
|
527
|
-
|
|
528
|
-
height
|
|
529
|
-
};
|
|
639
|
+
// layoutInfo 总是更新,Image.getSize 回调要靠 layoutInfo.current 决定是否 setShow
|
|
640
|
+
let changed = setLayoutInfo(width, height);
|
|
530
641
|
if (!needImageSize) {
|
|
531
|
-
setLayoutInfoWidth(width);
|
|
532
|
-
setLayoutInfoHeight(height);
|
|
533
642
|
// 有渐变角度的时候,才触发渲染组件
|
|
534
643
|
if (type === 'linear') {
|
|
535
|
-
|
|
536
|
-
width: calcPercent(sizeList[0], width),
|
|
537
|
-
height: calcPercent(sizeList[1], height)
|
|
538
|
-
};
|
|
539
|
-
setImageSizeWidth(sizeInfo.current.width);
|
|
540
|
-
setImageSizeHeight(sizeInfo.current.height);
|
|
644
|
+
changed = setImageSize(calcPercent(sizeList[0], width), calcPercent(sizeList[1], height)) || changed;
|
|
541
645
|
}
|
|
646
|
+
changed && bumpVersion();
|
|
542
647
|
setShow(true);
|
|
543
648
|
}
|
|
544
649
|
else if (sizeInfo.current) {
|
|
545
|
-
|
|
546
|
-
setLayoutInfoHeight(height);
|
|
547
|
-
setImageSizeWidth(sizeInfo.current.width);
|
|
548
|
-
setImageSizeHeight(sizeInfo.current.height);
|
|
650
|
+
changed && bumpVersion();
|
|
549
651
|
setShow(true);
|
|
550
652
|
}
|
|
653
|
+
// needImageSize && !sizeInfo.current:等 Image.getSize 回调里 setShow(true),此处不触发渲染
|
|
551
654
|
};
|
|
552
655
|
const backgroundProps = extendObject({ key: 'backgroundImage' }, needLayout ? { onLayout } : {}, { style: extendObject({}, inheritStyle(innerStyle), StyleSheet.absoluteFillObject, { overflow: 'hidden' }) });
|
|
553
|
-
return createElement(View, backgroundProps, show && type === 'linear' && createElement(LinearGradient, extendObject({ useAngle: true },
|
|
656
|
+
return createElement(View, backgroundProps, show && type === 'linear' && createElement(LinearGradient, extendObject({ useAngle: true }, imageProps)), show && type === 'image' && renderImage(imageProps, enableFastImage));
|
|
554
657
|
}
|
|
555
658
|
function wrapWithChildren(props, { hasVarDec, enableBackground, backgroundStyle, varContext, textPassThrough, innerStyle, enableFastImage }) {
|
|
556
|
-
const children = wrapChildren(props, {
|
|
659
|
+
const children = wrapChildren(props.children, {
|
|
557
660
|
hasVarDec,
|
|
558
661
|
varContext,
|
|
559
662
|
textPassThrough
|
|
560
663
|
});
|
|
664
|
+
if (!enableBackground)
|
|
665
|
+
return children;
|
|
561
666
|
return [
|
|
562
667
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
563
|
-
|
|
668
|
+
useWrapImage(backgroundStyle, innerStyle, enableFastImage),
|
|
564
669
|
children
|
|
565
670
|
];
|
|
566
671
|
}
|
|
@@ -574,19 +679,12 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
574
679
|
if (__mpx_perf_framework__)
|
|
575
680
|
idProps = perf.scopeStart('view:render:props');
|
|
576
681
|
const { textProps, innerProps: props = {} } = splitProps(viewProps);
|
|
577
|
-
let { style = {}, 'hover-style': hoverStyle, 'hover-start-time': hoverStartTime = 50, 'hover-stay-time': hoverStayTime = 400, 'enable-var': enableVar, '
|
|
578
|
-
// 默认样式
|
|
579
|
-
const defaultStyle = style.display === 'flex'
|
|
580
|
-
? {
|
|
581
|
-
flexDirection: 'row',
|
|
582
|
-
flexBasis: 'auto',
|
|
583
|
-
flexShrink: 1,
|
|
584
|
-
flexWrap: 'nowrap'
|
|
585
|
-
}
|
|
586
|
-
: {};
|
|
682
|
+
let { style = {}, 'hover-style': hoverStyle, 'hover-start-time': hoverStartTime = 50, 'hover-stay-time': hoverStayTime = 400, 'enable-var': enableVar, 'enable-background': enableBackground, 'enable-text-pass-through': enableTextPassThrough, 'enable-fast-image': enableFastImage, 'enable-animation': enableAnimation, 'parent-width': parentWidth, 'parent-height': parentHeight, animation, catchtransitionend, bindtransitionend } = props;
|
|
587
683
|
const enableHover = !!hoverStyle;
|
|
588
684
|
const { isHover, gesture } = useHover({ enableHover, hoverStartTime, hoverStayTime });
|
|
589
|
-
const styleObj =
|
|
685
|
+
const styleObj = isHover
|
|
686
|
+
? extendObject({}, style, hoverStyle)
|
|
687
|
+
: style;
|
|
590
688
|
if (__mpx_perf_framework__)
|
|
591
689
|
perf.scopeEnd(idProps);
|
|
592
690
|
// ───── style 阶段 ─────
|
|
@@ -595,13 +693,16 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
595
693
|
idStyle = perf.scopeStart('view:render:style');
|
|
596
694
|
const { normalStyle, hasSelfPercent, hasPositionFixed, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, {
|
|
597
695
|
enableVar,
|
|
598
|
-
externalVarContext,
|
|
599
|
-
parentFontSize,
|
|
600
696
|
parentWidth,
|
|
601
|
-
parentHeight
|
|
697
|
+
parentHeight,
|
|
698
|
+
// 基于合并后的 styleObj 判断(hover 状态切换 display 也能触发)
|
|
699
|
+
// 用户传 flex shorthand 时使用精简 default,避免 flexBasis/flexShrink 反向覆盖
|
|
700
|
+
defaultStyle: styleObj.display === 'flex'
|
|
701
|
+
? (hasOwn(styleObj, 'flex') ? FLEX_DEFAULT_STYLE_TRIMMED : FLEX_DEFAULT_STYLE)
|
|
702
|
+
: undefined
|
|
602
703
|
});
|
|
603
704
|
const { textStyle, backgroundStyle, innerStyle = {} } = splitStyle(normalStyle);
|
|
604
|
-
const textPassThrough =
|
|
705
|
+
const textPassThrough = useTextPassThrough(textStyle, textProps, { enableTextPassThrough });
|
|
605
706
|
enableBackground = enableBackground || !!backgroundStyle;
|
|
606
707
|
const enableBackgroundRef = useRef(enableBackground);
|
|
607
708
|
if (enableBackgroundRef.current !== enableBackground) {
|
|
@@ -612,18 +713,16 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
612
713
|
style: normalStyle
|
|
613
714
|
});
|
|
614
715
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
|
|
615
|
-
const viewStyle =
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
: isFunction(bindtransitionend)
|
|
619
|
-
? bindtransitionend
|
|
620
|
-
: undefined;
|
|
716
|
+
const viewStyle = layoutStyle
|
|
717
|
+
? extendObject({}, innerStyle, layoutStyle)
|
|
718
|
+
: innerStyle;
|
|
621
719
|
const { enableStyleAnimation, animationStyle } = useAnimationHooks({
|
|
622
720
|
layoutRef,
|
|
623
721
|
animation,
|
|
624
722
|
enableAnimation,
|
|
625
723
|
style: viewStyle,
|
|
626
|
-
|
|
724
|
+
catchtransitionend,
|
|
725
|
+
bindtransitionend
|
|
627
726
|
});
|
|
628
727
|
if (__mpx_perf_framework__)
|
|
629
728
|
perf.scopeEnd(idStyle);
|
|
@@ -635,15 +734,16 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
635
734
|
ref: nodeRef,
|
|
636
735
|
style: enableStyleAnimation ? [viewStyle, animationStyle] : viewStyle
|
|
637
736
|
}), [
|
|
638
|
-
'animation',
|
|
639
737
|
'hover-start-time',
|
|
640
738
|
'hover-stay-time',
|
|
641
739
|
'hover-style',
|
|
642
740
|
'hover-class',
|
|
643
|
-
'enable-
|
|
741
|
+
'enable-background',
|
|
644
742
|
'enable-animation',
|
|
645
|
-
'
|
|
646
|
-
'
|
|
743
|
+
'enable-fast-image',
|
|
744
|
+
'animation',
|
|
745
|
+
'catchtransitionend',
|
|
746
|
+
'bindtransitionend'
|
|
647
747
|
], {
|
|
648
748
|
layoutRef
|
|
649
749
|
});
|
|
@@ -18,5 +18,6 @@ interface WebViewProps {
|
|
|
18
18
|
binderror?: (event: CommonCallbackEvent) => void;
|
|
19
19
|
[x: string]: any;
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
type WebViewInstance = WebView<any>;
|
|
22
|
+
declare const _WebView: import("react").ForwardRefExoticComponent<Omit<WebViewProps, "ref"> & import("react").RefAttributes<HandlerRef<WebViewInstance, WebViewProps>>>;
|
|
22
23
|
export default _WebView;
|
|
@@ -9,6 +9,10 @@ import useNodesRef from './useNodesRef';
|
|
|
9
9
|
import { getCurrentPage, useNavigation } from './utils';
|
|
10
10
|
import { RouteContext } from './context';
|
|
11
11
|
import { StyleSheet, View, Text } from 'react-native';
|
|
12
|
+
// react-native-webview@13.17+ 将 WebView 泛型默认值由 {} 改为 undefined,
|
|
13
|
+
// 导致 WebViewProps & undefined 塌成 never、JSX 直接使用时 props 全部不可赋值。
|
|
14
|
+
// 显式实参化为 WebView<object>(其 props 即 WebViewProps),保留类实例签名使 ref 仍解析为 WebView,兼容各版本声明。
|
|
15
|
+
const RNWebView = WebView;
|
|
12
16
|
const styles = StyleSheet.create({
|
|
13
17
|
loadErrorContext: {
|
|
14
18
|
display: 'flex',
|
|
@@ -299,7 +303,7 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
299
303
|
<View style={styles.loadErrorText}><Text style={{ fontSize: 14, color: '#999999' }}>{currentErrorText.text}</Text></View>
|
|
300
304
|
<View style={styles.loadErrorButton} onTouchEnd={_reload}><Text style={{ fontSize: 12, color: '#666666' }}>{currentErrorText.button}</Text></View>
|
|
301
305
|
</View>)
|
|
302
|
-
: (<
|
|
306
|
+
: (<RNWebView containerStyle={defaultWebViewStyle} source={{ uri: src }} ref={webViewRef} javaScriptEnabled={true} onNavigationStateChange={_changeUrl} onMessage={_message} injectedJavaScript={injectedJavaScript} onLoadProgress={_onLoadProgress} onLoadEnd={onLoadEnd} onHttpError={onHttpError} onError={onError} allowsBackForwardNavigationGestures={true}></RNWebView>)}
|
|
303
307
|
</Portal>);
|
|
304
308
|
});
|
|
305
309
|
_WebView.displayName = 'MpxWebview';
|