@mpxjs/webpack-plugin 2.10.18 → 2.10.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/lib/dependencies/ResolveDependency.js +2 -2
  2. package/lib/index.js +25 -6
  3. package/lib/json-compiler/helper.js +11 -10
  4. package/lib/json-compiler/index.js +7 -4
  5. package/lib/json-compiler/plugin.js +4 -4
  6. package/lib/loader.js +4 -4
  7. package/lib/native-loader.js +4 -4
  8. package/lib/platform/create-diagnostic.js +168 -0
  9. package/lib/platform/index.js +16 -3
  10. package/lib/platform/json/wx/index.js +66 -17
  11. package/lib/platform/run-rules.js +9 -5
  12. package/lib/platform/style/wx/index.js +4 -3
  13. package/lib/platform/template/normalize-component-rules.js +7 -9
  14. package/lib/platform/template/wx/component-config/camera.js +12 -0
  15. package/lib/platform/template/wx/component-config/custom-built-in-component.js +34 -0
  16. package/lib/platform/template/wx/component-config/index.js +18 -3
  17. package/lib/platform/template/wx/component-config/input.js +1 -7
  18. package/lib/platform/template/wx/component-config/movable-view.js +1 -7
  19. package/lib/platform/template/wx/component-config/text.js +1 -1
  20. package/lib/platform/template/wx/component-config/textarea.js +1 -25
  21. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  22. package/lib/platform/template/wx/index.js +48 -34
  23. package/lib/react/processJSON.js +7 -4
  24. package/lib/react/processStyles.js +22 -8
  25. package/lib/react/processTemplate.js +85 -41
  26. package/lib/react/style-helper.js +120 -85
  27. package/lib/react/template-loader.js +148 -0
  28. package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +1 -1
  29. package/lib/runtime/components/react/dist/mpx-camera.d.ts +31 -0
  30. package/lib/runtime/components/react/dist/mpx-camera.jsx +270 -0
  31. package/lib/runtime/components/react/dist/mpx-image.d.ts +0 -1
  32. package/lib/runtime/components/react/dist/mpx-image.jsx +1 -2
  33. package/lib/runtime/components/react/dist/mpx-picker/type.d.ts +1 -1
  34. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +92 -15
  35. package/lib/runtime/components/react/dist/mpx-web-view.jsx +1 -1
  36. package/lib/runtime/components/react/dist/utils.jsx +3 -2
  37. package/lib/runtime/components/react/mpx-async-suspense.tsx +2 -1
  38. package/lib/runtime/components/react/mpx-camera.tsx +358 -0
  39. package/lib/runtime/components/react/mpx-image.tsx +1 -3
  40. package/lib/runtime/components/react/mpx-picker/type.ts +1 -1
  41. package/lib/runtime/components/react/mpx-scroll-view.tsx +106 -16
  42. package/lib/runtime/components/react/mpx-web-view.tsx +1 -1
  43. package/lib/runtime/components/react/utils.tsx +3 -2
  44. package/lib/runtime/components/wx/default-component.mpx +9 -0
  45. package/lib/runtime/components/wx/default-page.mpx +3 -11
  46. package/lib/runtime/optionProcessor.d.ts +2 -0
  47. package/lib/runtime/optionProcessor.js +77 -1
  48. package/lib/style-compiler/index.js +2 -0
  49. package/lib/style-compiler/plugins/remove-strip-conditional-comments.js +14 -0
  50. package/lib/style-compiler/strip-conditional.js +40 -26
  51. package/lib/template-compiler/compiler.js +274 -116
  52. package/lib/template-compiler/gen-node-react.js +35 -7
  53. package/lib/template-compiler/index.js +9 -7
  54. package/lib/utils/const.js +4 -1
  55. package/lib/utils/dom-tag-config.js +1 -1
  56. package/lib/utils/partial-compile-rules.js +27 -0
  57. package/lib/utils/pre-process-json.js +3 -0
  58. package/lib/utils/source-location.js +96 -0
  59. package/lib/web/compile-wx-template-fragment.js +68 -0
  60. package/lib/web/index.js +2 -0
  61. package/lib/web/processJSON.js +7 -4
  62. package/lib/web/processScript.js +41 -3
  63. package/lib/web/processTemplate.js +61 -19
  64. package/lib/web/template-loader.js +123 -0
  65. package/lib/web/template-shared.js +48 -0
  66. package/lib/wxml/loader.js +3 -2
  67. package/lib/wxss/loader.js +1 -1
  68. package/lib/wxss/utils.js +6 -4
  69. package/package.json +12 -4
  70. package/lib/platform/template/wx/component-config/component.js +0 -41
