@mpxjs/webpack-plugin 2.9.59 → 2.9.64
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 +1 -3
- package/lib/platform/style/wx/index.js +344 -270
- package/lib/platform/template/wx/component-config/checkbox-group.js +8 -0
- package/lib/platform/template/wx/component-config/checkbox.js +8 -0
- package/lib/platform/template/wx/component-config/cover-image.js +15 -0
- package/lib/platform/template/wx/component-config/cover-view.js +9 -0
- package/lib/platform/template/wx/component-config/form.js +13 -1
- package/lib/platform/template/wx/component-config/icon.js +8 -0
- package/lib/platform/template/wx/component-config/index.js +5 -1
- package/lib/platform/template/wx/component-config/label.js +15 -0
- package/lib/platform/template/wx/component-config/movable-area.js +18 -1
- package/lib/platform/template/wx/component-config/movable-view.js +18 -1
- package/lib/platform/template/wx/component-config/navigator.js +8 -0
- package/lib/platform/template/wx/component-config/picker-view-column.js +8 -0
- package/lib/platform/template/wx/component-config/picker-view.js +18 -2
- package/lib/platform/template/wx/component-config/picker.js +14 -1
- package/lib/platform/template/wx/component-config/radio-group.js +8 -0
- package/lib/platform/template/wx/component-config/radio.js +8 -0
- package/lib/platform/template/wx/component-config/root-portal.js +15 -0
- package/lib/platform/template/wx/component-config/switch.js +8 -0
- package/lib/platform/template/wx/component-config/unsupported.js +1 -3
- package/lib/react/processScript.js +2 -0
- package/lib/react/processStyles.js +1 -0
- package/lib/react/processTemplate.js +2 -3
- package/lib/react/style-helper.js +12 -7
- package/lib/runtime/components/react/context.ts +40 -0
- package/lib/runtime/components/react/dist/context.js +8 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +34 -12
- package/lib/runtime/components/react/dist/mpx-button.jsx +88 -88
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +82 -0
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +139 -0
- package/lib/runtime/components/react/dist/mpx-form.jsx +61 -0
- package/lib/runtime/components/react/dist/mpx-icon.jsx +48 -0
- package/lib/runtime/components/react/dist/mpx-image/index.jsx +39 -43
- package/lib/runtime/components/react/dist/mpx-image/svg.jsx +3 -2
- package/lib/runtime/components/react/dist/mpx-input.jsx +63 -37
- package/lib/runtime/components/react/dist/mpx-label.jsx +55 -0
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +41 -0
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +346 -0
- package/lib/runtime/components/react/dist/mpx-navigator.jsx +35 -0
- package/lib/runtime/components/react/dist/mpx-picker/date.jsx +69 -0
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +138 -0
- package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +142 -0
- package/lib/runtime/components/react/dist/mpx-picker/region.jsx +94 -0
- package/lib/runtime/components/react/dist/mpx-picker/regionData.js +6099 -0
- package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +76 -0
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +244 -0
- package/lib/runtime/components/react/dist/mpx-picker/type.js +1 -0
- package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +107 -0
- package/lib/runtime/components/react/dist/mpx-picker-view.jsx +162 -0
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +80 -0
- package/lib/runtime/components/react/dist/mpx-radio.jsx +154 -0
- package/lib/runtime/components/react/dist/mpx-root-portal.jsx +15 -0
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +93 -70
- package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +281 -157
- package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +21 -11
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +19 -11
- package/lib/runtime/components/react/dist/mpx-switch.jsx +79 -0
- package/lib/runtime/components/react/dist/mpx-text.jsx +21 -49
- package/lib/runtime/components/react/dist/mpx-textarea.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-view.jsx +451 -146
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +17 -20
- package/lib/runtime/components/react/dist/parser.js +218 -0
- package/lib/runtime/components/react/dist/types/common.js +1 -0
- package/lib/runtime/components/react/dist/useNodesRef.js +3 -8
- package/lib/runtime/components/react/dist/utils.jsx +433 -0
- package/lib/runtime/components/react/getInnerListeners.ts +43 -21
- package/lib/runtime/components/react/mpx-button.tsx +129 -119
- package/lib/runtime/components/react/mpx-checkbox-group.tsx +152 -0
- package/lib/runtime/components/react/mpx-checkbox.tsx +234 -0
- package/lib/runtime/components/react/mpx-form.tsx +117 -0
- package/lib/runtime/components/react/mpx-icon.tsx +106 -0
- package/lib/runtime/components/react/mpx-image/index.tsx +62 -68
- package/lib/runtime/components/react/mpx-image/svg.tsx +7 -5
- package/lib/runtime/components/react/mpx-input.tsx +90 -42
- package/lib/runtime/components/react/mpx-label.tsx +110 -0
- package/lib/runtime/components/react/mpx-movable-area.tsx +81 -0
- package/lib/runtime/components/react/mpx-movable-view.tsx +424 -0
- package/lib/runtime/components/react/mpx-navigator.tsx +67 -0
- package/lib/runtime/components/react/mpx-picker/date.tsx +82 -0
- package/lib/runtime/components/react/mpx-picker/index.tsx +155 -0
- package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +156 -0
- package/lib/runtime/components/react/mpx-picker/region.tsx +107 -0
- package/lib/runtime/components/react/mpx-picker/regionData.ts +6101 -0
- package/lib/runtime/components/react/mpx-picker/selector.tsx +91 -0
- package/lib/runtime/components/react/mpx-picker/time.tsx +270 -0
- package/lib/runtime/components/react/mpx-picker/type.ts +107 -0
- package/lib/runtime/components/react/mpx-picker-view-column.tsx +156 -0
- package/lib/runtime/components/react/mpx-picker-view.tsx +220 -0
- package/lib/runtime/components/react/mpx-radio-group.tsx +150 -0
- package/lib/runtime/components/react/mpx-radio.tsx +230 -0
- package/lib/runtime/components/react/mpx-root-portal.tsx +27 -0
- package/lib/runtime/components/react/mpx-scroll-view.tsx +184 -130
- package/lib/runtime/components/react/mpx-swiper/carouse.tsx +308 -183
- package/lib/runtime/components/react/mpx-swiper/index.tsx +27 -19
- package/lib/runtime/components/react/mpx-swiper/type.ts +23 -5
- package/lib/runtime/components/react/mpx-swiper-item.tsx +49 -14
- package/lib/runtime/components/react/mpx-switch.tsx +148 -0
- package/lib/runtime/components/react/mpx-text.tsx +53 -77
- package/lib/runtime/components/react/mpx-textarea.tsx +3 -3
- package/lib/runtime/components/react/mpx-view.tsx +576 -195
- package/lib/runtime/components/react/mpx-web-view.tsx +34 -39
- package/lib/runtime/components/react/parser.ts +245 -0
- package/lib/runtime/components/react/types/common.ts +12 -0
- package/lib/runtime/components/react/types/getInnerListeners.ts +2 -1
- package/lib/runtime/components/react/types/global.d.ts +17 -1
- package/lib/runtime/components/react/useNodesRef.ts +4 -10
- package/lib/runtime/components/react/utils.tsx +505 -0
- package/lib/runtime/optionProcessor.js +19 -17
- package/lib/template-compiler/compiler.js +84 -61
- package/lib/template-compiler/gen-node-react.js +7 -9
- package/lib/web/processStyles.js +2 -5
- package/package.json +8 -3
- package/lib/runtime/components/react/dist/utils.js +0 -80
- package/lib/runtime/components/react/utils.ts +0 -92
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import { useEffect, useRef, isValidElement, useContext, useState, Children, cloneElement } from 'react';
|
|
2
|
+
import { Dimensions, StyleSheet } from 'react-native';
|
|
3
|
+
import { isObject, hasOwn, diffAndCloneA, error, warn } from '@mpxjs/utils';
|
|
4
|
+
import { VarContext } from './context';
|
|
5
|
+
import { ExpressionParser, parseFunc, ReplaceSource } from './parser';
|
|
6
|
+
export const TEXT_STYLE_REGEX = /color|font.*|text.*|letterSpacing|lineHeight|includeFontPadding|writingDirection/;
|
|
7
|
+
export const PERCENT_REGEX = /^\s*-?\d+(\.\d+)?%\s*$/;
|
|
8
|
+
export const URL_REGEX = /^\s*url\(["']?(.*?)["']?\)\s*$/;
|
|
9
|
+
export const BACKGROUND_REGEX = /^background(Image|Size|Repeat|Position)$/;
|
|
10
|
+
export const TEXT_PROPS_REGEX = /ellipsizeMode|numberOfLines/;
|
|
11
|
+
export const DEFAULT_FONT_SIZE = 16;
|
|
12
|
+
export const DEFAULT_UNLAY_STYLE = {
|
|
13
|
+
opacity: 0
|
|
14
|
+
};
|
|
15
|
+
export function rpx(value) {
|
|
16
|
+
const { width } = Dimensions.get('screen');
|
|
17
|
+
// rn 单位 dp = 1(css)px = 1 物理像素 * pixelRatio(像素比)
|
|
18
|
+
// px = rpx * (750 / 屏幕宽度)
|
|
19
|
+
return value * width / 750;
|
|
20
|
+
}
|
|
21
|
+
const rpxRegExp = /^\s*(-?\d+(\.\d+)?)rpx\s*$/;
|
|
22
|
+
const pxRegExp = /^\s*(-?\d+(\.\d+)?)(px)?\s*$/;
|
|
23
|
+
const hairlineRegExp = /^\s*hairlineWidth\s*$/;
|
|
24
|
+
const varDecRegExp = /^--.*/;
|
|
25
|
+
const varUseRegExp = /var\(/;
|
|
26
|
+
const calcUseRegExp = /calc\(/;
|
|
27
|
+
export function omit(obj, fields) {
|
|
28
|
+
const shallowCopy = Object.assign({}, obj);
|
|
29
|
+
for (let i = 0; i < fields.length; i += 1) {
|
|
30
|
+
const key = fields[i];
|
|
31
|
+
delete shallowCopy[key];
|
|
32
|
+
}
|
|
33
|
+
return shallowCopy;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 用法等同于 useEffect,但是会忽略首次执行,只在依赖更新时执行
|
|
37
|
+
*/
|
|
38
|
+
export const useUpdateEffect = (effect, deps) => {
|
|
39
|
+
const isMounted = useRef(false);
|
|
40
|
+
// for react-refresh
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
return () => {
|
|
43
|
+
isMounted.current = false;
|
|
44
|
+
};
|
|
45
|
+
}, []);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (!isMounted.current) {
|
|
48
|
+
isMounted.current = true;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
return effect();
|
|
52
|
+
}
|
|
53
|
+
}, deps);
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* 解析行内样式
|
|
57
|
+
* @param inlineStyle
|
|
58
|
+
* @returns
|
|
59
|
+
*/
|
|
60
|
+
export const parseInlineStyle = (inlineStyle = '') => {
|
|
61
|
+
return inlineStyle.split(';').reduce((styleObj, style) => {
|
|
62
|
+
const [k, v, ...rest] = style.split(':');
|
|
63
|
+
if (rest.length || !v || !k)
|
|
64
|
+
return styleObj;
|
|
65
|
+
const key = k.trim().replace(/-./g, c => c.substring(1).toUpperCase());
|
|
66
|
+
return Object.assign(styleObj, { [key]: v.trim() });
|
|
67
|
+
}, {});
|
|
68
|
+
};
|
|
69
|
+
export const parseUrl = (cssUrl = '') => {
|
|
70
|
+
if (!cssUrl)
|
|
71
|
+
return;
|
|
72
|
+
const match = cssUrl.match(URL_REGEX);
|
|
73
|
+
return match?.[1];
|
|
74
|
+
};
|
|
75
|
+
export const getRestProps = (transferProps = {}, originProps = {}, deletePropsKey = []) => {
|
|
76
|
+
return {
|
|
77
|
+
...transferProps,
|
|
78
|
+
...omit(originProps, deletePropsKey)
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
export function isText(ele) {
|
|
82
|
+
if (isValidElement(ele)) {
|
|
83
|
+
const displayName = ele.type?.displayName;
|
|
84
|
+
return displayName === 'mpx-text' || displayName === 'Text';
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
export function isEmbedded(ele) {
|
|
89
|
+
if (isValidElement(ele)) {
|
|
90
|
+
const displayName = ele.type?.displayName || '';
|
|
91
|
+
return ['mpx-checkbox', 'mpx-radio', 'mpx-switch'].includes(displayName);
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
export function every(children, callback) {
|
|
96
|
+
const childrenArray = Array.isArray(children) ? children : [children];
|
|
97
|
+
return childrenArray.every((child) => callback(child));
|
|
98
|
+
}
|
|
99
|
+
export function groupBy(obj, callback, group = {}) {
|
|
100
|
+
Object.entries(obj).forEach(([key, val]) => {
|
|
101
|
+
const groupKey = callback(key, val);
|
|
102
|
+
group[groupKey] = group[groupKey] || {};
|
|
103
|
+
group[groupKey][key] = val;
|
|
104
|
+
});
|
|
105
|
+
return group;
|
|
106
|
+
}
|
|
107
|
+
export function splitStyle(styleObj) {
|
|
108
|
+
return groupBy(styleObj, (key) => {
|
|
109
|
+
if (TEXT_STYLE_REGEX.test(key)) {
|
|
110
|
+
return 'textStyle';
|
|
111
|
+
}
|
|
112
|
+
else if (BACKGROUND_REGEX.test(key)) {
|
|
113
|
+
return 'backgroundStyle';
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
return 'innerStyle';
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
const selfPercentRule = {
|
|
121
|
+
translateX: 'width',
|
|
122
|
+
translateY: 'height',
|
|
123
|
+
borderTopLeftRadius: 'width',
|
|
124
|
+
borderBottomLeftRadius: 'width',
|
|
125
|
+
borderBottomRightRadius: 'width',
|
|
126
|
+
borderTopRightRadius: 'width',
|
|
127
|
+
borderRadius: 'width'
|
|
128
|
+
};
|
|
129
|
+
const parentHeightPercentRule = {
|
|
130
|
+
height: true,
|
|
131
|
+
top: true,
|
|
132
|
+
bottom: true
|
|
133
|
+
};
|
|
134
|
+
// todo calc时处理角度和时间等单位
|
|
135
|
+
function formatValue(value) {
|
|
136
|
+
let matched;
|
|
137
|
+
if ((matched = pxRegExp.exec(value))) {
|
|
138
|
+
return +matched[1];
|
|
139
|
+
}
|
|
140
|
+
else if ((matched = rpxRegExp.exec(value))) {
|
|
141
|
+
return rpx(+matched[1]);
|
|
142
|
+
}
|
|
143
|
+
else if (hairlineRegExp.test(value)) {
|
|
144
|
+
return StyleSheet.hairlineWidth;
|
|
145
|
+
}
|
|
146
|
+
return value;
|
|
147
|
+
}
|
|
148
|
+
function resolvePercent(value, key, percentConfig) {
|
|
149
|
+
if (!(typeof value === 'string' && PERCENT_REGEX.test(value)))
|
|
150
|
+
return value;
|
|
151
|
+
let base;
|
|
152
|
+
let reason;
|
|
153
|
+
if (key === 'fontSize') {
|
|
154
|
+
base = percentConfig.parentFontSize;
|
|
155
|
+
reason = 'parent-font-size';
|
|
156
|
+
}
|
|
157
|
+
else if (key === 'lineHeight') {
|
|
158
|
+
base = resolvePercent(percentConfig.fontSize, 'fontSize', percentConfig);
|
|
159
|
+
reason = 'font-size';
|
|
160
|
+
}
|
|
161
|
+
else if (selfPercentRule[key]) {
|
|
162
|
+
base = percentConfig[selfPercentRule[key]];
|
|
163
|
+
reason = selfPercentRule[key];
|
|
164
|
+
}
|
|
165
|
+
else if (parentHeightPercentRule[key]) {
|
|
166
|
+
base = percentConfig.parentHeight;
|
|
167
|
+
reason = 'parent-height';
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
base = percentConfig.parentWidth;
|
|
171
|
+
reason = 'parent-width';
|
|
172
|
+
}
|
|
173
|
+
if (typeof base !== 'number') {
|
|
174
|
+
error(`[${key}] can not contain % unit unless you set [${reason}] with a number for the percent calculation.`);
|
|
175
|
+
return value;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
return parseFloat(value) / 100 * base;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function transformPercent(styleObj, percentKeyPaths, percentConfig) {
|
|
182
|
+
percentKeyPaths.forEach((percentKeyPath) => {
|
|
183
|
+
setStyle(styleObj, percentKeyPath, ({ target, key, value }) => {
|
|
184
|
+
target[key] = resolvePercent(value, key, percentConfig);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
function resolveVar(input, varContext) {
|
|
189
|
+
const parsed = parseFunc(input, 'var');
|
|
190
|
+
const replaced = new ReplaceSource(input);
|
|
191
|
+
parsed.forEach(({ start, end, args }) => {
|
|
192
|
+
const varName = args[0];
|
|
193
|
+
const fallback = args[1] || '';
|
|
194
|
+
let varValue = hasOwn(varContext, varName) ? varContext[varName] : fallback;
|
|
195
|
+
if (varUseRegExp.test(varValue)) {
|
|
196
|
+
varValue = '' + resolveVar(varValue, varContext);
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
varValue = '' + formatValue(varValue);
|
|
200
|
+
}
|
|
201
|
+
replaced.replace(start, end - 1, varValue);
|
|
202
|
+
});
|
|
203
|
+
return formatValue(replaced.source());
|
|
204
|
+
}
|
|
205
|
+
function transformVar(styleObj, varKeyPaths, varContext) {
|
|
206
|
+
varKeyPaths.forEach((varKeyPath) => {
|
|
207
|
+
setStyle(styleObj, varKeyPath, ({ target, key, value }) => {
|
|
208
|
+
target[key] = resolveVar(value, varContext);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
function transformCalc(styleObj, calcKeyPaths, formatter) {
|
|
213
|
+
calcKeyPaths.forEach((calcKeyPath) => {
|
|
214
|
+
setStyle(styleObj, calcKeyPath, ({ target, key, value }) => {
|
|
215
|
+
const parsed = parseFunc(value, 'calc');
|
|
216
|
+
const replaced = new ReplaceSource(value);
|
|
217
|
+
parsed.forEach(({ start, end, args }) => {
|
|
218
|
+
const exp = args[0];
|
|
219
|
+
try {
|
|
220
|
+
const result = new ExpressionParser(exp, (value) => {
|
|
221
|
+
return formatter(value, key);
|
|
222
|
+
}).parse();
|
|
223
|
+
replaced.replace(start, end - 1, '' + result.value);
|
|
224
|
+
}
|
|
225
|
+
catch (e) {
|
|
226
|
+
error(`calc(${exp}) parse error.`, undefined, e);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
target[key] = formatValue(replaced.source());
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }) {
|
|
234
|
+
const varStyle = {};
|
|
235
|
+
const normalStyle = {};
|
|
236
|
+
let hasVarDec = false;
|
|
237
|
+
let hasVarUse = false;
|
|
238
|
+
let hasSelfPercent = false;
|
|
239
|
+
const varKeyPaths = [];
|
|
240
|
+
const percentKeyPaths = [];
|
|
241
|
+
const calcKeyPaths = [];
|
|
242
|
+
const [width, setWidth] = useState(0);
|
|
243
|
+
const [height, setHeight] = useState(0);
|
|
244
|
+
function varVisitor({ key, value, keyPath }) {
|
|
245
|
+
if (keyPath.length === 1) {
|
|
246
|
+
if (varDecRegExp.test(key)) {
|
|
247
|
+
hasVarDec = true;
|
|
248
|
+
varStyle[key] = value;
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
// clone对象避免set值时改写到props
|
|
252
|
+
normalStyle[key] = isObject(value) ? diffAndCloneA(value).clone : value;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// 对于var定义中使用的var无需替换值,可以通过resolveVar递归解析出值
|
|
256
|
+
if (!varDecRegExp.test(key) && varUseRegExp.test(value)) {
|
|
257
|
+
hasVarUse = true;
|
|
258
|
+
varKeyPaths.push(keyPath.slice());
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// traverse var
|
|
262
|
+
traverseStyle(styleObj, [varVisitor]);
|
|
263
|
+
hasVarDec = hasVarDec || !!externalVarContext;
|
|
264
|
+
enableVar = enableVar || hasVarDec || hasVarUse;
|
|
265
|
+
const enableVarRef = useRef(enableVar);
|
|
266
|
+
if (enableVarRef.current !== enableVar) {
|
|
267
|
+
error('css variable use/declare should be stable in the component lifecycle, or you can set [enable-var] with true.');
|
|
268
|
+
}
|
|
269
|
+
// apply var
|
|
270
|
+
const varContextRef = useRef({});
|
|
271
|
+
if (enableVarRef.current) {
|
|
272
|
+
const varContext = useContext(VarContext);
|
|
273
|
+
const newVarContext = Object.assign({}, varContext, externalVarContext, varStyle);
|
|
274
|
+
// 缓存比较newVarContext是否发生变化
|
|
275
|
+
if (diffAndCloneA(varContextRef.current, newVarContext).diff) {
|
|
276
|
+
varContextRef.current = newVarContext;
|
|
277
|
+
}
|
|
278
|
+
transformVar(normalStyle, varKeyPaths, varContextRef.current);
|
|
279
|
+
}
|
|
280
|
+
function calcVisitor({ value, keyPath }) {
|
|
281
|
+
if (calcUseRegExp.test(value)) {
|
|
282
|
+
calcKeyPaths.push(keyPath.slice());
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function percentVisitor({ key, value, keyPath }) {
|
|
286
|
+
if (hasOwn(selfPercentRule, key) && PERCENT_REGEX.test(value)) {
|
|
287
|
+
hasSelfPercent = true;
|
|
288
|
+
percentKeyPaths.push(keyPath.slice());
|
|
289
|
+
}
|
|
290
|
+
else if (key === 'fontSize' || key === 'lineHeight') {
|
|
291
|
+
percentKeyPaths.push(keyPath.slice());
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// traverse calc & percent
|
|
295
|
+
traverseStyle(normalStyle, [percentVisitor, calcVisitor]);
|
|
296
|
+
const percentConfig = {
|
|
297
|
+
width,
|
|
298
|
+
height,
|
|
299
|
+
fontSize: normalStyle.fontSize,
|
|
300
|
+
parentWidth,
|
|
301
|
+
parentHeight,
|
|
302
|
+
parentFontSize
|
|
303
|
+
};
|
|
304
|
+
// apply percent
|
|
305
|
+
transformPercent(normalStyle, percentKeyPaths, percentConfig);
|
|
306
|
+
// apply calc
|
|
307
|
+
transformCalc(normalStyle, calcKeyPaths, (value, key) => {
|
|
308
|
+
if (PERCENT_REGEX.test(value)) {
|
|
309
|
+
const resolved = resolvePercent(value, key, percentConfig);
|
|
310
|
+
return typeof resolved === 'number' ? resolved : 0;
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
const formatted = formatValue(value);
|
|
314
|
+
if (typeof formatted === 'number') {
|
|
315
|
+
return formatted;
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
warn('calc() only support number, px, rpx, % temporarily.');
|
|
319
|
+
return 0;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
return {
|
|
324
|
+
normalStyle,
|
|
325
|
+
hasSelfPercent,
|
|
326
|
+
hasVarDec,
|
|
327
|
+
enableVarRef,
|
|
328
|
+
varContextRef,
|
|
329
|
+
setWidth,
|
|
330
|
+
setHeight
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
export function traverseStyle(styleObj, visitors) {
|
|
334
|
+
const keyPath = [];
|
|
335
|
+
function traverse(target) {
|
|
336
|
+
if (Array.isArray(target)) {
|
|
337
|
+
target.forEach((value, index) => {
|
|
338
|
+
const key = String(index);
|
|
339
|
+
keyPath.push(key);
|
|
340
|
+
visitors.forEach(visitor => visitor({
|
|
341
|
+
target,
|
|
342
|
+
key,
|
|
343
|
+
value,
|
|
344
|
+
keyPath
|
|
345
|
+
}));
|
|
346
|
+
traverse(value);
|
|
347
|
+
keyPath.pop();
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
else if (isObject(target)) {
|
|
351
|
+
Object.entries(target).forEach(([key, value]) => {
|
|
352
|
+
keyPath.push(key);
|
|
353
|
+
visitors.forEach(visitor => visitor({ target, key, value, keyPath }));
|
|
354
|
+
traverse(value);
|
|
355
|
+
keyPath.pop();
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
traverse(styleObj);
|
|
360
|
+
}
|
|
361
|
+
export function setStyle(styleObj, keyPath, setter, needClone = false) {
|
|
362
|
+
let target = styleObj;
|
|
363
|
+
const firstKey = keyPath[0];
|
|
364
|
+
const lastKey = keyPath[keyPath.length - 1];
|
|
365
|
+
if (needClone)
|
|
366
|
+
target[firstKey] = diffAndCloneA(target[firstKey]).clone;
|
|
367
|
+
for (let i = 0; i < keyPath.length - 1; i++) {
|
|
368
|
+
target = target[keyPath[i]];
|
|
369
|
+
if (!target)
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
setter({
|
|
373
|
+
target,
|
|
374
|
+
key: lastKey,
|
|
375
|
+
value: target[lastKey],
|
|
376
|
+
keyPath
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
export function splitProps(props) {
|
|
380
|
+
return groupBy(props, (key) => {
|
|
381
|
+
if (TEXT_PROPS_REGEX.test(key)) {
|
|
382
|
+
return 'textProps';
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
return 'innerProps';
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
export const useLayout = ({ props, hasSelfPercent, setWidth, setHeight, onLayout, nodeRef }) => {
|
|
390
|
+
const layoutRef = useRef({});
|
|
391
|
+
const hasLayoutRef = useRef(false);
|
|
392
|
+
const layoutStyle = !hasLayoutRef.current && hasSelfPercent ? DEFAULT_UNLAY_STYLE : {};
|
|
393
|
+
const layoutProps = {};
|
|
394
|
+
const enableOffset = props['enable-offset'];
|
|
395
|
+
if (hasSelfPercent || onLayout || enableOffset) {
|
|
396
|
+
layoutProps.onLayout = (e) => {
|
|
397
|
+
hasLayoutRef.current = true;
|
|
398
|
+
if (hasSelfPercent) {
|
|
399
|
+
const { width, height } = e?.nativeEvent?.layout || {};
|
|
400
|
+
setWidth(width || 0);
|
|
401
|
+
setHeight(height || 0);
|
|
402
|
+
}
|
|
403
|
+
if (enableOffset) {
|
|
404
|
+
nodeRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
|
|
405
|
+
layoutRef.current = { x, y, width, height, offsetLeft, offsetTop };
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
onLayout && onLayout(e);
|
|
409
|
+
props.onLayout && props.onLayout(e);
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
return {
|
|
413
|
+
layoutRef,
|
|
414
|
+
layoutStyle,
|
|
415
|
+
layoutProps
|
|
416
|
+
};
|
|
417
|
+
};
|
|
418
|
+
export function wrapChildren(props = {}, { hasVarDec, varContext, textStyle, textProps }) {
|
|
419
|
+
let { children } = props;
|
|
420
|
+
if (textStyle || textProps) {
|
|
421
|
+
children = Children.map(children, (child) => {
|
|
422
|
+
if (isText(child)) {
|
|
423
|
+
const style = { ...textStyle, ...child.props.style };
|
|
424
|
+
return cloneElement(child, { ...textProps, style });
|
|
425
|
+
}
|
|
426
|
+
return child;
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
if (hasVarDec && varContext) {
|
|
430
|
+
children = <VarContext.Provider value={varContext} key='varContextWrap'>{children}</VarContext.Provider>;
|
|
431
|
+
}
|
|
432
|
+
return children;
|
|
433
|
+
}
|
|
@@ -82,7 +82,7 @@ export const getDataSet = (props: Record<string, any>) => {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
export const getCustomEvent = (
|
|
85
|
-
type
|
|
85
|
+
type = '',
|
|
86
86
|
oe: any = {},
|
|
87
87
|
{ detail = {}, layoutRef }: { detail?: Record<string, unknown>; layoutRef: LayoutRef },
|
|
88
88
|
props: Props = {}
|
|
@@ -97,16 +97,18 @@ export const getCustomEvent = (
|
|
|
97
97
|
dataset: getDataSet(props),
|
|
98
98
|
offsetLeft: layoutRef?.current?.offsetLeft || 0,
|
|
99
99
|
offsetTop: layoutRef?.current?.offsetTop || 0
|
|
100
|
-
}
|
|
101
|
-
|
|
100
|
+
},
|
|
101
|
+
persist: oe.persist,
|
|
102
|
+
stopPropagation: oe.stopPropagation,
|
|
103
|
+
preventDefault: oe.preventDefault
|
|
102
104
|
}
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
const useInnerProps = (
|
|
106
108
|
props: Props = {},
|
|
107
109
|
additionalProps: AdditionalProps = {},
|
|
108
|
-
|
|
109
|
-
rawConfig
|
|
110
|
+
userRemoveProps: RemoveProps = [],
|
|
111
|
+
rawConfig?: UseInnerPropsConfig
|
|
110
112
|
) => {
|
|
111
113
|
const ref = useRef<InnerRef>({
|
|
112
114
|
startTimer: {
|
|
@@ -127,7 +129,18 @@ const useInnerProps = (
|
|
|
127
129
|
|
|
128
130
|
const propsRef = useRef<Record<string, any>>({})
|
|
129
131
|
const eventConfig: { [key: string]: string[] } = {}
|
|
130
|
-
const config = rawConfig || {}
|
|
132
|
+
const config = rawConfig || { layoutRef: { current: {} }, disableTouch: false, disableTap: false }
|
|
133
|
+
const removeProps = [
|
|
134
|
+
'children',
|
|
135
|
+
'enable-background',
|
|
136
|
+
'enable-offset',
|
|
137
|
+
'enable-var',
|
|
138
|
+
'external-var-context',
|
|
139
|
+
'parent-font-size',
|
|
140
|
+
'parent-width',
|
|
141
|
+
'parent-height',
|
|
142
|
+
...userRemoveProps
|
|
143
|
+
]
|
|
131
144
|
|
|
132
145
|
propsRef.current = { ...props, ...additionalProps }
|
|
133
146
|
|
|
@@ -141,7 +154,7 @@ const useInnerProps = (
|
|
|
141
154
|
return omit(propsRef.current, removeProps)
|
|
142
155
|
}
|
|
143
156
|
|
|
144
|
-
function handleEmitEvent(
|
|
157
|
+
function handleEmitEvent (
|
|
145
158
|
events: string[],
|
|
146
159
|
type: string,
|
|
147
160
|
oe: NativeTouchEvent
|
|
@@ -156,7 +169,20 @@ const useInnerProps = (
|
|
|
156
169
|
}
|
|
157
170
|
})
|
|
158
171
|
}
|
|
159
|
-
|
|
172
|
+
|
|
173
|
+
function checkIsNeedPress (e: NativeTouchEvent, type: 'bubble' | 'capture') {
|
|
174
|
+
const tapDetailInfo = ref.current.mpxPressInfo.detail || { x: 0, y: 0 }
|
|
175
|
+
const nativeEvent = e.nativeEvent
|
|
176
|
+
const currentPageX = nativeEvent.changedTouches[0].pageX
|
|
177
|
+
const currentPageY = nativeEvent.changedTouches[0].pageY
|
|
178
|
+
if (Math.abs(currentPageX - tapDetailInfo.x) > 1 || Math.abs(currentPageY - tapDetailInfo.y) > 1) {
|
|
179
|
+
ref.current.needPress[type] = false
|
|
180
|
+
ref.current.startTimer[type] && clearTimeout(ref.current.startTimer[type] as SetTimeoutReturnType)
|
|
181
|
+
ref.current.startTimer[type] = null
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function handleTouchstart (e: NativeTouchEvent, type: 'bubble' | 'capture') {
|
|
160
186
|
e.persist()
|
|
161
187
|
const bubbleTouchEvent = ['catchtouchstart', 'bindtouchstart']
|
|
162
188
|
const bubblePressEvent = ['catchlongpress', 'bindlongpress']
|
|
@@ -181,23 +207,17 @@ const useInnerProps = (
|
|
|
181
207
|
}
|
|
182
208
|
}
|
|
183
209
|
|
|
184
|
-
function handleTouchmove(e: NativeTouchEvent, type: 'bubble' | 'capture') {
|
|
210
|
+
function handleTouchmove (e: NativeTouchEvent, type: 'bubble' | 'capture') {
|
|
185
211
|
const bubbleTouchEvent = ['catchtouchmove', 'bindtouchmove']
|
|
186
212
|
const captureTouchEvent = ['capture-catchtouchmove', 'capture-bindtouchmove']
|
|
187
|
-
const tapDetailInfo = ref.current.mpxPressInfo.detail || { x: 0, y: 0 }
|
|
188
|
-
const nativeEvent = e.nativeEvent
|
|
189
|
-
const currentPageX = nativeEvent.changedTouches[0].pageX
|
|
190
|
-
const currentPageY = nativeEvent.changedTouches[0].pageY
|
|
191
213
|
const currentTouchEvent = type === 'bubble' ? bubbleTouchEvent : captureTouchEvent
|
|
192
|
-
if (Math.abs(currentPageX - tapDetailInfo.x) > 1 || Math.abs(currentPageY - tapDetailInfo.y) > 1) {
|
|
193
|
-
ref.current.needPress[type] = false
|
|
194
|
-
ref.current.startTimer[type] && clearTimeout(ref.current.startTimer[type] as SetTimeoutReturnType)
|
|
195
|
-
ref.current.startTimer[type] = null
|
|
196
|
-
}
|
|
197
214
|
handleEmitEvent(currentTouchEvent, 'touchmove', e)
|
|
215
|
+
checkIsNeedPress(e, type)
|
|
198
216
|
}
|
|
199
217
|
|
|
200
|
-
function handleTouchend(e: NativeTouchEvent, type: 'bubble' | 'capture') {
|
|
218
|
+
function handleTouchend (e: NativeTouchEvent, type: 'bubble' | 'capture') {
|
|
219
|
+
// move event may not be triggered
|
|
220
|
+
checkIsNeedPress(e, type)
|
|
201
221
|
const bubbleTouchEvent = ['catchtouchend', 'bindtouchend']
|
|
202
222
|
const bubbleTapEvent = ['catchtap', 'bindtap']
|
|
203
223
|
const captureTouchEvent = ['capture-catchtouchend', 'capture-bindtouchend']
|
|
@@ -208,11 +228,14 @@ const useInnerProps = (
|
|
|
208
228
|
ref.current.startTimer[type] = null
|
|
209
229
|
handleEmitEvent(currentTouchEvent, 'touchend', e)
|
|
210
230
|
if (ref.current.needPress[type]) {
|
|
231
|
+
if (type === 'bubble' && config.disableTap) {
|
|
232
|
+
return
|
|
233
|
+
}
|
|
211
234
|
handleEmitEvent(currentTapEvent, 'tap', e)
|
|
212
235
|
}
|
|
213
236
|
}
|
|
214
237
|
|
|
215
|
-
function handleTouchcancel(e: NativeTouchEvent, type: 'bubble' | 'capture') {
|
|
238
|
+
function handleTouchcancel (e: NativeTouchEvent, type: 'bubble' | 'capture') {
|
|
216
239
|
const bubbleTouchEvent = ['catchtouchcancel', 'bindtouchcancel']
|
|
217
240
|
const captureTouchEvent = ['capture-catchtouchcancel', 'capture-bindtouchcancel']
|
|
218
241
|
const currentTouchEvent = type === 'bubble' ? bubbleTouchEvent : captureTouchEvent
|
|
@@ -272,7 +295,6 @@ const useInnerProps = (
|
|
|
272
295
|
|
|
273
296
|
const finalEventKeys = [...new Set(transformedEventKeys)]
|
|
274
297
|
|
|
275
|
-
|
|
276
298
|
touchEventList.forEach(item => {
|
|
277
299
|
if (finalEventKeys.includes(item.eventName)) {
|
|
278
300
|
events[item.eventName] = item.handler
|