@mpxjs/webpack-plugin 2.9.62 → 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 +67 -53
- 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 +9 -7
- package/lib/runtime/components/react/dist/context.js +1 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +12 -1
- package/lib/runtime/components/react/dist/mpx-button.jsx +52 -74
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +19 -18
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +28 -41
- package/lib/runtime/components/react/dist/mpx-form.jsx +16 -14
- package/lib/runtime/components/react/dist/mpx-icon.jsx +14 -17
- package/lib/runtime/components/react/dist/mpx-image/index.jsx +34 -33
- package/lib/runtime/components/react/dist/mpx-image/svg.jsx +3 -1
- package/lib/runtime/components/react/dist/mpx-input.jsx +35 -31
- package/lib/runtime/components/react/dist/mpx-label.jsx +29 -37
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +13 -18
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +8 -8
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +9 -9
- package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +7 -4
- package/lib/runtime/components/react/dist/mpx-picker/region.jsx +11 -7
- package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +18 -18
- package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +102 -10
- package/lib/runtime/components/react/dist/mpx-picker-view.jsx +147 -53
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +19 -18
- package/lib/runtime/components/react/dist/mpx-radio.jsx +28 -43
- package/lib/runtime/components/react/dist/mpx-root-portal.jsx +8 -4
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +33 -26
- package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +139 -74
- package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +14 -6
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +19 -11
- package/lib/runtime/components/react/dist/mpx-switch.jsx +17 -14
- package/lib/runtime/components/react/dist/mpx-text.jsx +19 -35
- package/lib/runtime/components/react/dist/mpx-textarea.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-view.jsx +284 -209
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +8 -5
- package/lib/runtime/components/react/dist/parser.js +218 -0
- package/lib/runtime/components/react/dist/utils.jsx +433 -0
- package/lib/runtime/components/react/getInnerListeners.ts +18 -8
- package/lib/runtime/components/react/mpx-button.tsx +81 -91
- package/lib/runtime/components/react/mpx-checkbox-group.tsx +48 -43
- package/lib/runtime/components/react/mpx-checkbox.tsx +52 -63
- package/lib/runtime/components/react/mpx-form.tsx +49 -21
- package/lib/runtime/components/react/mpx-icon.tsx +30 -27
- package/lib/runtime/components/react/mpx-image/index.tsx +52 -46
- package/lib/runtime/components/react/mpx-image/svg.tsx +5 -3
- package/lib/runtime/components/react/mpx-input.tsx +58 -38
- package/lib/runtime/components/react/mpx-label.tsx +54 -59
- package/lib/runtime/components/react/mpx-movable-area.tsx +38 -24
- package/lib/runtime/components/react/mpx-movable-view.tsx +27 -28
- package/lib/runtime/components/react/mpx-navigator.tsx +2 -2
- package/lib/runtime/components/react/mpx-picker/date.tsx +2 -3
- package/lib/runtime/components/react/mpx-picker/index.tsx +10 -10
- package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +15 -12
- package/lib/runtime/components/react/mpx-picker/region.tsx +21 -18
- package/lib/runtime/components/react/mpx-picker/selector.tsx +5 -6
- package/lib/runtime/components/react/mpx-picker/time.tsx +25 -29
- package/lib/runtime/components/react/mpx-picker/type.ts +1 -1
- package/lib/runtime/components/react/mpx-picker-view-column.tsx +148 -20
- package/lib/runtime/components/react/mpx-picker-view.tsx +179 -63
- package/lib/runtime/components/react/mpx-radio-group.tsx +50 -47
- package/lib/runtime/components/react/mpx-radio.tsx +56 -72
- package/lib/runtime/components/react/mpx-root-portal.tsx +10 -8
- package/lib/runtime/components/react/mpx-scroll-view.tsx +133 -103
- package/lib/runtime/components/react/mpx-swiper/carouse.tsx +174 -96
- package/lib/runtime/components/react/mpx-swiper/index.tsx +18 -9
- package/lib/runtime/components/react/mpx-swiper/type.ts +16 -5
- package/lib/runtime/components/react/mpx-swiper-item.tsx +46 -13
- package/lib/runtime/components/react/mpx-switch.tsx +44 -23
- package/lib/runtime/components/react/mpx-text.tsx +37 -45
- package/lib/runtime/components/react/mpx-textarea.tsx +1 -1
- package/lib/runtime/components/react/mpx-view.tsx +388 -240
- package/lib/runtime/components/react/mpx-web-view.tsx +19 -20
- package/lib/runtime/components/react/parser.ts +245 -0
- package/lib/runtime/components/react/types/common.ts +4 -4
- package/lib/runtime/components/react/types/global.d.ts +14 -2
- package/lib/runtime/components/react/useNodesRef.ts +1 -2
- package/lib/runtime/components/react/utils.tsx +505 -0
- package/lib/template-compiler/compiler.js +28 -20
- package/lib/template-compiler/gen-node-react.js +1 -3
- package/lib/web/processStyles.js +2 -5
- package/package.json +6 -4
- package/lib/runtime/components/react/dist/utils.js +0 -148
- package/lib/runtime/components/react/utils.ts +0 -170
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
import { useEffect, useRef, ReactNode, ReactElement, FunctionComponent, isValidElement, useContext, useState, Dispatch, SetStateAction, Children, cloneElement } from 'react'
|
|
2
|
+
import { Dimensions, StyleSheet, LayoutChangeEvent, TextStyle } 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
|
+
|
|
7
|
+
export const TEXT_STYLE_REGEX = /color|font.*|text.*|letterSpacing|lineHeight|includeFontPadding|writingDirection/
|
|
8
|
+
export const PERCENT_REGEX = /^\s*-?\d+(\.\d+)?%\s*$/
|
|
9
|
+
export const URL_REGEX = /^\s*url\(["']?(.*?)["']?\)\s*$/
|
|
10
|
+
export const BACKGROUND_REGEX = /^background(Image|Size|Repeat|Position)$/
|
|
11
|
+
export const TEXT_PROPS_REGEX = /ellipsizeMode|numberOfLines/
|
|
12
|
+
export const DEFAULT_FONT_SIZE = 16
|
|
13
|
+
export const DEFAULT_UNLAY_STYLE = {
|
|
14
|
+
opacity: 0
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function rpx (value: number) {
|
|
18
|
+
const { width } = Dimensions.get('screen')
|
|
19
|
+
// rn 单位 dp = 1(css)px = 1 物理像素 * pixelRatio(像素比)
|
|
20
|
+
// px = rpx * (750 / 屏幕宽度)
|
|
21
|
+
return value * width / 750
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const rpxRegExp = /^\s*(-?\d+(\.\d+)?)rpx\s*$/
|
|
25
|
+
const pxRegExp = /^\s*(-?\d+(\.\d+)?)(px)?\s*$/
|
|
26
|
+
const hairlineRegExp = /^\s*hairlineWidth\s*$/
|
|
27
|
+
const varDecRegExp = /^--.*/
|
|
28
|
+
const varUseRegExp = /var\(/
|
|
29
|
+
const calcUseRegExp = /calc\(/
|
|
30
|
+
|
|
31
|
+
export function omit<T, K extends string> (obj: T, fields: K[]): Omit<T, K> {
|
|
32
|
+
const shallowCopy: any = Object.assign({}, obj)
|
|
33
|
+
for (let i = 0; i < fields.length; i += 1) {
|
|
34
|
+
const key = fields[i]
|
|
35
|
+
delete shallowCopy[key]
|
|
36
|
+
}
|
|
37
|
+
return shallowCopy
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 用法等同于 useEffect,但是会忽略首次执行,只在依赖更新时执行
|
|
42
|
+
*/
|
|
43
|
+
export const useUpdateEffect = (effect: any, deps: any) => {
|
|
44
|
+
const isMounted = useRef(false)
|
|
45
|
+
|
|
46
|
+
// for react-refresh
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
return () => {
|
|
49
|
+
isMounted.current = false
|
|
50
|
+
}
|
|
51
|
+
}, [])
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!isMounted.current) {
|
|
55
|
+
isMounted.current = true
|
|
56
|
+
} else {
|
|
57
|
+
return effect()
|
|
58
|
+
}
|
|
59
|
+
}, deps)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 解析行内样式
|
|
64
|
+
* @param inlineStyle
|
|
65
|
+
* @returns
|
|
66
|
+
*/
|
|
67
|
+
export const parseInlineStyle = (inlineStyle = ''): Record<string, string> => {
|
|
68
|
+
return inlineStyle.split(';').reduce((styleObj, style) => {
|
|
69
|
+
const [k, v, ...rest] = style.split(':')
|
|
70
|
+
if (rest.length || !v || !k) return styleObj
|
|
71
|
+
const key = k.trim().replace(/-./g, c => c.substring(1).toUpperCase())
|
|
72
|
+
return Object.assign(styleObj, { [key]: v.trim() })
|
|
73
|
+
}, {})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const parseUrl = (cssUrl = '') => {
|
|
77
|
+
if (!cssUrl) return
|
|
78
|
+
const match = cssUrl.match(URL_REGEX)
|
|
79
|
+
return match?.[1]
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const getRestProps = (transferProps: any = {}, originProps: any = {}, deletePropsKey: any = []) => {
|
|
83
|
+
return {
|
|
84
|
+
...transferProps,
|
|
85
|
+
...omit(originProps, deletePropsKey)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function isText (ele: ReactNode): ele is ReactElement {
|
|
90
|
+
if (isValidElement(ele)) {
|
|
91
|
+
const displayName = (ele.type as FunctionComponent)?.displayName
|
|
92
|
+
return displayName === 'mpx-text' || displayName === 'Text'
|
|
93
|
+
}
|
|
94
|
+
return false
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function isEmbedded (ele: ReactNode): ele is ReactElement {
|
|
98
|
+
if (isValidElement(ele)) {
|
|
99
|
+
const displayName = (ele.type as FunctionComponent)?.displayName || ''
|
|
100
|
+
return ['mpx-checkbox', 'mpx-radio', 'mpx-switch'].includes(displayName)
|
|
101
|
+
}
|
|
102
|
+
return false
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function every (children: ReactNode, callback: (children: ReactNode) => boolean) {
|
|
106
|
+
const childrenArray = Array.isArray(children) ? children : [children]
|
|
107
|
+
return childrenArray.every((child) => callback(child))
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
type GroupData<T> = Record<string, Partial<T>>
|
|
111
|
+
export function groupBy<T extends Record<string, any>> (
|
|
112
|
+
obj: T,
|
|
113
|
+
callback: (key: string, val: T[keyof T]) => string,
|
|
114
|
+
group: GroupData<T> = {}
|
|
115
|
+
): GroupData<T> {
|
|
116
|
+
Object.entries(obj).forEach(([key, val]) => {
|
|
117
|
+
const groupKey = callback(key, val)
|
|
118
|
+
group[groupKey] = group[groupKey] || {}
|
|
119
|
+
group[groupKey][key as keyof T] = val
|
|
120
|
+
})
|
|
121
|
+
return group
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function splitStyle<T extends Record<string, any>> (styleObj: T): {
|
|
125
|
+
textStyle?: Partial<T>;
|
|
126
|
+
backgroundStyle?: Partial<T>;
|
|
127
|
+
innerStyle?: Partial<T>;
|
|
128
|
+
} {
|
|
129
|
+
return groupBy(styleObj, (key) => {
|
|
130
|
+
if (TEXT_STYLE_REGEX.test(key)) {
|
|
131
|
+
return 'textStyle'
|
|
132
|
+
} else if (BACKGROUND_REGEX.test(key)) {
|
|
133
|
+
return 'backgroundStyle'
|
|
134
|
+
} else {
|
|
135
|
+
return 'innerStyle'
|
|
136
|
+
}
|
|
137
|
+
}) as {
|
|
138
|
+
textStyle: Partial<T>;
|
|
139
|
+
backgroundStyle: Partial<T>;
|
|
140
|
+
innerStyle: Partial<T>;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const selfPercentRule: Record<string, 'height' | 'width'> = {
|
|
145
|
+
translateX: 'width',
|
|
146
|
+
translateY: 'height',
|
|
147
|
+
borderTopLeftRadius: 'width',
|
|
148
|
+
borderBottomLeftRadius: 'width',
|
|
149
|
+
borderBottomRightRadius: 'width',
|
|
150
|
+
borderTopRightRadius: 'width',
|
|
151
|
+
borderRadius: 'width'
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const parentHeightPercentRule: Record<string, boolean> = {
|
|
155
|
+
height: true,
|
|
156
|
+
top: true,
|
|
157
|
+
bottom: true
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// todo calc时处理角度和时间等单位
|
|
161
|
+
function formatValue (value: string) {
|
|
162
|
+
let matched
|
|
163
|
+
if ((matched = pxRegExp.exec(value))) {
|
|
164
|
+
return +matched[1]
|
|
165
|
+
} else if ((matched = rpxRegExp.exec(value))) {
|
|
166
|
+
return rpx(+matched[1])
|
|
167
|
+
} else if (hairlineRegExp.test(value)) {
|
|
168
|
+
return StyleSheet.hairlineWidth
|
|
169
|
+
}
|
|
170
|
+
return value
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
interface PercentConfig {
|
|
174
|
+
fontSize?: number | string
|
|
175
|
+
width?: number
|
|
176
|
+
height?: number
|
|
177
|
+
parentFontSize?: number
|
|
178
|
+
parentWidth?: number
|
|
179
|
+
parentHeight?: number
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function resolvePercent (value: string | number | undefined, key: string, percentConfig: PercentConfig): string | number | undefined {
|
|
183
|
+
if (!(typeof value === 'string' && PERCENT_REGEX.test(value))) return value
|
|
184
|
+
let base
|
|
185
|
+
let reason
|
|
186
|
+
if (key === 'fontSize') {
|
|
187
|
+
base = percentConfig.parentFontSize
|
|
188
|
+
reason = 'parent-font-size'
|
|
189
|
+
} else if (key === 'lineHeight') {
|
|
190
|
+
base = resolvePercent(percentConfig.fontSize, 'fontSize', percentConfig)
|
|
191
|
+
reason = 'font-size'
|
|
192
|
+
} else if (selfPercentRule[key]) {
|
|
193
|
+
base = percentConfig[selfPercentRule[key]]
|
|
194
|
+
reason = selfPercentRule[key]
|
|
195
|
+
} else if (parentHeightPercentRule[key]) {
|
|
196
|
+
base = percentConfig.parentHeight
|
|
197
|
+
reason = 'parent-height'
|
|
198
|
+
} else {
|
|
199
|
+
base = percentConfig.parentWidth
|
|
200
|
+
reason = 'parent-width'
|
|
201
|
+
}
|
|
202
|
+
if (typeof base !== 'number') {
|
|
203
|
+
error(`[${key}] can not contain % unit unless you set [${reason}] with a number for the percent calculation.`)
|
|
204
|
+
return value
|
|
205
|
+
} else {
|
|
206
|
+
return parseFloat(value) / 100 * base
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function transformPercent (styleObj: Record<string, any>, percentKeyPaths: Array<Array<string>>, percentConfig: PercentConfig) {
|
|
211
|
+
percentKeyPaths.forEach((percentKeyPath) => {
|
|
212
|
+
setStyle(styleObj, percentKeyPath, ({ target, key, value }) => {
|
|
213
|
+
target[key] = resolvePercent(value, key, percentConfig)
|
|
214
|
+
})
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function resolveVar (input: string, varContext: Record<string, any>) {
|
|
219
|
+
const parsed = parseFunc(input, 'var')
|
|
220
|
+
const replaced = new ReplaceSource(input)
|
|
221
|
+
|
|
222
|
+
parsed.forEach(({ start, end, args }) => {
|
|
223
|
+
const varName = args[0]
|
|
224
|
+
const fallback = args[1] || ''
|
|
225
|
+
let varValue = hasOwn(varContext, varName) ? varContext[varName] : fallback
|
|
226
|
+
if (varUseRegExp.test(varValue)) {
|
|
227
|
+
varValue = '' + resolveVar(varValue, varContext)
|
|
228
|
+
} else {
|
|
229
|
+
varValue = '' + formatValue(varValue)
|
|
230
|
+
}
|
|
231
|
+
replaced.replace(start, end - 1, varValue)
|
|
232
|
+
})
|
|
233
|
+
return formatValue(replaced.source())
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function transformVar (styleObj: Record<string, any>, varKeyPaths: Array<Array<string>>, varContext: Record<string, any>) {
|
|
237
|
+
varKeyPaths.forEach((varKeyPath) => {
|
|
238
|
+
setStyle(styleObj, varKeyPath, ({ target, key, value }) => {
|
|
239
|
+
target[key] = resolveVar(value, varContext)
|
|
240
|
+
})
|
|
241
|
+
})
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function transformCalc (styleObj: Record<string, any>, calcKeyPaths: Array<Array<string>>, formatter: (value: string, key: string) => number) {
|
|
245
|
+
calcKeyPaths.forEach((calcKeyPath) => {
|
|
246
|
+
setStyle(styleObj, calcKeyPath, ({ target, key, value }) => {
|
|
247
|
+
const parsed = parseFunc(value, 'calc')
|
|
248
|
+
const replaced = new ReplaceSource(value)
|
|
249
|
+
parsed.forEach(({ start, end, args }) => {
|
|
250
|
+
const exp = args[0]
|
|
251
|
+
try {
|
|
252
|
+
const result = new ExpressionParser(exp, (value) => {
|
|
253
|
+
return formatter(value, key)
|
|
254
|
+
}).parse()
|
|
255
|
+
replaced.replace(start, end - 1, '' + result.value)
|
|
256
|
+
} catch (e) {
|
|
257
|
+
error(`calc(${exp}) parse error.`, undefined, e)
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
target[key] = formatValue(replaced.source())
|
|
261
|
+
})
|
|
262
|
+
})
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
interface TransformStyleConfig {
|
|
266
|
+
enableVar?: boolean
|
|
267
|
+
externalVarContext?: Record<string, any>
|
|
268
|
+
parentFontSize?: number
|
|
269
|
+
parentWidth?: number
|
|
270
|
+
parentHeight?: number
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export function useTransformStyle (styleObj: Record<string, any> = {}, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }: TransformStyleConfig) {
|
|
274
|
+
const varStyle: Record<string, any> = {}
|
|
275
|
+
const normalStyle: Record<string, any> = {}
|
|
276
|
+
let hasVarDec = false
|
|
277
|
+
let hasVarUse = false
|
|
278
|
+
let hasSelfPercent = false
|
|
279
|
+
const varKeyPaths: Array<Array<string>> = []
|
|
280
|
+
const percentKeyPaths: Array<Array<string>> = []
|
|
281
|
+
const calcKeyPaths: Array<Array<string>> = []
|
|
282
|
+
const [width, setWidth] = useState(0)
|
|
283
|
+
const [height, setHeight] = useState(0)
|
|
284
|
+
|
|
285
|
+
function varVisitor ({ key, value, keyPath }: VisitorArg) {
|
|
286
|
+
if (keyPath.length === 1) {
|
|
287
|
+
if (varDecRegExp.test(key)) {
|
|
288
|
+
hasVarDec = true
|
|
289
|
+
varStyle[key] = value
|
|
290
|
+
} else {
|
|
291
|
+
// clone对象避免set值时改写到props
|
|
292
|
+
normalStyle[key] = isObject(value) ? diffAndCloneA(value).clone : value
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// 对于var定义中使用的var无需替换值,可以通过resolveVar递归解析出值
|
|
296
|
+
if (!varDecRegExp.test(key) && varUseRegExp.test(value)) {
|
|
297
|
+
hasVarUse = true
|
|
298
|
+
varKeyPaths.push(keyPath.slice())
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// traverse var
|
|
302
|
+
traverseStyle(styleObj, [varVisitor])
|
|
303
|
+
hasVarDec = hasVarDec || !!externalVarContext
|
|
304
|
+
enableVar = enableVar || hasVarDec || hasVarUse
|
|
305
|
+
const enableVarRef = useRef(enableVar)
|
|
306
|
+
if (enableVarRef.current !== enableVar) {
|
|
307
|
+
error('css variable use/declare should be stable in the component lifecycle, or you can set [enable-var] with true.')
|
|
308
|
+
}
|
|
309
|
+
// apply var
|
|
310
|
+
const varContextRef = useRef({})
|
|
311
|
+
if (enableVarRef.current) {
|
|
312
|
+
const varContext = useContext(VarContext)
|
|
313
|
+
const newVarContext = Object.assign({}, varContext, externalVarContext, varStyle)
|
|
314
|
+
// 缓存比较newVarContext是否发生变化
|
|
315
|
+
if (diffAndCloneA(varContextRef.current, newVarContext).diff) {
|
|
316
|
+
varContextRef.current = newVarContext
|
|
317
|
+
}
|
|
318
|
+
transformVar(normalStyle, varKeyPaths, varContextRef.current)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function calcVisitor ({ value, keyPath }: VisitorArg) {
|
|
322
|
+
if (calcUseRegExp.test(value)) {
|
|
323
|
+
calcKeyPaths.push(keyPath.slice())
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function percentVisitor ({ key, value, keyPath }: VisitorArg) {
|
|
328
|
+
if (hasOwn(selfPercentRule, key) && PERCENT_REGEX.test(value)) {
|
|
329
|
+
hasSelfPercent = true
|
|
330
|
+
percentKeyPaths.push(keyPath.slice())
|
|
331
|
+
} else if (key === 'fontSize' || key === 'lineHeight') {
|
|
332
|
+
percentKeyPaths.push(keyPath.slice())
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// traverse calc & percent
|
|
337
|
+
traverseStyle(normalStyle, [percentVisitor, calcVisitor])
|
|
338
|
+
|
|
339
|
+
const percentConfig = {
|
|
340
|
+
width,
|
|
341
|
+
height,
|
|
342
|
+
fontSize: normalStyle.fontSize,
|
|
343
|
+
parentWidth,
|
|
344
|
+
parentHeight,
|
|
345
|
+
parentFontSize
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// apply percent
|
|
349
|
+
transformPercent(normalStyle, percentKeyPaths, percentConfig)
|
|
350
|
+
// apply calc
|
|
351
|
+
transformCalc(normalStyle, calcKeyPaths, (value: string, key: string) => {
|
|
352
|
+
if (PERCENT_REGEX.test(value)) {
|
|
353
|
+
const resolved = resolvePercent(value, key, percentConfig)
|
|
354
|
+
return typeof resolved === 'number' ? resolved : 0
|
|
355
|
+
} else {
|
|
356
|
+
const formatted = formatValue(value)
|
|
357
|
+
if (typeof formatted === 'number') {
|
|
358
|
+
return formatted
|
|
359
|
+
} else {
|
|
360
|
+
warn('calc() only support number, px, rpx, % temporarily.')
|
|
361
|
+
return 0
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
return {
|
|
367
|
+
normalStyle,
|
|
368
|
+
hasSelfPercent,
|
|
369
|
+
hasVarDec,
|
|
370
|
+
enableVarRef,
|
|
371
|
+
varContextRef,
|
|
372
|
+
setWidth,
|
|
373
|
+
setHeight
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
export interface VisitorArg {
|
|
378
|
+
target: Record<string, any>
|
|
379
|
+
key: string
|
|
380
|
+
value: any
|
|
381
|
+
keyPath: Array<string>
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export function traverseStyle (styleObj: Record<string, any>, visitors: Array<(arg: VisitorArg) => void>) {
|
|
385
|
+
const keyPath: Array<string> = []
|
|
386
|
+
function traverse<T extends Record<string, any>> (target: T) {
|
|
387
|
+
if (Array.isArray(target)) {
|
|
388
|
+
target.forEach((value, index) => {
|
|
389
|
+
const key = String(index)
|
|
390
|
+
keyPath.push(key)
|
|
391
|
+
visitors.forEach(visitor => visitor({
|
|
392
|
+
target,
|
|
393
|
+
key,
|
|
394
|
+
value,
|
|
395
|
+
keyPath
|
|
396
|
+
}))
|
|
397
|
+
traverse(value)
|
|
398
|
+
keyPath.pop()
|
|
399
|
+
})
|
|
400
|
+
} else if (isObject(target)) {
|
|
401
|
+
Object.entries(target).forEach(([key, value]) => {
|
|
402
|
+
keyPath.push(key)
|
|
403
|
+
visitors.forEach(visitor => visitor({ target, key, value, keyPath }))
|
|
404
|
+
traverse(value)
|
|
405
|
+
keyPath.pop()
|
|
406
|
+
})
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
traverse(styleObj)
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
export function setStyle (styleObj: Record<string, any>, keyPath: Array<string>, setter: (arg: VisitorArg) => void, needClone = false) {
|
|
413
|
+
let target = styleObj
|
|
414
|
+
const firstKey = keyPath[0]
|
|
415
|
+
const lastKey = keyPath[keyPath.length - 1]
|
|
416
|
+
if (needClone) target[firstKey] = diffAndCloneA(target[firstKey]).clone
|
|
417
|
+
for (let i = 0; i < keyPath.length - 1; i++) {
|
|
418
|
+
target = target[keyPath[i]]
|
|
419
|
+
if (!target) return
|
|
420
|
+
}
|
|
421
|
+
setter({
|
|
422
|
+
target,
|
|
423
|
+
key: lastKey,
|
|
424
|
+
value: target[lastKey],
|
|
425
|
+
keyPath
|
|
426
|
+
})
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export function splitProps<T extends Record<string, any>> (props: T): {
|
|
430
|
+
textProps?: Partial<T>;
|
|
431
|
+
innerProps?: Partial<T>;
|
|
432
|
+
} {
|
|
433
|
+
return groupBy(props, (key) => {
|
|
434
|
+
if (TEXT_PROPS_REGEX.test(key)) {
|
|
435
|
+
return 'textProps'
|
|
436
|
+
} else {
|
|
437
|
+
return 'innerProps'
|
|
438
|
+
}
|
|
439
|
+
}) as {
|
|
440
|
+
textProps: Partial<T>;
|
|
441
|
+
innerProps: Partial<T>;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
interface LayoutConfig {
|
|
446
|
+
props: Record<string, any>
|
|
447
|
+
hasSelfPercent: boolean
|
|
448
|
+
setWidth: Dispatch<SetStateAction<number>>
|
|
449
|
+
setHeight: Dispatch<SetStateAction<number>>
|
|
450
|
+
onLayout?: (event?: LayoutChangeEvent) => void
|
|
451
|
+
nodeRef: React.RefObject<any>
|
|
452
|
+
}
|
|
453
|
+
export const useLayout = ({ props, hasSelfPercent, setWidth, setHeight, onLayout, nodeRef }:LayoutConfig) => {
|
|
454
|
+
const layoutRef = useRef({})
|
|
455
|
+
const hasLayoutRef = useRef(false)
|
|
456
|
+
const layoutStyle: Record<string, any> = !hasLayoutRef.current && hasSelfPercent ? DEFAULT_UNLAY_STYLE : {}
|
|
457
|
+
const layoutProps: Record<string, any> = {}
|
|
458
|
+
const enableOffset = props['enable-offset']
|
|
459
|
+
if (hasSelfPercent || onLayout || enableOffset) {
|
|
460
|
+
layoutProps.onLayout = (e: LayoutChangeEvent) => {
|
|
461
|
+
hasLayoutRef.current = true
|
|
462
|
+
if (hasSelfPercent) {
|
|
463
|
+
const { width, height } = e?.nativeEvent?.layout || {}
|
|
464
|
+
setWidth(width || 0)
|
|
465
|
+
setHeight(height || 0)
|
|
466
|
+
}
|
|
467
|
+
if (enableOffset) {
|
|
468
|
+
nodeRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => {
|
|
469
|
+
layoutRef.current = { x, y, width, height, offsetLeft, offsetTop }
|
|
470
|
+
})
|
|
471
|
+
}
|
|
472
|
+
onLayout && onLayout(e)
|
|
473
|
+
props.onLayout && props.onLayout(e)
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return {
|
|
477
|
+
layoutRef,
|
|
478
|
+
layoutStyle,
|
|
479
|
+
layoutProps
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
export interface WrapChildrenConfig {
|
|
484
|
+
hasVarDec: boolean
|
|
485
|
+
varContext?: Record<string, any>
|
|
486
|
+
textStyle?: TextStyle
|
|
487
|
+
textProps?: Record<string, any>
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
export function wrapChildren (props: Record<string, any> = {}, { hasVarDec, varContext, textStyle, textProps }: WrapChildrenConfig) {
|
|
491
|
+
let { children } = props
|
|
492
|
+
if (textStyle || textProps) {
|
|
493
|
+
children = Children.map(children, (child) => {
|
|
494
|
+
if (isText(child)) {
|
|
495
|
+
const style = { ...textStyle, ...child.props.style }
|
|
496
|
+
return cloneElement(child, { ...textProps, style })
|
|
497
|
+
}
|
|
498
|
+
return child
|
|
499
|
+
})
|
|
500
|
+
}
|
|
501
|
+
if (hasVarDec && varContext) {
|
|
502
|
+
children = <VarContext.Provider value={varContext} key='varContextWrap'>{children}</VarContext.Provider>
|
|
503
|
+
}
|
|
504
|
+
return children
|
|
505
|
+
}
|
|
@@ -1068,7 +1068,10 @@ function processStyleReact (el, options) {
|
|
|
1068
1068
|
let staticStyle = getAndRemoveAttr(el, 'style').val || ''
|
|
1069
1069
|
staticStyle = staticStyle.replace(/\s+/g, ' ')
|
|
1070
1070
|
|
|
1071
|
-
const show = getAndRemoveAttr(el, config[mode].directive.show)
|
|
1071
|
+
const { val: show, has } = getAndRemoveAttr(el, config[mode].directive.show)
|
|
1072
|
+
if (has && show === undefined) {
|
|
1073
|
+
error$1(`Attrs ${config[mode].directive.show} should have a value `)
|
|
1074
|
+
}
|
|
1072
1075
|
|
|
1073
1076
|
if (dynamicClass || staticClass || dynamicStyle || staticStyle || show) {
|
|
1074
1077
|
const staticClassExp = parseMustacheWithContext(staticClass).result
|
|
@@ -1080,14 +1083,14 @@ function processStyleReact (el, options) {
|
|
|
1080
1083
|
addAttrs(el, [{
|
|
1081
1084
|
name: 'style',
|
|
1082
1085
|
// runtime helper
|
|
1083
|
-
value: `{{this.__getStyle(${staticClassExp}, ${dynamicClassExp}, ${staticStyleExp}, ${dynamicStyleExp}
|
|
1086
|
+
value: `{{this.__getStyle(${staticClassExp}, ${dynamicClassExp}, ${staticStyleExp}, ${dynamicStyleExp}${show === undefined ? '' : `, !(${showExp})`})}}`
|
|
1084
1087
|
}])
|
|
1085
1088
|
}
|
|
1086
1089
|
|
|
1087
1090
|
if (staticHoverClass && staticHoverClass !== 'none') {
|
|
1088
1091
|
const staticClassExp = parseMustacheWithContext(staticHoverClass).result
|
|
1089
1092
|
addAttrs(el, [{
|
|
1090
|
-
name: '
|
|
1093
|
+
name: 'hover-style',
|
|
1091
1094
|
value: `{{this.__getStyle(${staticClassExp})}}`
|
|
1092
1095
|
}])
|
|
1093
1096
|
}
|
|
@@ -1355,11 +1358,13 @@ function processEvent (el, options) {
|
|
|
1355
1358
|
}
|
|
1356
1359
|
}
|
|
1357
1360
|
|
|
1358
|
-
function processSlotReact (el) {
|
|
1361
|
+
function processSlotReact (el, meta) {
|
|
1359
1362
|
if (el.tag === 'slot') {
|
|
1360
1363
|
el.slot = {
|
|
1361
1364
|
name: getAndRemoveAttr(el, 'name').val
|
|
1362
1365
|
}
|
|
1366
|
+
meta.options = meta.options || {}
|
|
1367
|
+
meta.options.disableMemo = true
|
|
1363
1368
|
}
|
|
1364
1369
|
}
|
|
1365
1370
|
|
|
@@ -1720,34 +1725,33 @@ function processRefReact (el, meta) {
|
|
|
1720
1725
|
type
|
|
1721
1726
|
}
|
|
1722
1727
|
|
|
1728
|
+
const selectors = []
|
|
1729
|
+
|
|
1730
|
+
/**
|
|
1731
|
+
* selectorsConf: [type, [[prefix, selector], [prefix, selector]]]
|
|
1732
|
+
*/
|
|
1723
1733
|
if (!val) {
|
|
1724
|
-
refConf.key = `ref_rn_${++refId}`
|
|
1725
|
-
refConf.sKeys = []
|
|
1726
1734
|
const rawId = el.attrsMap.id
|
|
1727
1735
|
const rawClass = el.attrsMap.class
|
|
1728
1736
|
const rawDynamicClass = el.attrsMap[config[mode].directive.dynamicClass]
|
|
1729
1737
|
|
|
1730
|
-
meta.computed = meta.computed || []
|
|
1731
1738
|
if (rawId) {
|
|
1732
1739
|
const staticId = parseMustacheWithContext(rawId).result
|
|
1733
|
-
|
|
1734
|
-
refConf.sKeys.push({ key: computedIdKey, prefix: '#' })
|
|
1735
|
-
meta.computed.push(`${computedIdKey}() {\n return ${staticId}}`)
|
|
1740
|
+
selectors.push({ prefix: '#', selector: `${staticId}` })
|
|
1736
1741
|
}
|
|
1737
1742
|
if (rawClass || rawDynamicClass) {
|
|
1738
1743
|
const staticClass = parseMustacheWithContext(rawClass).result
|
|
1739
1744
|
const dynamicClass = parseMustacheWithContext(rawDynamicClass).result
|
|
1740
|
-
|
|
1741
|
-
refConf.sKeys.push({ key: computedClassKey, prefix: '.' })
|
|
1742
|
-
meta.computed.push(`${computedClassKey}() {\n return this.__getClass(${staticClass}, ${dynamicClass})}`)
|
|
1745
|
+
selectors.push({ prefix: '.', selector: `this.__getClass(${staticClass}, ${dynamicClass})` })
|
|
1743
1746
|
}
|
|
1747
|
+
} else {
|
|
1748
|
+
meta.refs.push(refConf)
|
|
1749
|
+
selectors.push({ prefix: '', selector: `"${refConf.key}"` })
|
|
1744
1750
|
}
|
|
1745
|
-
|
|
1746
|
-
meta.refs.push(refConf)
|
|
1747
|
-
|
|
1751
|
+
const selectorsConf = selectors.map(item => `["${item.prefix}", ${item.selector}]`)
|
|
1748
1752
|
addAttrs(el, [{
|
|
1749
1753
|
name: 'ref',
|
|
1750
|
-
value: `{{ this.__getRefVal('${
|
|
1754
|
+
value: `{{ this.__getRefVal('${type}', [${selectorsConf}]) }}`
|
|
1751
1755
|
}])
|
|
1752
1756
|
}
|
|
1753
1757
|
}
|
|
@@ -2329,7 +2333,7 @@ function getVirtualHostRoot (options, meta) {
|
|
|
2329
2333
|
if (ctorType === 'component') {
|
|
2330
2334
|
if (mode === 'wx' && hasVirtualHost) {
|
|
2331
2335
|
// wx组件注入virtualHost配置
|
|
2332
|
-
|
|
2336
|
+
meta.options = meta.options || {}
|
|
2333
2337
|
meta.options.virtualHost = true
|
|
2334
2338
|
}
|
|
2335
2339
|
if (mode === 'web' && !hasVirtualHost) {
|
|
@@ -2353,8 +2357,12 @@ function getVirtualHostRoot (options, meta) {
|
|
|
2353
2357
|
name: 'class',
|
|
2354
2358
|
value: `${MPX_ROOT_VIEW} host-${moduleId}`
|
|
2355
2359
|
}
|
|
2360
|
+
// todo 运行时通过root标识确定是否合并rootProps
|
|
2361
|
+
// {
|
|
2362
|
+
// name: 'is-root',
|
|
2363
|
+
// value: '{{true}}'
|
|
2364
|
+
// }
|
|
2356
2365
|
])
|
|
2357
|
-
rootView.isRoot = true
|
|
2358
2366
|
processElement(rootView, rootView, options, meta)
|
|
2359
2367
|
return rootView
|
|
2360
2368
|
}
|
|
@@ -2622,7 +2630,7 @@ function processElement (el, root, options, meta) {
|
|
|
2622
2630
|
processStyleReact(el, options)
|
|
2623
2631
|
processEventReact(el)
|
|
2624
2632
|
processComponentIs(el, options)
|
|
2625
|
-
processSlotReact(el)
|
|
2633
|
+
processSlotReact(el, meta)
|
|
2626
2634
|
processAttrs(el, options)
|
|
2627
2635
|
return
|
|
2628
2636
|
}
|
|
@@ -60,9 +60,7 @@ function genNode (node) {
|
|
|
60
60
|
exp += `__getSlot(${name ? s(name) : ''})`
|
|
61
61
|
} else {
|
|
62
62
|
exp += `createElement(${`getComponent(${node.is || s(node.tag)})`}`
|
|
63
|
-
if (node.
|
|
64
|
-
exp += `, Object.assign({}, rootProps, {style: Object.assign({}, ${attrExpMap.style}, rootProps.style)})`
|
|
65
|
-
} else if (node.attrsList.length) {
|
|
63
|
+
if (node.attrsList.length) {
|
|
66
64
|
const attrs = []
|
|
67
65
|
node.attrsList && node.attrsList.forEach(({ name, value }) => {
|
|
68
66
|
const attrExp = attrExpMap[name] ? attrExpMap[name] : s(value)
|
package/lib/web/processStyles.js
CHANGED
|
@@ -8,11 +8,8 @@ module.exports = function (styles, options, callback) {
|
|
|
8
8
|
attrs (style) {
|
|
9
9
|
const attrs = Object.assign({}, style.attrs)
|
|
10
10
|
if (options.autoScope) attrs.scoped = true
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// query中包含module字符串会被新版vue-cli中的默认rules当做css-module处理
|
|
14
|
-
mid: options.moduleId
|
|
15
|
-
})
|
|
11
|
+
// query中包含module字符串会被新版vue-cli中的默认rules当做css-module处理
|
|
12
|
+
attrs.mid = options.moduleId
|
|
16
13
|
return attrs
|
|
17
14
|
}
|
|
18
15
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpxjs/webpack-plugin",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.64",
|
|
4
4
|
"description": "mpx compile core",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mpx"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@better-scroll/wheel": "^2.5.1",
|
|
29
29
|
"@better-scroll/zoom": "^2.5.1",
|
|
30
30
|
"@mpxjs/template-engine": "^2.8.7",
|
|
31
|
-
"@mpxjs/utils": "^2.9.
|
|
31
|
+
"@mpxjs/utils": "^2.9.64",
|
|
32
32
|
"acorn": "^8.11.3",
|
|
33
33
|
"acorn-walk": "^7.2.0",
|
|
34
34
|
"async": "^2.6.0",
|
|
@@ -82,16 +82,18 @@
|
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@ant-design/react-native": "^5.2.2",
|
|
85
|
-
"@mpxjs/api-proxy": "^2.9.
|
|
85
|
+
"@mpxjs/api-proxy": "^2.9.64",
|
|
86
86
|
"@types/babel-traverse": "^6.25.4",
|
|
87
87
|
"@types/babel-types": "^7.0.4",
|
|
88
88
|
"@types/react": "^18.2.79",
|
|
89
89
|
"react-native": "^0.74.5",
|
|
90
90
|
"react-native-gesture-handler": "^2.18.1",
|
|
91
|
+
"react-native-linear-gradient": "^2.8.3",
|
|
92
|
+
"react-native-webview": "^13.12.2",
|
|
91
93
|
"rimraf": "^6.0.1"
|
|
92
94
|
},
|
|
93
95
|
"engines": {
|
|
94
96
|
"node": ">=14.14.0"
|
|
95
97
|
},
|
|
96
|
-
"gitHead": "
|
|
98
|
+
"gitHead": "803334dc0e600f219d514c27461aa7663b7a6653"
|
|
97
99
|
}
|