@@ -0,0 +1,358 @@
1
+ import { createElement, forwardRef, useRef, useCallback, useContext, useState, useEffect, useMemo } from 'react'
2
+ import { getCurrentPage, useTransformStyle, useLayout, extendObject } from './utils'
3
+ import useInnerProps, { getCustomEvent } from './getInnerListeners'
4
+ import { Camera, useCameraDevice, useCodeScanner, useCameraFormat } from 'react-native-vision-camera'
5
+ import { noop, warn, hasOwn } from '@mpxjs/utils'
6
+ import { RouteContext } from './context'
7
+ import { watch, WatchOptions } from '@mpxjs/core'
8
+
9
+ const qualityValue = {
10
+ high: 90,
11
+ normal: 75,
12
+ low: 50,
13
+ original: 100
14
+ }
15
+
16
+ interface CameraProps {
17
+ mode?: 'normal' | 'scanCode'
18
+ resolution?: 'low' | 'medium' | 'high'
19
+ 'device-position'?: 'front' | 'back'
20
+ flash?: 'auto' | 'on' | 'off'
21
+ 'frame-size'?: 'small' | 'medium' | 'large'
22
+ style?: Record<string, any>
23
+ bindstop?: () => void
24
+ binderror?: (error: { message: string }) => void
25
+ bindinitdone?: (result: { type: string, data: string }) => void
26
+ bindscancode?: (result: { type: string, data: string }) => void
27
+ 'parent-font-size'?: number
28
+ 'parent-width'?: number
29
+ 'parent-height'?: number
30
+ 'enable-var'?: boolean
31
+ 'external-var-context'?: any
32
+ }
33
+
34
+ interface TakePhotoOptions {
35
+ quality?: 'high' | 'normal' | 'low' | 'original'
36
+ success?: (result: { errMsg: string, tempImagePath: string }) => void
37
+ fail?: (result: { errMsg: string }) => void
38
+ complete?: (result: { errMsg: string, tempImagePath?: string }) => void
39
+ }
40
+
41
+ interface RecordOptions {
42
+ timeout?: number
43
+ success?: (result: { errMsg: string }) => void
44
+ fail?: (result: { errMsg: string, error?: any }) => void
45
+ complete?: (result: { errMsg: string }) => void
46
+ timeoutCallback?: (result: { errMsg: string, error?: any }) => void
47
+ }
48
+
49
+ interface StopRecordOptions {
50
+ success?: (result: { errMsg: string, tempVideoPath: string, duration: number }) => void
51
+ fail?: (result: { errMsg: string }) => void
52
+ complete?: (result: { errMsg: string, tempVideoPath?: string, duration?: number }) => void
53
+ }
54
+
55
+ interface CameraRef {
56
+ setZoom: (zoom: number) => void
57
+ takePhoto: (options?: TakePhotoOptions) => void
58
+ startRecord: (options?: RecordOptions) => void
59
+ stopRecord: (options?: StopRecordOptions) => void
60
+ }
61
+
62
+ type HandlerRef<T, P> = {
63
+ current: T | null
64
+ }
65
+
66
+ let RecordRes: any = null
67
+
68
+ const _camera = forwardRef<HandlerRef<any, CameraProps>, CameraProps>((props: CameraProps, ref): JSX.Element | null => {
69
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
70
+ const cameraRef = useRef<any>(null)
71
+ const {
72
+ mode = 'normal',
73
+ resolution = 'medium',
74
+ 'device-position': devicePosition = 'back',
75
+ flash = 'auto',
76
+ 'frame-size': frameSize = 'medium',
77
+ bindinitdone,
78
+ bindstop,
79
+ bindscancode,
80
+ 'parent-font-size': parentFontSize,
81
+ 'parent-width': parentWidth,
82
+ 'parent-height': parentHeight,
83
+ 'enable-var': enableVar,
84
+ 'external-var-context': externalVarContext,
85
+ style = {}
86
+ } = props
87
+ const styleObj = extendObject(
88
+ {},
89
+ style
90
+ )
91
+ const {
92
+ normalStyle,
93
+ hasSelfPercent,
94
+ setWidth,
95
+ setHeight
96
+ } = useTransformStyle(styleObj, {
97
+ enableVar,
98
+ externalVarContext,
99
+ parentFontSize,
100
+ parentWidth,
101
+ parentHeight
102
+ })
103
+ const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: cameraRef })
104
+ const isPhoto = useRef<boolean>(false)
105
+ isPhoto.current = mode === 'normal'
106
+ const device = useCameraDevice(devicePosition || 'back')
107
+ const { navigation, pageId } = useContext(RouteContext) || {}
108
+ const [zoomValue, setZoomValue] = useState<number>(1)
109
+ const [isActive, setIsActive] = useState<boolean>(true)
110
+ const [hasPermission, setHasPermission] = useState<boolean | null>(null)
111
+ const page = getCurrentPage(pageId)
112
+
113
+ // 先定义常量,避免在条件判断后使用
114
+ const maxZoom = device?.maxZoom || 1
115
+ const RESOLUTION_MAPPING: Record<string, { width: number, height: number } | 'max'> = {
116
+ low: { width: 1280, height: 720 },
117
+ medium: { width: 1920, height: 1080 },
118
+ high: 'max'
119
+ }
120
+ const FRAME_SIZE_MAPPING: Record<string, { width: number, height: number } | 'max'> = {
121
+ small: { width: 1280, height: 720 },
122
+ medium: { width: 1920, height: 1080 },
123
+ large: 'max'
124
+ }
125
+
126
+ const format = useCameraFormat(device, [
127
+ {
128
+ photoResolution: RESOLUTION_MAPPING[resolution],
129
+ videoResolution: FRAME_SIZE_MAPPING[frameSize] || RESOLUTION_MAPPING[resolution]
130
+ }
131
+ ])
132
+ const isScancode = useCallback((fail: (res: { errMsg: string }) => void, complete: (res: { errMsg: string }) => void) => {
133
+ if (!isPhoto.current) {
134
+ const result = {
135
+ errMsg: 'Not allow to invoke takePhoto in \'scanCode\' mode.'
136
+ }
137
+ fail(result)
138
+ complete(result)
139
+ return true
140
+ }
141
+ return false
142
+ }, [])
143
+ const codeScanner = useCodeScanner({
144
+ codeTypes: ['qr'],
145
+ onCodeScanned: (codes: any[]) => {
146
+ codes.forEach(code => {
147
+ const type = code.type === 'qr' ? 'QR_CODE' : code.type?.toUpperCase()
148
+ const frame = code.frame || {}
149
+ bindscancode && bindscancode(getCustomEvent('scancode', {}, {
150
+ detail: {
151
+ result: code.value,
152
+ type,
153
+ scanArea: [parseInt(frame.x) || 0, parseInt(frame.y) || 0, parseInt(frame.width) || 0, parseInt(frame.height) || 0]
154
+ }
155
+ }))
156
+ })
157
+ }
158
+ })
159
+
160
+ const onInitialized = useCallback(() => {
161
+ bindinitdone && bindinitdone(getCustomEvent('initdone', {}, {
162
+ detail: {
163
+ maxZoom
164
+ }
165
+ }))
166
+ }, [bindinitdone, maxZoom])
167
+
168
+ const onStopped = useCallback(() => {
169
+ bindstop && bindstop()
170
+ }, [bindstop])
171
+
172
+ const camera: CameraRef = useMemo(() => ({
173
+ setZoom: (zoom: number) => {
174
+ setZoomValue(zoom)
175
+ },
176
+ takePhoto: (options: TakePhotoOptions = {}) => {
177
+ const { success = noop, fail = noop, complete = noop } = options
178
+ if (isScancode(fail, complete)) return
179
+ cameraRef.current?.takePhoto?.({
180
+ quality: qualityValue[options.quality || 'normal'] as number
181
+ } as any).then((res: { path: any }) => {
182
+ const result = {
183
+ errMsg: 'takePhoto:ok',
184
+ tempImagePath: res.path
185
+ }
186
+ success(result)
187
+ complete(result)
188
+ }).catch(() => {
189
+ const result = {
190
+ errMsg: 'takePhoto:fail'
191
+ }
192
+ fail(result)
193
+ complete(result)
194
+ })
195
+ },
196
+ startRecord: (options: RecordOptions = {}) => {
197
+ let { timeout = 30, success = noop, fail = noop, complete = noop, timeoutCallback = noop } = options
198
+ timeout = timeout > 300 ? 300 : timeout
199
+ let recordTimer: NodeJS.Timeout | null = null
200
+ if (isScancode(fail, complete)) return
201
+ try {
202
+ const result = {
203
+ errMsg: 'startRecord:ok'
204
+ }
205
+ success(result)
206
+ complete(result)
207
+
208
+ cameraRef.current?.startRecording?.({
209
+ onRecordingError: (error: any) => {
210
+ if (recordTimer) clearTimeout(recordTimer)
211
+ const errorResult = {
212
+ errMsg: 'startRecord:fail during recording',
213
+ error: error
214
+ }
215
+ timeoutCallback(errorResult)
216
+ },
217
+ onRecordingFinished: (video: any) => {
218
+ RecordRes = video
219
+ if (recordTimer) clearTimeout(recordTimer)
220
+ }
221
+ })
222
+
223
+ recordTimer = setTimeout(() => { // 超时自动停止
224
+ cameraRef.current?.stopRecording().catch(() => {
225
+ // 忽略停止录制时的错误
226
+ })
227
+ }, timeout * 1000)
228
+ } catch (error: any) {
229
+ if (recordTimer) clearTimeout(recordTimer)
230
+ const result = {
231
+ errMsg: 'startRecord:fail ' + (error.message || 'unknown error')
232
+ }
233
+ fail(result)
234
+ complete(result)
235
+ }
236
+ },
237
+ stopRecord: (options: StopRecordOptions = {}) => {
238
+ const { success = noop, fail = noop, complete = noop } = options
239
+ if (isScancode(fail, complete)) return
240
+ try {
241
+ cameraRef.current?.stopRecording().then(() => {
242
+ setTimeout(() => {
243
+ if (RecordRes) {
244
+ const result = {
245
+ errMsg: 'stopRecord:ok',
246
+ tempVideoPath: RecordRes?.path,
247
+ duration: RecordRes.duration * 1000 // 转成ms
248
+ }
249
+ RecordRes = null
250
+ success(result)
251
+ complete(result)
252
+ }
253
+ }, 200) // 延时200ms,确保录制结果已准备好
254
+ }).catch((e: any) => {
255
+ const result = {
256
+ errMsg: 'stopRecord:fail ' + (e.message || 'promise rejected')
257
+ }
258
+ fail(result)
259
+ complete(result)
260
+ })
261
+ } catch (error: any) {
262
+ const result = {
263
+ errMsg: 'stopRecord:fail ' + (error.message || 'unknown error')
264
+ }
265
+ fail(result)
266
+ complete(result)
267
+ }
268
+ }
269
+ }), [])
270
+
271
+ useEffect(() => {
272
+ let unWatch: any
273
+ if (pageId && hasOwn(global.__mpxPageStatusMap, String(pageId))) {
274
+ unWatch = watch(() => global.__mpxPageStatusMap[pageId], (newVal: string) => {
275
+ if (newVal === 'show') {
276
+ if (page.id === pageId) {
277
+ setIsActive(true)
278
+ }
279
+ }
280
+ if (newVal === 'hide') {
281
+ setIsActive(false)
282
+ }
283
+ }, { sync: true } as WatchOptions)
284
+ }
285
+ const checkCameraPermission = async () => {
286
+ try {
287
+ const cameraPermission = global?.__mpx?.config?.rnConfig?.cameraPermission
288
+ if (typeof cameraPermission === 'function') {
289
+ const permissionResult = await cameraPermission()
290
+ setHasPermission(permissionResult === true)
291
+ } else {
292
+ setHasPermission(true)
293
+ }
294
+ } catch (error) {
295
+ setHasPermission(false)
296
+ }
297
+ }
298
+ checkCameraPermission()
299
+ return () => {
300
+ if (navigation?.camera === camera) {
301
+ delete navigation.camera
302
+ }
303
+ unWatch && unWatch()
304
+ }
305
+ }, [])
306
+
307
+ const innerProps:any = useInnerProps(
308
+ extendObject(
309
+ {},
310
+ props,
311
+ layoutProps,
312
+ {
313
+ ref: cameraRef,
314
+ style: extendObject({}, normalStyle, layoutStyle),
315
+ isActive,
316
+ photo: true,
317
+ video: true,
318
+ onInitialized,
319
+ onStopped,
320
+ device,
321
+ format,
322
+ codeScanner: !isPhoto.current ? codeScanner : undefined,
323
+ zoom: zoomValue,
324
+ torch: flash
325
+ }
326
+ ),
327
+ [
328
+ 'mode',
329
+ 'resolution',
330
+ 'frame-size',
331
+ 'bindinitdone',
332
+ 'bindstop',
333
+ 'flash',
334
+ 'bindscancode',
335
+ 'binderror'
336
+ ],
337
+ {
338
+ layoutRef
339
+ }
340
+ )
341
+
342
+ if (navigation && navigation.camera && navigation.camera !== camera) {
343
+ warn('<camera>: 一个页面只能插入一个')
344
+ return null
345
+ } else if (navigation) {
346
+ navigation.camera = camera
347
+ }
348
+
349
+ if (!hasPermission || !device) {
350
+ return null
351
+ }
352
+
353
+ return createElement(Camera, innerProps)
354
+ })
355
+
356
+ _camera.displayName = 'MpxCamera'
357
+
358
+ export default _camera
@@ -48,7 +48,6 @@ export type Mode =
48
48
  export interface ImageProps {
49
49
  src?: string
50
50
  mode?: Mode
51
- svg?: boolean
52
51
  style?: ImageStyle & Record<string, any>
53
52
  'enable-offset'?: boolean
54
53
  'enable-var'?: boolean
@@ -456,8 +455,7 @@ const Image = forwardRef<HandlerRef<RNImage, ImageProps>, ImageProps>((props, re
456
455
  ),
457
456
  [
458
457
  'src',
459
- 'mode',
460
- 'svg'
458
+ 'mode'
461
459
  ],
462
460
  {
463
461
  layoutRef
@@ -79,7 +79,7 @@ export interface RegionProps extends BasePickerProps {
79
79
  /** 表示选中的省市区,默认选中每一列的第一个值, 默认值 [] */
80
80
  value?: string[]
81
81
  /** 默认值 region */
82
- level?: 'province' | 'city' | 'region' | 'sub-district'
82
+ level?: 'province' | 'city' | 'region'
83
83
  /** 可为每一列的顶部添加一个自定义的项 */
84
84
  'custom-item'?: string
85
85
  /** value 改变时触发 change 事件, event.detail = {value, code, postcode},
@@ -299,22 +299,112 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
299
299
  }
300
300
  }, [refresherTriggered])
301
301
 
302
- function scrollTo ({ top = 0, left = 0, animated = false }: { top?: number; left?: number; animated?: boolean }) {
303
- scrollToOffset(left, top, animated)
302
+ function scrollTo ({ top = 0, left = 0, animated = false, duration }: { top?: number; left?: number; animated?: boolean; duration?: number }) {
303
+ // 如果指定了 duration 且需要动画,使用自定义动画
304
+ if (animated && duration && duration > 0) {
305
+ // 获取当前滚动位置
306
+ const currentY = scrollOptions.current.scrollTop || 0
307
+ const currentX = scrollOptions.current.scrollLeft || 0
308
+
309
+ const startTime = Date.now()
310
+ const deltaY = top - currentY
311
+ const deltaX = left - currentX
312
+
313
+ // 缓动函数:easeInOutCubic
314
+ const easing = (t: number) => {
315
+ return t < 0.5
316
+ ? 4 * t * t * t
317
+ : 1 - Math.pow(-2 * t + 2, 3) / 2
318
+ }
319
+
320
+ // 使用 requestAnimationFrame 实现平滑动画
321
+ const animate = () => {
322
+ const elapsed = Date.now() - startTime
323
+ const progress = Math.min(elapsed / duration, 1) // 0 到 1
324
+
325
+ const easeProgress = easing(progress)
326
+ const nextY = currentY + deltaY * easeProgress
327
+ const nextX = currentX + deltaX * easeProgress
328
+
329
+ if (scrollViewRef.current) {
330
+ scrollViewRef.current.scrollTo({ y: nextY, x: nextX, animated: false })
331
+ }
332
+
333
+ if (progress < 1) {
334
+ requestAnimationFrame(animate)
335
+ } else {
336
+ // 确保最终位置准确
337
+ if (scrollViewRef.current) {
338
+ scrollViewRef.current.scrollTo({ y: top, x: left, animated: false })
339
+ }
340
+ }
341
+ }
342
+
343
+ requestAnimationFrame(animate)
344
+ } else {
345
+ // 使用原生的 scrollTo
346
+ scrollToOffset(left, top, animated)
347
+ }
304
348
  }
305
349
 
306
- function handleScrollIntoView (selector = '', { offset = 0, animated = true } = {}) {
307
- const refs = __selectRef!(`#${selector}`, 'node')
308
- if (!refs) return
309
- const { nodeRef } = refs.getNodeInstance()
310
- nodeRef.current?.measureLayout(
311
- scrollViewRef.current,
312
- (left: number, top: number) => {
313
- const adjustedLeft = scrollX ? left + offset : left
314
- const adjustedTop = scrollY ? top + offset : top
315
- scrollToOffset(adjustedLeft, adjustedTop, animated)
350
+ function handleScrollIntoView (selector = '', { offset = 0, animated = true, duration = undefined }: { offset?: number; animated?: boolean; duration?: number } = {}) {
351
+ try {
352
+ const currentSelectRef = propsRef.current.__selectRef
353
+
354
+ if (!currentSelectRef) {
355
+ const errMsg = '__selectRef is not available. Please ensure the scroll-view component is properly initialized.'
356
+ warn(errMsg)
357
+ return
316
358
  }
317
- )
359
+
360
+ const targetScrollView = scrollViewRef.current
361
+
362
+ if (!targetScrollView) {
363
+ const errMsg = 'scrollViewRef is not ready'
364
+ warn(errMsg)
365
+ return
366
+ }
367
+
368
+ // scroll-into-view prop 按微信规范直传裸 id(如 "section-1"),而 __refs 注册时 key 带 # 或 . 前缀,需补齐才能命中;
369
+ // pageScrollTo 调用方已自带前缀(如 "#section-1")
370
+ const normalizedSelector = selector.startsWith('#') || selector.startsWith('.') ? selector : `#${selector}`
371
+
372
+ // 调用 __selectRef 查找元素
373
+ const refs = currentSelectRef(normalizedSelector, 'node')
374
+ if (!refs) {
375
+ const errMsg = `Element not found for selector: ${normalizedSelector}`
376
+ warn(errMsg)
377
+ return
378
+ }
379
+
380
+ const { nodeRef } = refs.getNodeInstance()
381
+ if (!nodeRef?.current) {
382
+ const errMsg = `Node ref not available for selector: ${normalizedSelector}`
383
+ warn(errMsg)
384
+ return
385
+ }
386
+
387
+ nodeRef.current.measureLayout(
388
+ targetScrollView,
389
+ (left: number, top: number) => {
390
+ const adjustedLeft = scrollX ? left + offset : left
391
+ const adjustedTop = scrollY ? top + offset : top
392
+
393
+ // 使用 scrollTo 方法,支持 duration 参数
394
+ if (duration !== undefined) {
395
+ scrollTo({ left: adjustedLeft, top: adjustedTop, animated, duration })
396
+ } else {
397
+ scrollToOffset(adjustedLeft, adjustedTop, animated)
398
+ }
399
+ },
400
+ (error: any) => {
401
+ warn(`Failed to measure layout for selector ${normalizedSelector}: ${error}`)
402
+ }
403
+ )
404
+ } catch (error: any) {
405
+ const errMsg = `handleScrollIntoView error for selector ${selector}: ${error?.message || error}`
406
+ warn(errMsg)
407
+ }
318
408
  }
319
409
 
320
410
  function selectLength (size: { height: number; width: number }) {
@@ -641,9 +731,9 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
641
731
 
642
732
  // 处理下拉刷新的手势 - 使用 useMemo 避免每次渲染都创建
643
733
  const panGesture = useMemo(() => {
644
- if (!hasRefresher) return Gesture.Pan() // 返回空手势
645
-
646
734
  return Gesture.Pan()
735
+ .activeOffsetY([-5, 5])
736
+ .failOffsetX([-5, 5])
647
737
  .onUpdate((event) => {
648
738
  'worklet'
649
739
  if (enhanced && !!bounces) {
@@ -703,7 +793,7 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
703
793
  }
704
794
  })
705
795
  .simultaneousWithExternalGesture(scrollViewRef)
706
- }, [hasRefresher, enhanced, bounces, refreshing, refresherThreshold])
796
+ }, [enhanced, bounces, refreshing, refresherThreshold])
707
797
 
708
798
  const scrollAdditionalProps: ScrollAdditionalProps = extendObject(
709
799
  {
@@ -234,7 +234,7 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
234
234
  }
235
235
  break
236
236
  case 'postMessage':
237
- bindmessage && bindmessage(getCustomEvent('messsage', {}, { // RN组件销毁顺序与小程序不一致,所以改成和支付宝消息一致
237
+ bindmessage && bindmessage(getCustomEvent('message', {}, { // RN组件销毁顺序与小程序不一致,所以改成和支付宝消息一致
238
238
  detail: {
239
239
  data: params[0]?.data
240
240
  }
@@ -334,8 +334,9 @@ export function parseValues (str: string, char = ' ') {
334
334
  // parse string transform, eg: transform: 'rotateX(45deg) rotateZ(0.785398rad)'
335
335
  function parseTransform (transformStr: string) {
336
336
  const values = parseValues(transformStr)
337
- // Todo transform 排序不一致时,transform动画会闪烁,故这里同样的排序输出 transform
338
- values.sort()
337
+ // Todo 2 RN下顺序不一致转换结果不一致,故这里不处理,动画前后transform 排序不一致的问题,由业务调整写法
338
+ // Todo 1 transform 排序不一致时,transform动画会闪烁,故这里同样的排序输出 transform
339
+ // values.sort()
339
340
  const transform: { [propName: string]: string | number | number[] }[] = []
340
341
  values.forEach(item => {
341
342
  const match = item.match(/([/\w]+)\((.+)\)/)
@@ -0,0 +1,9 @@
1
+ <template>
2
+ <view></view>
3
+ </template>
4
+
5
+ <script>
6
+ import { createComponent } from '@mpxjs/core'
7
+
8
+ createComponent({})
9
+ </script>
@@ -1,6 +1,5 @@
1
1
  <template>
2
- <view>局部构建兜底页面</view>
3
- <view>当前路由:{{currentRoute}}</view>
2
+ <view>局部构建兜底页面:{{pageRoute}}</view>
4
3
  </template>
5
4
 
6
5
  <script>
@@ -10,18 +9,11 @@ import { createPage } from '@mpxjs/core'
10
9
  createPage({
11
10
  data() {
12
11
  return {
13
- currentRoute: '',
12
+ pageRoute: ''
14
13
  }
15
14
  },
16
15
  onLoad() {
17
- this.getPagePath()
18
- },
19
- methods: {
20
- getPagePath() {
21
- const pages = getCurrentPages() || []
22
- const currPage = pages[pages.length - 1]
23
- this.currentRoute = currPage && currPage.route || ''
24
- },
16
+ this.pageRoute = this.route
25
17
  }
26
18
  })
27
19
  </script>
@@ -17,4 +17,6 @@ export function getComponent (...args: any): object
17
17
 
18
18
  export function getWxsMixin (...args: any): object
19
19
 
20
+ export function createTemplateComponent (...args: any): object
21
+
20
22
  export function processAppOption (...args: any): void