@mpxjs/webpack-plugin 2.9.72 → 2.10.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/file-loader.js +5 -0
- package/lib/index.js +21 -3
- package/lib/platform/template/wx/component-config/input.js +1 -1
- package/lib/platform/template/wx/component-config/textarea.js +1 -1
- package/lib/platform/template/wx/component-config/unsupported.js +1 -1
- package/lib/platform/template/wx/component-config/video.js +28 -1
- package/lib/platform/template/wx/index.js +2 -2
- package/lib/react/processScript.js +6 -4
- package/lib/react/processTemplate.js +5 -3
- package/lib/runtime/components/react/KeyboardAvoidingView.tsx +108 -0
- package/lib/runtime/components/react/context.ts +18 -2
- package/lib/runtime/components/react/dist/KeyboardAvoidingView.jsx +89 -0
- package/lib/runtime/components/react/dist/context.js +1 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +1 -2
- package/lib/runtime/components/react/dist/mpx-button.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-icon/icons/cancel.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/clear.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/download.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/info.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/search.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/success.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/success_no_circle.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/waiting.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/warn.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/index.jsx +50 -0
- package/lib/runtime/components/react/dist/mpx-image.jsx +19 -18
- package/lib/runtime/components/react/dist/mpx-input.jsx +48 -19
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +16 -14
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-portal/index.jsx +30 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +112 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +41 -0
- package/lib/runtime/components/react/dist/mpx-root-portal.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +19 -7
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +3 -2
- package/lib/runtime/components/react/dist/mpx-textarea.jsx +11 -3
- package/lib/runtime/components/react/dist/mpx-video.jsx +248 -0
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +149 -50
- package/lib/runtime/components/react/dist/useAnimationHooks.js +4 -4
- package/lib/runtime/components/react/dist/utils.jsx +8 -3
- package/lib/runtime/components/react/getInnerListeners.ts +1 -2
- package/lib/runtime/components/react/mpx-button.tsx +1 -1
- package/lib/runtime/components/react/mpx-icon/icons/cancel.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/clear.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/download.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/info.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/search.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/success.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/success_no_circle.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/waiting.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/warn.png +0 -0
- package/lib/runtime/components/react/mpx-icon/index.tsx +111 -0
- package/lib/runtime/components/react/mpx-image.tsx +26 -14
- package/lib/runtime/components/react/mpx-input.tsx +52 -20
- package/lib/runtime/components/react/mpx-movable-view.tsx +19 -16
- package/lib/runtime/components/react/mpx-picker/time.tsx +2 -1
- package/lib/runtime/components/react/mpx-portal/index.tsx +39 -0
- package/lib/runtime/components/react/mpx-portal/portal-host.tsx +141 -0
- package/lib/runtime/components/react/mpx-portal/portal-manager.tsx +64 -0
- package/lib/runtime/components/react/mpx-root-portal.tsx +1 -1
- package/lib/runtime/components/react/mpx-scroll-view.tsx +20 -8
- package/lib/runtime/components/react/mpx-swiper.tsx +3 -2
- package/lib/runtime/components/react/mpx-textarea.tsx +13 -3
- package/lib/runtime/components/react/mpx-video.tsx +388 -0
- package/lib/runtime/components/react/mpx-web-view.tsx +180 -49
- package/lib/runtime/components/react/types/getInnerListeners.d.ts +1 -1
- package/lib/runtime/components/react/types/global.d.ts +8 -0
- package/lib/runtime/components/react/useAnimationHooks.ts +4 -4
- package/lib/runtime/components/react/utils.tsx +12 -6
- package/lib/script-setup-compiler/index.js +6 -2
- package/lib/style-compiler/index.js +3 -4
- package/lib/style-compiler/strip-conditional-loader.js +127 -0
- package/lib/template-compiler/compiler.js +23 -9
- package/lib/template-compiler/index.js +4 -4
- package/lib/web/processTemplate.js +7 -5
- package/lib/wxs/loader.js +2 -2
- package/lib/wxs/pre-loader.js +2 -2
- package/package.json +7 -5
- package/lib/runtime/components/react/dist/mpx-icon.jsx +0 -41
- package/lib/runtime/components/react/mpx-icon.tsx +0 -102
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { forwardRef,
|
|
2
|
-
import { warn,
|
|
3
|
-
import
|
|
1
|
+
import { forwardRef, useRef, useContext, useMemo, useState, useCallback, useEffect } from 'react'
|
|
2
|
+
import { warn, isFunction } from '@mpxjs/utils'
|
|
3
|
+
import Portal from './mpx-portal/index'
|
|
4
4
|
import { getCustomEvent } from './getInnerListeners'
|
|
5
5
|
import { promisify, redirectTo, navigateTo, navigateBack, reLaunch, switchTab } from '@mpxjs/api-proxy'
|
|
6
6
|
import { WebView } from 'react-native-webview'
|
|
7
7
|
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
8
|
-
import { getCurrentPage,
|
|
9
|
-
import {
|
|
8
|
+
import { getCurrentPage, useNavigation } from './utils'
|
|
9
|
+
import { WebViewHttpErrorEvent, WebViewEvent, WebViewMessageEvent, WebViewNavigation, WebViewProgressEvent } from 'react-native-webview/lib/WebViewTypes'
|
|
10
10
|
import { RouteContext } from './context'
|
|
11
|
+
import { StyleSheet, View, Text } from 'react-native'
|
|
11
12
|
|
|
12
13
|
type OnMessageCallbackEvent = {
|
|
13
14
|
detail: {
|
|
@@ -28,6 +29,7 @@ interface WebViewProps {
|
|
|
28
29
|
binderror?: (event: CommonCallbackEvent) => void
|
|
29
30
|
[x: string]: any
|
|
30
31
|
}
|
|
32
|
+
type Listener = (type: string, callback: (e: Event) => void) => () => void
|
|
31
33
|
|
|
32
34
|
interface PayloadData {
|
|
33
35
|
[x: string]: any
|
|
@@ -40,15 +42,66 @@ type MessageData = {
|
|
|
40
42
|
callbackId?: number
|
|
41
43
|
}
|
|
42
44
|
|
|
45
|
+
type LanguageCode = 'zh-CN' | 'en-US'; // 支持的语言代码
|
|
46
|
+
|
|
47
|
+
interface ErrorText {
|
|
48
|
+
text: string;
|
|
49
|
+
button: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type ErrorTextMap = Record<LanguageCode, ErrorText>
|
|
53
|
+
|
|
54
|
+
const styles = StyleSheet.create({
|
|
55
|
+
loadErrorContext: {
|
|
56
|
+
display: 'flex',
|
|
57
|
+
alignItems: 'center'
|
|
58
|
+
},
|
|
59
|
+
loadErrorText: {
|
|
60
|
+
fontSize: 12,
|
|
61
|
+
color: '#666666',
|
|
62
|
+
paddingTop: '40%',
|
|
63
|
+
paddingBottom: 20,
|
|
64
|
+
paddingLeft: '10%',
|
|
65
|
+
paddingRight: '10%',
|
|
66
|
+
textAlign: 'center'
|
|
67
|
+
},
|
|
68
|
+
loadErrorButton: {
|
|
69
|
+
color: '#666666',
|
|
70
|
+
textAlign: 'center',
|
|
71
|
+
padding: 10,
|
|
72
|
+
borderColor: '#666666',
|
|
73
|
+
borderStyle: 'solid',
|
|
74
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
75
|
+
borderRadius: 10
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
43
79
|
const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((props, ref): JSX.Element | null => {
|
|
44
80
|
const { src, bindmessage, bindload, binderror } = props
|
|
45
81
|
const mpx = global.__mpx
|
|
82
|
+
const errorText: ErrorTextMap = {
|
|
83
|
+
'zh-CN': {
|
|
84
|
+
text: '网络不可用,请检查网络设置',
|
|
85
|
+
button: '重新加载'
|
|
86
|
+
},
|
|
87
|
+
'en-US': {
|
|
88
|
+
text: 'The network is not available. Please check the network settings',
|
|
89
|
+
button: 'Reload'
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const currentErrorText = errorText[(mpx.i18n.locale as LanguageCode) || 'zh-CN']
|
|
93
|
+
|
|
46
94
|
if (props.style) {
|
|
47
95
|
warn('The web-view component does not support the style prop.')
|
|
48
96
|
}
|
|
49
|
-
const pageId = useContext(RouteContext)
|
|
97
|
+
const { pageId } = useContext(RouteContext) || {}
|
|
98
|
+
const [pageLoadErr, setPageLoadErr] = useState<boolean>(false)
|
|
50
99
|
const currentPage = useMemo(() => getCurrentPage(pageId), [pageId])
|
|
51
100
|
const webViewRef = useRef<WebView>(null)
|
|
101
|
+
const fristLoaded = useRef<boolean>(false)
|
|
102
|
+
const isLoadError = useRef<boolean>(false)
|
|
103
|
+
const statusCode = useRef<string|number>('')
|
|
104
|
+
const [isLoaded, setIsLoaded] = useState<boolean>(true)
|
|
52
105
|
const defaultWebViewStyle = {
|
|
53
106
|
position: 'absolute' as 'absolute' | 'relative' | 'static',
|
|
54
107
|
left: 0 as number,
|
|
@@ -56,6 +109,27 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
56
109
|
top: 0 as number,
|
|
57
110
|
bottom: 0 as number
|
|
58
111
|
}
|
|
112
|
+
const canGoBack = useRef<boolean>(false)
|
|
113
|
+
const isNavigateBack = useRef<boolean>(false)
|
|
114
|
+
|
|
115
|
+
const beforeRemoveHandle = (e: Event) => {
|
|
116
|
+
if (canGoBack.current && !isNavigateBack.current) {
|
|
117
|
+
webViewRef.current?.goBack()
|
|
118
|
+
e.preventDefault()
|
|
119
|
+
}
|
|
120
|
+
isNavigateBack.current = false
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const navigation = useNavigation()
|
|
124
|
+
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
const beforeRemoveSubscription = navigation?.addListener?.('beforeRemove', beforeRemoveHandle)
|
|
127
|
+
return () => {
|
|
128
|
+
if (isFunction(beforeRemoveSubscription)) {
|
|
129
|
+
beforeRemoveSubscription()
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}, [])
|
|
59
133
|
|
|
60
134
|
useNodesRef<WebView, WebViewProps>(props, ref, webViewRef, {
|
|
61
135
|
style: defaultWebViewStyle
|
|
@@ -65,25 +139,11 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
65
139
|
return null
|
|
66
140
|
}
|
|
67
141
|
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
timeStamp: res.timeStamp,
|
|
72
|
-
detail: {
|
|
73
|
-
src: res.nativeEvent?.url
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
bindload(result)
|
|
77
|
-
}
|
|
78
|
-
const _error = function (res: WebViewErrorEvent) {
|
|
79
|
-
const result = {
|
|
80
|
-
type: 'error',
|
|
81
|
-
timeStamp: res.timeStamp,
|
|
82
|
-
detail: {
|
|
83
|
-
src: ''
|
|
84
|
-
}
|
|
142
|
+
const _reload = function () {
|
|
143
|
+
if (__mpx_mode__ === 'android') {
|
|
144
|
+
fristLoaded.current = false // 安卓需要重新设置
|
|
85
145
|
}
|
|
86
|
-
|
|
146
|
+
setPageLoadErr(false)
|
|
87
147
|
}
|
|
88
148
|
const injectedJavaScript = `
|
|
89
149
|
if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
|
|
@@ -109,12 +169,27 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
109
169
|
}
|
|
110
170
|
});
|
|
111
171
|
}
|
|
172
|
+
true;
|
|
112
173
|
`
|
|
174
|
+
|
|
175
|
+
const sendMessage = function (params: string) {
|
|
176
|
+
return `
|
|
177
|
+
window.mpxWebviewMessageCallback && window.mpxWebviewMessageCallback(${params})
|
|
178
|
+
true;
|
|
179
|
+
`
|
|
180
|
+
}
|
|
113
181
|
const _changeUrl = function (navState: WebViewNavigation) {
|
|
114
182
|
if (navState.navigationType) { // navigationType这个事件在页面开始加载时和页面加载完成时都会被触发所以判断这个避免其他无效触发执行该逻辑
|
|
183
|
+
canGoBack.current = navState.canGoBack
|
|
115
184
|
currentPage.__webViewUrl = navState.url
|
|
116
185
|
}
|
|
117
186
|
}
|
|
187
|
+
|
|
188
|
+
const _onLoadProgress = function (event: WebViewProgressEvent) {
|
|
189
|
+
if (__mpx_mode__ === 'android') {
|
|
190
|
+
canGoBack.current = event.nativeEvent.canGoBack
|
|
191
|
+
}
|
|
192
|
+
}
|
|
118
193
|
const _message = function (res: WebViewMessageEvent) {
|
|
119
194
|
let data: MessageData = {}
|
|
120
195
|
let asyncCallback
|
|
@@ -134,7 +209,6 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
134
209
|
{ // case下不允许直接声明,包个块解决该问题
|
|
135
210
|
const title = postData._documentTitle
|
|
136
211
|
if (title) {
|
|
137
|
-
const navigation = getFocusedNavigation()
|
|
138
212
|
navigation && navigation.setOptions({ title })
|
|
139
213
|
}
|
|
140
214
|
}
|
|
@@ -153,6 +227,7 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
153
227
|
asyncCallback = navObj.navigateTo(...params)
|
|
154
228
|
break
|
|
155
229
|
case 'navigateBack':
|
|
230
|
+
isNavigateBack.current = true
|
|
156
231
|
asyncCallback = navObj.navigateBack(...params)
|
|
157
232
|
break
|
|
158
233
|
case 'redirectTo':
|
|
@@ -181,47 +256,103 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
181
256
|
|
|
182
257
|
asyncCallback && asyncCallback.then((res: any) => {
|
|
183
258
|
if (webViewRef.current?.postMessage) {
|
|
184
|
-
const
|
|
259
|
+
const result = JSON.stringify({
|
|
185
260
|
type,
|
|
186
261
|
callbackId: data.callbackId,
|
|
187
262
|
result: res
|
|
188
263
|
})
|
|
189
|
-
webViewRef.current.
|
|
264
|
+
webViewRef.current.injectJavaScript(sendMessage(result))
|
|
190
265
|
}
|
|
191
266
|
}).catch((error: any) => {
|
|
192
267
|
if (webViewRef.current?.postMessage) {
|
|
193
|
-
const
|
|
268
|
+
const result = JSON.stringify({
|
|
194
269
|
type,
|
|
195
270
|
callbackId: data.callbackId,
|
|
196
271
|
error
|
|
197
272
|
})
|
|
198
|
-
webViewRef.current.
|
|
273
|
+
webViewRef.current.injectJavaScript(sendMessage(result))
|
|
199
274
|
}
|
|
200
275
|
})
|
|
201
276
|
}
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
277
|
+
const onLoadEndHandle = function (res: WebViewEvent) {
|
|
278
|
+
fristLoaded.current = true
|
|
279
|
+
setIsLoaded(true)
|
|
280
|
+
const src = res.nativeEvent?.url
|
|
281
|
+
if (isLoadError.current) {
|
|
282
|
+
isLoadError.current = false
|
|
283
|
+
isNavigateBack.current = false
|
|
284
|
+
const result = {
|
|
285
|
+
type: 'error',
|
|
286
|
+
timeStamp: res.timeStamp,
|
|
287
|
+
detail: {
|
|
288
|
+
src,
|
|
289
|
+
statusCode: statusCode.current
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
binderror && binderror(result)
|
|
293
|
+
} else {
|
|
294
|
+
const result = {
|
|
295
|
+
type: 'load',
|
|
296
|
+
timeStamp: res.timeStamp,
|
|
297
|
+
detail: {
|
|
298
|
+
src
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
bindload?.(result)
|
|
302
|
+
}
|
|
208
303
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
304
|
+
const onLoadEnd = function (res: WebViewEvent) {
|
|
305
|
+
if (__mpx_mode__ === 'android') {
|
|
306
|
+
setTimeout(() => {
|
|
307
|
+
onLoadEndHandle(res)
|
|
308
|
+
}, 0)
|
|
309
|
+
} else {
|
|
310
|
+
onLoadEndHandle(res)
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const onHttpError = function (res: WebViewHttpErrorEvent) {
|
|
314
|
+
isLoadError.current = true
|
|
315
|
+
statusCode.current = res.nativeEvent?.statusCode
|
|
316
|
+
}
|
|
317
|
+
const onError = function () {
|
|
318
|
+
statusCode.current = ''
|
|
319
|
+
isLoadError.current = true
|
|
320
|
+
if (!fristLoaded.current) {
|
|
321
|
+
setPageLoadErr(true)
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
const onLoadStart = function () {
|
|
325
|
+
if (!fristLoaded.current) {
|
|
326
|
+
setIsLoaded(false)
|
|
327
|
+
}
|
|
213
328
|
}
|
|
214
|
-
extendObject(events, {
|
|
215
|
-
onMessage: _message
|
|
216
|
-
})
|
|
217
329
|
|
|
218
|
-
return
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
330
|
+
return (
|
|
331
|
+
<Portal key={pageLoadErr ? 'error' : 'webview'}>
|
|
332
|
+
{pageLoadErr
|
|
333
|
+
? (
|
|
334
|
+
<View style={[styles.loadErrorContext, defaultWebViewStyle]}>
|
|
335
|
+
<View style={styles.loadErrorText}><Text style={{ fontSize: 14, color: '#999999' }}>{currentErrorText.text}</Text></View>
|
|
336
|
+
<View style={styles.loadErrorButton} onTouchEnd={_reload}><Text style={{ fontSize: 12, color: '#666666' }}>{currentErrorText.button}</Text></View>
|
|
337
|
+
</View>
|
|
338
|
+
)
|
|
339
|
+
: (<WebView
|
|
340
|
+
style={ defaultWebViewStyle }
|
|
341
|
+
source={{ uri: src }}
|
|
342
|
+
ref={webViewRef}
|
|
343
|
+
javaScriptEnabled={true}
|
|
344
|
+
onNavigationStateChange={_changeUrl}
|
|
345
|
+
onMessage={_message}
|
|
346
|
+
injectedJavaScript={injectedJavaScript}
|
|
347
|
+
onLoadProgress={_onLoadProgress}
|
|
348
|
+
onLoadEnd={onLoadEnd}
|
|
349
|
+
onHttpError={onHttpError}
|
|
350
|
+
onError={onError}
|
|
351
|
+
onLoadStart={onLoadStart}
|
|
352
|
+
allowsBackForwardNavigationGestures={isLoaded}
|
|
353
|
+
></WebView>)}
|
|
354
|
+
</Portal>
|
|
355
|
+
)
|
|
225
356
|
})
|
|
226
357
|
|
|
227
358
|
_WebView.displayName = 'MpxWebview'
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
declare let __mpx_mode__: 'wx' | 'ali' | 'swan' | 'qq' | 'tt' | 'web' | 'dd' | 'qa' | 'jd' | 'android' | 'ios'
|
|
1
2
|
declare module '@mpxjs/utils' {
|
|
2
3
|
export function isEmptyObject (obj: Object): boolean
|
|
3
4
|
export function isFunction (fn: unknown): boolean
|
|
@@ -20,6 +21,11 @@ declare module '@mpxjs/utils' {
|
|
|
20
21
|
left: number
|
|
21
22
|
right: number
|
|
22
23
|
},
|
|
24
|
+
setOptions: (params: Record<string, any>) => void,
|
|
25
|
+
addListener: (eventName: string, callback: (e: Event) => void) => void
|
|
26
|
+
removeListener: (eventName: string, callback: (e: Event) => void) => void
|
|
27
|
+
dispatch: (eventName: string) => void
|
|
28
|
+
pageId: number
|
|
23
29
|
layout: {
|
|
24
30
|
x: number
|
|
25
31
|
y: number
|
|
@@ -37,3 +43,5 @@ declare let global: {
|
|
|
37
43
|
declare module '@react-navigation/native' {
|
|
38
44
|
export function useNavigation (): Record<string, any>
|
|
39
45
|
}
|
|
46
|
+
|
|
47
|
+
declare module '*.png'
|
|
@@ -40,10 +40,10 @@ export type AnimationProp = {
|
|
|
40
40
|
// 微信 timingFunction 和 RN Easing 对应关系
|
|
41
41
|
const EasingKey = {
|
|
42
42
|
linear: Easing.linear,
|
|
43
|
-
ease: Easing.ease,
|
|
44
|
-
'ease-in': Easing.in(Easing.
|
|
45
|
-
'ease-in-out': Easing.inOut(Easing.
|
|
46
|
-
'ease-out': Easing.out(Easing.
|
|
43
|
+
ease: Easing.inOut(Easing.ease),
|
|
44
|
+
'ease-in': Easing.in(Easing.poly(3)),
|
|
45
|
+
'ease-in-out': Easing.inOut(Easing.poly(3)),
|
|
46
|
+
'ease-out': Easing.out(Easing.poly(3))
|
|
47
47
|
// 'step-start': '',
|
|
48
48
|
// 'step-end': ''
|
|
49
49
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { useEffect, useCallback, useMemo, useRef, ReactNode, ReactElement, isValidElement, useContext, useState, Dispatch, SetStateAction, Children, cloneElement } from 'react'
|
|
2
2
|
import { LayoutChangeEvent, TextStyle, ImageProps, Image, Platform } from 'react-native'
|
|
3
3
|
import { isObject, isFunction, isNumber, hasOwn, diffAndCloneA, error, warn } from '@mpxjs/utils'
|
|
4
|
-
import { VarContext, ScrollViewContext } from './context'
|
|
4
|
+
import { VarContext, ScrollViewContext, RouteContext } from './context'
|
|
5
5
|
import { ExpressionParser, parseFunc, ReplaceSource } from './parser'
|
|
6
6
|
import { initialWindowMetrics } from 'react-native-safe-area-context'
|
|
7
|
-
import { useNavigation } from '@react-navigation/native'
|
|
8
7
|
import FastImage, { FastImageProps } from '@d11/react-native-fast-image'
|
|
9
8
|
import type { AnyFunc, ExtendedFunctionComponent, ExtendedViewStyle } from './types/common'
|
|
10
9
|
import { runOnJS } from 'react-native-reanimated'
|
|
@@ -40,11 +39,16 @@ const safeAreaInsetMap: Record<string, 'top' | 'right' | 'bottom' | 'left'> = {
|
|
|
40
39
|
'safe-area-inset-left': 'left'
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
function getSafeAreaInset (name: string, navigation: Record<string, any>) {
|
|
42
|
+
function getSafeAreaInset (name: string, navigation: Record<string, any> | undefined) {
|
|
44
43
|
const insets = extendObject({}, initialWindowMetrics?.insets, navigation?.insets)
|
|
45
44
|
return insets[safeAreaInsetMap[name]]
|
|
46
45
|
}
|
|
47
46
|
|
|
47
|
+
export function useNavigation (): Record<string, any> | undefined {
|
|
48
|
+
const { navigation } = useContext(RouteContext) || {}
|
|
49
|
+
return navigation
|
|
50
|
+
}
|
|
51
|
+
|
|
48
52
|
export function omit<T, K extends string> (obj: T, fields: K[]): Omit<T, K> {
|
|
49
53
|
const shallowCopy: any = extendObject({}, obj)
|
|
50
54
|
for (let i = 0; i < fields.length; i += 1) {
|
|
@@ -239,7 +243,7 @@ function transformVar (styleObj: Record<string, any>, varKeyPaths: Array<Array<s
|
|
|
239
243
|
})
|
|
240
244
|
}
|
|
241
245
|
|
|
242
|
-
function transformEnv (styleObj: Record<string, any>, envKeyPaths: Array<Array<string>>, navigation: Record<string, any>) {
|
|
246
|
+
function transformEnv (styleObj: Record<string, any>, envKeyPaths: Array<Array<string>>, navigation: Record<string, any> | undefined) {
|
|
243
247
|
envKeyPaths.forEach((envKeyPath) => {
|
|
244
248
|
setStyle(styleObj, envKeyPath, ({ target, key, value }) => {
|
|
245
249
|
const parsed = parseFunc(value, 'env')
|
|
@@ -518,6 +522,7 @@ export const useLayout = ({ props, hasSelfPercent, setWidth, setHeight, onLayout
|
|
|
518
522
|
const hasLayoutRef = useRef(false)
|
|
519
523
|
const layoutStyle = useMemo(() => { return !hasLayoutRef.current && hasSelfPercent ? HIDDEN_STYLE : {} }, [hasLayoutRef.current])
|
|
520
524
|
const layoutProps: Record<string, any> = {}
|
|
525
|
+
const navigation = useNavigation()
|
|
521
526
|
const enableOffset = props['enable-offset']
|
|
522
527
|
if (hasSelfPercent || onLayout || enableOffset) {
|
|
523
528
|
layoutProps.onLayout = (e: LayoutChangeEvent) => {
|
|
@@ -529,7 +534,8 @@ export const useLayout = ({ props, hasSelfPercent, setWidth, setHeight, onLayout
|
|
|
529
534
|
}
|
|
530
535
|
if (enableOffset) {
|
|
531
536
|
nodeRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => {
|
|
532
|
-
|
|
537
|
+
const { y: navigationY = 0 } = navigation?.layout || {}
|
|
538
|
+
layoutRef.current = { x, y: y - navigationY, width, height, offsetLeft, offsetTop: offsetTop - navigationY }
|
|
533
539
|
})
|
|
534
540
|
}
|
|
535
541
|
onLayout && onLayout(e)
|
|
@@ -628,7 +634,7 @@ export function flatGesture (gestures: Array<GestureHandler> = []) {
|
|
|
628
634
|
|
|
629
635
|
export const extendObject = Object.assign
|
|
630
636
|
|
|
631
|
-
export function getCurrentPage (pageId: number | null) {
|
|
637
|
+
export function getCurrentPage (pageId: number | null | undefined) {
|
|
632
638
|
if (!global.getCurrentPages) return
|
|
633
639
|
const pages = global.getCurrentPages()
|
|
634
640
|
return pages.find((page: any) => isFunction(page.getPageId) && page.getPageId() === pageId)
|
|
@@ -380,7 +380,9 @@ function compileScriptSetup (
|
|
|
380
380
|
|
|
381
381
|
if (node.type === 'ImportDeclaration') {
|
|
382
382
|
// import declarations are moved to top
|
|
383
|
-
|
|
383
|
+
if (start !== 0) {
|
|
384
|
+
_s.move(start, end, 0)
|
|
385
|
+
}
|
|
384
386
|
// dedupe imports
|
|
385
387
|
let removed = 0
|
|
386
388
|
const removeSpecifier = (i) => {
|
|
@@ -533,7 +535,9 @@ function compileScriptSetup (
|
|
|
533
535
|
(node.type === 'VariableDeclaration' && node.declare)
|
|
534
536
|
) {
|
|
535
537
|
recordType(node, declaredTypes)
|
|
536
|
-
|
|
538
|
+
if (node.start !== 0) {
|
|
539
|
+
_s.move(node.start, node.end + 1, 0)
|
|
540
|
+
}
|
|
537
541
|
}
|
|
538
542
|
}
|
|
539
543
|
|
|
@@ -4,7 +4,6 @@ const loadPostcssConfig = require('./load-postcss-config')
|
|
|
4
4
|
const { MPX_ROOT_VIEW, MPX_DISABLE_EXTRACTOR_CACHE } = require('../utils/const')
|
|
5
5
|
const rpx = require('./plugins/rpx')
|
|
6
6
|
const vw = require('./plugins/vw')
|
|
7
|
-
const pluginCondStrip = require('./plugins/conditional-strip')
|
|
8
7
|
const scopeId = require('./plugins/scope-id')
|
|
9
8
|
const transSpecial = require('./plugins/trans-special')
|
|
10
9
|
const cssArrayList = require('./plugins/css-array-list')
|
|
@@ -58,9 +57,9 @@ module.exports = function (css, map) {
|
|
|
58
57
|
plugins.push(transSpecial({ id }))
|
|
59
58
|
}
|
|
60
59
|
|
|
61
|
-
plugins.push(pluginCondStrip({
|
|
62
|
-
|
|
63
|
-
}))
|
|
60
|
+
// plugins.push(pluginCondStrip({
|
|
61
|
+
// defs
|
|
62
|
+
// }))
|
|
64
63
|
|
|
65
64
|
for (const item of transRpxRules) {
|
|
66
65
|
const {
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
class Node {
|
|
2
|
+
constructor (type, condition = null) {
|
|
3
|
+
this.type = type // 'If', 'ElseIf', 'Else' 或 'Text'
|
|
4
|
+
this.condition = condition // If 或 Elif 的条件
|
|
5
|
+
this.children = []
|
|
6
|
+
this.value = ''
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// 提取 css string 为 token
|
|
11
|
+
function tokenize (cssString) {
|
|
12
|
+
const regex = /\/\*\s*@mpx-(if|elif|else|endif)(?:\s*\((.*?)\))?\s*\*\//g
|
|
13
|
+
const tokens = []
|
|
14
|
+
let lastIndex = 0
|
|
15
|
+
let match
|
|
16
|
+
|
|
17
|
+
while ((match = regex.exec(cssString)) !== null) {
|
|
18
|
+
// 如果 token 前有普通文本,生成文本 token
|
|
19
|
+
if (match.index > lastIndex) {
|
|
20
|
+
const text = cssString.substring(lastIndex, match.index)
|
|
21
|
+
tokens.push({ type: 'text', content: text })
|
|
22
|
+
}
|
|
23
|
+
// match[1] 为关键字:if, elif, else, endif
|
|
24
|
+
// match[2] 为条件(如果存在)
|
|
25
|
+
tokens.push({
|
|
26
|
+
type: match[1], // 'if'、'elif'、'else' 或 'endif'
|
|
27
|
+
condition: match[2] ? match[2].trim() : null
|
|
28
|
+
})
|
|
29
|
+
lastIndex = regex.lastIndex
|
|
30
|
+
}
|
|
31
|
+
// 处理结尾剩余的文本
|
|
32
|
+
if (lastIndex < cssString.length) {
|
|
33
|
+
const text = cssString.substring(lastIndex)
|
|
34
|
+
tokens.push({ type: 'text', content: text })
|
|
35
|
+
}
|
|
36
|
+
return tokens
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// parse:将生成的 token 数组构造成嵌套的 AST
|
|
40
|
+
function parse (cssString) {
|
|
41
|
+
const tokens = tokenize(cssString)
|
|
42
|
+
const ast = []
|
|
43
|
+
const nodeStack = []
|
|
44
|
+
let currentChildren = ast
|
|
45
|
+
tokens.forEach(token => {
|
|
46
|
+
if (token.type === 'text') {
|
|
47
|
+
const node = new Node('Text')
|
|
48
|
+
node.value = token.content
|
|
49
|
+
currentChildren.push(node)
|
|
50
|
+
} else if (token.type === 'if') {
|
|
51
|
+
const node = new Node('If', token.condition)
|
|
52
|
+
currentChildren.push(node)
|
|
53
|
+
nodeStack.push(currentChildren)
|
|
54
|
+
currentChildren = node.children
|
|
55
|
+
} else if (token.type === 'elif') {
|
|
56
|
+
if (nodeStack.length === 0) {
|
|
57
|
+
throw new Error('elif without a preceding if')
|
|
58
|
+
}
|
|
59
|
+
currentChildren = nodeStack[nodeStack.length - 1]
|
|
60
|
+
const node = new Node('ElseIf', token.condition)
|
|
61
|
+
currentChildren.push(node)
|
|
62
|
+
currentChildren = node.children
|
|
63
|
+
} else if (token.type === 'else') {
|
|
64
|
+
if (nodeStack.length === 0) {
|
|
65
|
+
throw new Error('else without a preceding if')
|
|
66
|
+
}
|
|
67
|
+
currentChildren = nodeStack[nodeStack.length - 1]
|
|
68
|
+
const node = new Node('Else')
|
|
69
|
+
currentChildren.push(node)
|
|
70
|
+
currentChildren = node.children
|
|
71
|
+
} else if (token.type === 'endif') {
|
|
72
|
+
if (nodeStack.length > 0) {
|
|
73
|
+
currentChildren = nodeStack.pop()
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
return ast
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function evaluateCondition (condition, defs) {
|
|
81
|
+
try {
|
|
82
|
+
const keys = Object.keys(defs)
|
|
83
|
+
const values = keys.map(key => defs[key])
|
|
84
|
+
/* eslint-disable no-new-func */
|
|
85
|
+
const func = new Function(...keys, `return (${condition});`)
|
|
86
|
+
return func(...values)
|
|
87
|
+
} catch (e) {
|
|
88
|
+
console.error(`Error evaluating condition: ${condition}`, e)
|
|
89
|
+
return false
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function traverseAndEvaluate (ast, defs) {
|
|
94
|
+
let output = ''
|
|
95
|
+
let batchedIf = false
|
|
96
|
+
function traverse (nodes) {
|
|
97
|
+
for (const node of nodes) {
|
|
98
|
+
if (node.type === 'Text') {
|
|
99
|
+
output += node.value
|
|
100
|
+
} else if (node.type === 'If') {
|
|
101
|
+
// 直接判断 If 节点
|
|
102
|
+
batchedIf = false
|
|
103
|
+
if (evaluateCondition(node.condition, defs)) {
|
|
104
|
+
traverse(node.children)
|
|
105
|
+
batchedIf = true
|
|
106
|
+
}
|
|
107
|
+
} else if (node.type === 'ElseIf' && !batchedIf) {
|
|
108
|
+
if (evaluateCondition(node.condition, defs)) {
|
|
109
|
+
traverse(node.children)
|
|
110
|
+
batchedIf = true
|
|
111
|
+
}
|
|
112
|
+
} else if (node.type === 'Else' && !batchedIf) {
|
|
113
|
+
traverse(node.children)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
traverse(ast)
|
|
118
|
+
return output
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports = function (css) {
|
|
122
|
+
this.cacheable()
|
|
123
|
+
const mpx = this.getMpx()
|
|
124
|
+
const defs = mpx.defs
|
|
125
|
+
const ast = parse(css)
|
|
126
|
+
return traverseAndEvaluate(ast, defs)
|
|
127
|
+
}
|