@mpxjs/webpack-plugin 2.10.19 → 2.10.21

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 (137) hide show
  1. package/lib/dependencies/ResolveDependency.js +2 -2
  2. package/lib/index.js +38 -7
  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/parser.js +1 -1
  9. package/lib/platform/create-diagnostic.js +168 -0
  10. package/lib/platform/index.js +16 -3
  11. package/lib/platform/json/wx/index.js +66 -17
  12. package/lib/platform/run-rules.js +9 -5
  13. package/lib/platform/style/wx/index.js +82 -33
  14. package/lib/platform/template/normalize-component-rules.js +7 -9
  15. package/lib/platform/template/wx/component-config/block.js +2 -1
  16. package/lib/platform/template/wx/component-config/custom-built-in-component.js +34 -0
  17. package/lib/platform/template/wx/component-config/index.js +18 -3
  18. package/lib/platform/template/wx/component-config/input.js +1 -7
  19. package/lib/platform/template/wx/component-config/movable-view.js +1 -7
  20. package/lib/platform/template/wx/component-config/text.js +1 -1
  21. package/lib/platform/template/wx/component-config/textarea.js +1 -25
  22. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  23. package/lib/platform/template/wx/index.js +48 -34
  24. package/lib/react/processJSON.js +7 -4
  25. package/lib/react/processStyles.js +22 -8
  26. package/lib/react/processTemplate.js +98 -41
  27. package/lib/react/style-helper.js +121 -86
  28. package/lib/react/template-loader.js +161 -0
  29. package/lib/runtime/components/react/context.ts +8 -1
  30. package/lib/runtime/components/react/dist/context.d.ts +6 -1
  31. package/lib/runtime/components/react/dist/context.js +1 -0
  32. package/lib/runtime/components/react/dist/getInnerListeners.js +1 -0
  33. package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +1 -1
  34. package/lib/runtime/components/react/dist/mpx-button.d.ts +1 -1
  35. package/lib/runtime/components/react/dist/mpx-button.jsx +6 -5
  36. package/lib/runtime/components/react/dist/mpx-camera.jsx +1 -0
  37. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +4 -1
  38. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +2 -1
  39. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +6 -4
  40. package/lib/runtime/components/react/dist/mpx-form.jsx +3 -3
  41. package/lib/runtime/components/react/dist/mpx-icon/index.jsx +5 -1
  42. package/lib/runtime/components/react/dist/mpx-image.d.ts +3 -3
  43. package/lib/runtime/components/react/dist/mpx-image.jsx +45 -12
  44. package/lib/runtime/components/react/dist/mpx-inline-text.jsx +10 -6
  45. package/lib/runtime/components/react/dist/mpx-input.jsx +17 -4
  46. package/lib/runtime/components/react/dist/mpx-label.jsx +6 -4
  47. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +19 -4
  48. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +12 -2
  49. package/lib/runtime/components/react/dist/mpx-picker/type.d.ts +1 -1
  50. package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +7 -4
  51. package/lib/runtime/components/react/dist/mpx-portal/index.jsx +5 -1
  52. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +4 -1
  53. package/lib/runtime/components/react/dist/mpx-radio.jsx +5 -4
  54. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +3 -1
  55. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +13 -4
  56. package/lib/runtime/components/react/dist/mpx-simple-text.jsx +52 -6
  57. package/lib/runtime/components/react/dist/mpx-simple-view.jsx +36 -6
  58. package/lib/runtime/components/react/dist/mpx-slider.jsx +2 -1
  59. package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +8 -4
  60. package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +6 -4
  61. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +7 -4
  62. package/lib/runtime/components/react/dist/mpx-swiper.jsx +15 -4
  63. package/lib/runtime/components/react/dist/mpx-switch.jsx +4 -1
  64. package/lib/runtime/components/react/dist/mpx-text.jsx +57 -12
  65. package/lib/runtime/components/react/dist/mpx-video.d.ts +2 -1
  66. package/lib/runtime/components/react/dist/mpx-video.jsx +10 -4
  67. package/lib/runtime/components/react/dist/mpx-view.jsx +42 -7
  68. package/lib/runtime/components/react/dist/utils.d.ts +21 -11
  69. package/lib/runtime/components/react/dist/utils.jsx +105 -35
  70. package/lib/runtime/components/react/getInnerListeners.ts +1 -0
  71. package/lib/runtime/components/react/mpx-async-suspense.tsx +2 -1
  72. package/lib/runtime/components/react/mpx-button.tsx +6 -5
  73. package/lib/runtime/components/react/mpx-camera.tsx +1 -0
  74. package/lib/runtime/components/react/mpx-canvas/index.tsx +4 -1
  75. package/lib/runtime/components/react/mpx-checkbox-group.tsx +2 -1
  76. package/lib/runtime/components/react/mpx-checkbox.tsx +6 -4
  77. package/lib/runtime/components/react/mpx-form.tsx +3 -3
  78. package/lib/runtime/components/react/mpx-icon/index.tsx +5 -1
  79. package/lib/runtime/components/react/mpx-image.tsx +57 -20
  80. package/lib/runtime/components/react/mpx-inline-text.tsx +12 -7
  81. package/lib/runtime/components/react/mpx-input.tsx +17 -4
  82. package/lib/runtime/components/react/mpx-label.tsx +6 -4
  83. package/lib/runtime/components/react/mpx-movable-view.tsx +20 -4
  84. package/lib/runtime/components/react/mpx-picker/index.tsx +12 -2
  85. package/lib/runtime/components/react/mpx-picker/type.ts +1 -1
  86. package/lib/runtime/components/react/mpx-picker-view/index.tsx +8 -4
  87. package/lib/runtime/components/react/mpx-portal/index.tsx +5 -1
  88. package/lib/runtime/components/react/mpx-radio-group.tsx +4 -1
  89. package/lib/runtime/components/react/mpx-radio.tsx +5 -4
  90. package/lib/runtime/components/react/mpx-rich-text/index.tsx +3 -1
  91. package/lib/runtime/components/react/mpx-scroll-view.tsx +13 -4
  92. package/lib/runtime/components/react/mpx-simple-text.tsx +55 -8
  93. package/lib/runtime/components/react/mpx-simple-view.tsx +30 -6
  94. package/lib/runtime/components/react/mpx-slider.tsx +2 -1
  95. package/lib/runtime/components/react/mpx-sticky-header.tsx +8 -4
  96. package/lib/runtime/components/react/mpx-sticky-section.tsx +6 -4
  97. package/lib/runtime/components/react/mpx-swiper-item.tsx +7 -4
  98. package/lib/runtime/components/react/mpx-swiper.tsx +16 -4
  99. package/lib/runtime/components/react/mpx-switch.tsx +4 -1
  100. package/lib/runtime/components/react/mpx-text.tsx +55 -15
  101. package/lib/runtime/components/react/mpx-video.tsx +11 -5
  102. package/lib/runtime/components/react/mpx-view.tsx +35 -7
  103. package/lib/runtime/components/react/types/global.d.ts +4 -0
  104. package/lib/runtime/components/react/utils.tsx +126 -45
  105. package/lib/runtime/components/wx/default-component.mpx +9 -0
  106. package/lib/runtime/components/wx/default-page.mpx +3 -11
  107. package/lib/runtime/optionProcessor.d.ts +2 -0
  108. package/lib/runtime/optionProcessor.js +77 -1
  109. package/lib/runtime/optionProcessorReact.js +5 -0
  110. package/lib/script-setup-compiler/index.js +1 -1
  111. package/lib/style-compiler/index.js +2 -0
  112. package/lib/style-compiler/plugins/remove-strip-conditional-comments.js +14 -0
  113. package/lib/style-compiler/plugins/trans-special.js +1 -1
  114. package/lib/style-compiler/strip-conditional.js +40 -26
  115. package/lib/template-compiler/compiler.js +306 -125
  116. package/lib/template-compiler/gen-node-react.js +35 -7
  117. package/lib/template-compiler/index.js +9 -7
  118. package/lib/utils/const.js +4 -1
  119. package/lib/utils/gen-component-tag.js +1 -5
  120. package/lib/utils/normalize-perf-options.js +47 -0
  121. package/lib/utils/partial-compile-rules.js +27 -0
  122. package/lib/utils/pre-process-json.js +3 -0
  123. package/lib/utils/source-location.js +96 -0
  124. package/lib/web/compile-wx-template-fragment.js +68 -0
  125. package/lib/web/index.js +3 -0
  126. package/lib/web/processJSON.js +7 -4
  127. package/lib/web/processMainScript.js +3 -7
  128. package/lib/web/processScript.js +43 -8
  129. package/lib/web/processStyles.js +12 -3
  130. package/lib/web/processTemplate.js +61 -19
  131. package/lib/web/template-loader.js +123 -0
  132. package/lib/web/template-shared.js +48 -0
  133. package/lib/wxml/loader.js +4 -3
  134. package/lib/wxss/loader.js +1 -1
  135. package/lib/wxss/utils.js +6 -4
  136. package/package.json +12 -4
  137. package/lib/platform/template/wx/component-config/component.js +0 -41
@@ -5,7 +5,7 @@ import Animated, { useAnimatedStyle, useSharedValue, withTiming, Easing, runOnJS
5
5
  import React, { JSX, forwardRef, useRef, useEffect, ReactNode, ReactElement, useMemo, createElement } from 'react'
6
6
  import useInnerProps, { getCustomEvent } from './getInnerListeners'
7
7
  import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数
8
- import { useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren, extendObject, GestureHandler, flatGesture, useRunOnJSCallback } from './utils'
8
+ import { useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren, extendObject, GestureHandler, flatGesture, useRunOnJSCallback, useTextPassThroughValue } from './utils'
9
9
  import { SwiperContext } from './context'
10
10
  import Portal from './mpx-portal'
11
11
  /**
@@ -199,6 +199,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
199
199
  })
200
200
  const { textStyle } = splitStyle(normalStyle)
201
201
  const { textProps } = splitProps(props)
202
+ const textPassThrough = useTextPassThroughValue(textStyle, textProps)
202
203
  const preMargin = props['previous-margin'] ? global.__formatValue(props['previous-margin']) as number : 0
203
204
  const nextMargin = props['next-margin'] ? global.__formatValue(props['next-margin']) as number : 0
204
205
  const preMarginShared = useSharedValue(preMargin)
@@ -278,6 +279,10 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
278
279
  'indicator-dots',
279
280
  'indicator-color',
280
281
  'indicator-width',
282
+ 'indicator-height',
283
+ 'indicator-radius',
284
+ 'indicator-spacing',
285
+ 'indicator-margin',
281
286
  'indicator-active-color',
282
287
  'previous-margin',
283
288
  'vertical',
@@ -287,7 +292,15 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
287
292
  'autoplay',
288
293
  'circular',
289
294
  'interval',
290
- 'easing-function'
295
+ 'easing-function',
296
+ 'current',
297
+ 'duration',
298
+ 'scale',
299
+ 'disableGesture',
300
+ 'wait-for',
301
+ 'simultaneous-handlers',
302
+ 'bindchange'
303
+
291
304
  ], { layoutRef: layoutRef })
292
305
 
293
306
  function onWrapperLayout (e: LayoutChangeEvent) {
@@ -922,8 +935,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
922
935
  }, {
923
936
  hasVarDec,
924
937
  varContext: varContextRef.current,
925
- textStyle,
926
- textProps
938
+ textPassThrough
927
939
  }))
928
940
  const renderChildrens = showPagination ? [animateComponent, renderPagination()] : animateComponent
929
941
  finalComponent = createElement(View, mergeProps, renderChildrens)
@@ -137,7 +137,10 @@ const _Switch = forwardRef<HandlerRef<Switch, _SwitchProps>, _SwitchProps>((prop
137
137
  'checked',
138
138
  'disabled',
139
139
  'type',
140
- 'color'
140
+ 'color',
141
+ 'name',
142
+ 'bindchange',
143
+ 'catchchange'
141
144
  ],
142
145
  { layoutRef }
143
146
  )
@@ -5,11 +5,13 @@
5
5
  * ✔ decode
6
6
  */
7
7
  import { Text, TextStyle, TextProps } from 'react-native'
8
- import { useRef, forwardRef, ReactNode, JSX, createElement, Children } from 'react'
8
+ import { useRef, forwardRef, ReactNode, JSX, createElement, Children, useContext } from 'react'
9
9
  import Portal from './mpx-portal'
10
10
  import useInnerProps from './getInnerListeners'
11
11
  import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数
12
- import { useTransformStyle, wrapChildren, extendObject } from './utils'
12
+ import { useTransformStyle, wrapChildren, extendObject, getDefaultAllowFontScaling, useTextPassThroughValue, isStringChildren, splitStyle } from './utils'
13
+ import { TextPassThroughContext } from './context'
14
+ import * as perf from '@mpxjs/perf'
13
15
 
14
16
  const decodeMap = {
15
17
  '&lt;': '<',
@@ -51,9 +53,17 @@ interface _TextProps extends TextProps {
51
53
  }
52
54
 
53
55
  const _Text = forwardRef<HandlerRef<Text, _TextProps>, _TextProps>((props, ref): JSX.Element => {
56
+ let stopTotal: (() => void) | undefined
57
+ if (__mpx_perf_framework__) stopTotal = perf.scope('text:render:total')
58
+
59
+ // ───── props 阶段 ─────
60
+ let stopProps: (() => void) | undefined
61
+ if (__mpx_perf_framework__) stopProps = perf.scope('text:render:props')
62
+ const inheritedText = useContext(TextPassThroughContext)
63
+ const mergedProps = extendObject({}, inheritedText?.pendingTextProps, props)
54
64
  const {
55
- style = {},
56
- allowFontScaling = false,
65
+ style: currentStyle = {},
66
+ allowFontScaling,
57
67
  selectable,
58
68
  'enable-var': enableVar,
59
69
  'external-var-context': externalVarContext,
@@ -62,35 +72,60 @@ const _Text = forwardRef<HandlerRef<Text, _TextProps>, _TextProps>((props, ref):
62
72
  'parent-width': parentWidth,
63
73
  'parent-height': parentHeight,
64
74
  decode
65
- } = props
75
+ } = mergedProps
76
+ if (__mpx_perf_framework__) stopProps!()
66
77
 
78
+ // ───── style 阶段 ─────
79
+ let stopStyle: (() => void) | undefined
80
+ if (__mpx_perf_framework__) stopStyle = perf.scope('text:render:style')
67
81
  const {
68
82
  normalStyle,
69
83
  hasVarDec,
70
84
  varContextRef,
71
85
  hasPositionFixed
72
- } = useTransformStyle(style, {
86
+ } = useTransformStyle(currentStyle, {
73
87
  enableVar,
74
88
  externalVarContext,
75
89
  parentFontSize,
76
90
  parentWidth,
77
91
  parentHeight
78
92
  })
93
+ const finalStyle = extendObject({}, inheritedText?.textStyle, normalStyle)
79
94
 
80
95
  const nodeRef = useRef(null)
81
- useNodesRef<Text, _TextProps>(props, ref, nodeRef, {
82
- style: normalStyle
96
+ useNodesRef<Text, _TextProps>(mergedProps, ref, nodeRef, {
97
+ style: finalStyle
83
98
  })
84
99
 
100
+ const children = decode ? getDecodedChildren(mergedProps.children) : mergedProps.children
101
+ const isStringOnly = isStringChildren(children)
102
+ let childTextStyle: TextStyle | undefined
103
+ if (!isStringOnly) {
104
+ const { textStyle = {} } = splitStyle(finalStyle)
105
+ childTextStyle = Object.keys(textStyle).length ? textStyle : undefined
106
+ }
107
+ const textPassThrough = useTextPassThroughValue(
108
+ childTextStyle,
109
+ undefined,
110
+ {
111
+ inheritTextProps: false,
112
+ disabled: isStringOnly
113
+ }
114
+ )
115
+ if (__mpx_perf_framework__) stopStyle!()
116
+
117
+ // ───── innerProps 阶段 ─────
118
+ let stopInnerProps: (() => void) | undefined
119
+ if (__mpx_perf_framework__) stopInnerProps = perf.scope('text:render:innerProps')
85
120
  const innerProps = useInnerProps(
86
121
  extendObject(
87
122
  {},
88
- props,
123
+ mergedProps,
89
124
  {
90
125
  ref: nodeRef,
91
- style: normalStyle,
126
+ style: finalStyle,
92
127
  selectable: !!selectable || !!userSelect,
93
- allowFontScaling
128
+ allowFontScaling: allowFontScaling ?? getDefaultAllowFontScaling()
94
129
  }
95
130
  ),
96
131
  [
@@ -98,23 +133,28 @@ const _Text = forwardRef<HandlerRef<Text, _TextProps>, _TextProps>((props, ref):
98
133
  'decode'
99
134
  ]
100
135
  )
136
+ if (__mpx_perf_framework__) stopInnerProps!()
101
137
 
102
- const children = decode ? getDecodedChildren(props.children) : props.children
103
-
138
+ // ───── createElement 阶段 ─────
139
+ let stopCreate: (() => void) | undefined
140
+ if (__mpx_perf_framework__) stopCreate = perf.scope('text:render:createElement')
104
141
  let finalComponent:JSX.Element = createElement(Text, innerProps, wrapChildren(
105
- extendObject({}, props, {
142
+ extendObject({}, mergedProps, {
106
143
  children
107
144
  }),
108
145
  {
109
146
  hasVarDec,
110
- varContext: varContextRef.current
147
+ varContext: varContextRef.current,
148
+ textPassThrough
111
149
  }
112
150
  ))
113
151
 
114
152
  if (hasPositionFixed) {
115
153
  finalComponent = createElement(Portal, null, finalComponent)
116
154
  }
155
+ if (__mpx_perf_framework__) stopCreate!()
117
156
 
157
+ if (__mpx_perf_framework__) stopTotal!()
118
158
  return finalComponent
119
159
  })
120
160
 
@@ -77,7 +77,7 @@ import useNodesRef, { HandlerRef } from './useNodesRef'
77
77
  import Portal from './mpx-portal'
78
78
 
79
79
  interface VideoProps {
80
- src: string
80
+ src: string | ReactVideoSourceProperties | number
81
81
  autoplay?: boolean
82
82
  loop?: boolean
83
83
  muted?: boolean
@@ -321,10 +321,8 @@ const MpxVideo = forwardRef<HandlerRef<View, VideoProps>, VideoProps>((videoProp
321
321
  videoRef.current && videoRef.current.setFullScreen(true)
322
322
  }
323
323
 
324
- const source: ReactVideoSourceProperties = {
325
- uri: src
326
- }
327
- if (isDrm) {
324
+ const source = typeof src === 'string' ? { uri: src } : (typeof src === 'number' ? src : extendObject({}, src))
325
+ if (isDrm && source && typeof source !== 'number') {
328
326
  source.drm = {
329
327
  type: DRMType.FAIRPLAY,
330
328
  certificateUrl: __mpx_mode__ !== 'ios' ? provisionUrl : certificateUrl,
@@ -369,6 +367,14 @@ const MpxVideo = forwardRef<HandlerRef<View, VideoProps>, VideoProps>((videoProp
369
367
  'src',
370
368
  'autoplay',
371
369
  'loop',
370
+ 'initial-time',
371
+ 'object-fit',
372
+ 'is-drm',
373
+ 'provision-url',
374
+ 'certificate-url',
375
+ 'license-url',
376
+ 'preferred-peak-bit-rate',
377
+ 'enable-auto-rotation',
372
378
  'bindplay',
373
379
  'bindpause',
374
380
  'bindended',
@@ -12,8 +12,9 @@ import useAnimationHooks, { AnimationType } from './animationHooks/index'
12
12
  import type { AnimationProp } from './animationHooks/utils'
13
13
  import { ExtendedViewStyle } from './types/common'
14
14
  import useNodesRef, { HandlerRef } from './useNodesRef'
15
- import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout, renderImage, pickStyle, extendObject, useHover } from './utils'
15
+ import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout, renderImage, pickStyle, extendObject, useHover, useTextPassThroughValue } from './utils'
16
16
  import { error, isFunction } from '@mpxjs/utils'
17
+ import * as perf from '@mpxjs/perf'
17
18
  import LinearGradient from 'react-native-linear-gradient'
18
19
  import { GestureDetector, PanGesture } from 'react-native-gesture-handler'
19
20
  import Portal from './mpx-portal'
@@ -681,16 +682,16 @@ interface WrapChildrenConfig {
681
682
  backgroundStyle?: ExtendedViewStyle
682
683
  varContext?: Record<string, any>
683
684
  textProps?: Record<string, any>
685
+ textPassThrough?: ReturnType<typeof useTextPassThroughValue>
684
686
  innerStyle?: Record<string, any>
685
687
  enableFastImage?: boolean
686
688
  }
687
689
 
688
- function wrapWithChildren (props: _ViewProps, { hasVarDec, enableBackground, textStyle, backgroundStyle, varContext, textProps, innerStyle, enableFastImage }: WrapChildrenConfig) {
690
+ function wrapWithChildren (props: _ViewProps, { hasVarDec, enableBackground, backgroundStyle, varContext, textPassThrough, innerStyle, enableFastImage }: WrapChildrenConfig) {
689
691
  const children = wrapChildren(props, {
690
692
  hasVarDec,
691
693
  varContext,
692
- textStyle,
693
- textProps
694
+ textPassThrough
694
695
  })
695
696
 
696
697
  return [
@@ -701,6 +702,13 @@ function wrapWithChildren (props: _ViewProps, { hasVarDec, enableBackground, tex
701
702
  }
702
703
 
703
704
  const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, ref): JSX.Element => {
705
+ // 性能探针 - total
706
+ let stopTotal: (() => void) | undefined
707
+ if (__mpx_perf_framework__) stopTotal = perf.scope('view:render:total')
708
+
709
+ // ───── props 阶段 ─────
710
+ let stopProps: (() => void) | undefined
711
+ if (__mpx_perf_framework__) stopProps = perf.scope('view:render:props')
704
712
  const { textProps, innerProps: props = {} } = splitProps(viewProps)
705
713
  let {
706
714
  style = {},
@@ -734,7 +742,11 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
734
742
  const { isHover, gesture } = useHover({ enableHover, hoverStartTime, hoverStayTime })
735
743
 
736
744
  const styleObj: ExtendedViewStyle = extendObject({}, defaultStyle, style, isHover ? hoverStyle as ExtendedViewStyle : {})
745
+ if (__mpx_perf_framework__) stopProps!()
737
746
 
747
+ // ───── style 阶段 ─────
748
+ let stopStyle: (() => void) | undefined
749
+ if (__mpx_perf_framework__) stopStyle = perf.scope('view:render:style')
738
750
  const {
739
751
  normalStyle,
740
752
  hasSelfPercent,
@@ -752,6 +764,7 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
752
764
  })
753
765
 
754
766
  const { textStyle, backgroundStyle, innerStyle = {} } = splitStyle(normalStyle)
767
+ const textPassThrough = useTextPassThroughValue(textStyle, textProps)
755
768
 
756
769
  enableBackground = enableBackground || !!backgroundStyle
757
770
  const enableBackgroundRef = useRef(enableBackground)
@@ -783,7 +796,11 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
783
796
  style: viewStyle,
784
797
  transitionend
785
798
  })
799
+ if (__mpx_perf_framework__) stopStyle!()
786
800
 
801
+ // ───── innerProps 阶段 ─────
802
+ let stopInnerProps: (() => void) | undefined
803
+ if (__mpx_perf_framework__) stopInnerProps = perf.scope('view:render:innerProps')
787
804
  const innerProps = useInnerProps(
788
805
  extendObject(
789
806
  {},
@@ -795,23 +812,31 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
795
812
  }
796
813
  ),
797
814
  [
815
+ 'animation',
798
816
  'hover-start-time',
799
817
  'hover-stay-time',
800
818
  'hover-style',
801
- 'hover-class'
819
+ 'hover-class',
820
+ 'enable-fast-image',
821
+ 'enable-animation',
822
+ 'bindtransitionend',
823
+ 'catchtransitionend'
802
824
  ],
803
825
  {
804
826
  layoutRef
805
827
  }
806
828
  )
829
+ if (__mpx_perf_framework__) stopInnerProps!()
807
830
 
831
+ // ───── createElement 阶段 ─────
832
+ let stopCreate: (() => void) | undefined
833
+ if (__mpx_perf_framework__) stopCreate = perf.scope('view:render:createElement')
808
834
  const childNode = wrapWithChildren(props, {
809
835
  hasVarDec,
810
836
  enableBackground: enableBackgroundRef.current,
811
- textStyle,
812
837
  backgroundStyle,
813
838
  varContext: varContextRef.current,
814
- textProps,
839
+ textPassThrough,
815
840
  innerStyle,
816
841
  enableFastImage
817
842
  })
@@ -827,6 +852,9 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
827
852
  if (hasPositionFixed) {
828
853
  finalComponent = createElement(Portal, null, finalComponent)
829
854
  }
855
+ if (__mpx_perf_framework__) stopCreate!()
856
+
857
+ if (__mpx_perf_framework__) stopTotal!()
830
858
  return finalComponent
831
859
  })
832
860
 
@@ -1,4 +1,8 @@
1
1
  declare let __mpx_mode__: 'wx' | 'ali' | 'swan' | 'qq' | 'tt' | 'web' | 'dd' | 'qa' | 'jd' | 'android' | 'ios' | 'harmony'
2
+ // 性能探针开关(DefinePlugin 注入)。详见 packages/webpack-plugin/lib/utils/normalize-perf-options.js
3
+ declare const __mpx_perf__: boolean
4
+ declare const __mpx_perf_framework__: boolean
5
+ declare const __mpx_perf_user__: boolean
2
6
  declare module '@mpxjs/utils' {
3
7
  export function isEmptyObject (obj: Object): boolean
4
8
  export function isFunction (fn: unknown): boolean
@@ -1,23 +1,39 @@
1
- import { useEffect, useCallback, useMemo, useRef, ReactNode, ReactElement, isValidElement, useContext, useState, Dispatch, SetStateAction, Children, cloneElement, createElement, MutableRefObject } from 'react'
1
+ import { useEffect, useCallback, useMemo, useRef, ReactNode, ReactElement, isValidElement, useContext, useState, Dispatch, SetStateAction, createElement, MutableRefObject } from 'react'
2
2
  import { LayoutChangeEvent, TextStyle, ImageProps, Image } from 'react-native'
3
3
  import { isObject, isFunction, isNumber, hasOwn, diffAndCloneA, error, warn } from '@mpxjs/utils'
4
- import { VarContext, ScrollViewContext, RouteContext } from './context'
4
+ import { VarContext, ScrollViewContext, RouteContext, TextPassThroughContext, TextPassThroughContextValue } from './context'
5
5
  import { ExpressionParser, parseFunc, ReplaceSource } from './parser'
6
6
  import { initialWindowMetrics } from 'react-native-safe-area-context'
7
- import type { FastImageProps } from '@d11/react-native-fast-image'
8
7
  import type { AnyFunc, ExtendedFunctionComponent } from './types/common'
9
8
  import { Gesture } from 'react-native-gesture-handler'
10
9
 
11
- export const TEXT_STYLE_REGEX = /color|font.*|text.*|letterSpacing|lineHeight|includeFontPadding|writingDirection/
10
+ export const TEXT_STYLE_MAP: Record<string, boolean> = {
11
+ color: true,
12
+ letterSpacing: true,
13
+ lineHeight: true,
14
+ includeFontPadding: true,
15
+ writingDirection: true
16
+ }
12
17
  export const PERCENT_REGEX = /^\s*-?\d+(\.\d+)?%\s*$/
13
18
  export const URL_REGEX = /^\s*url\(["']?(.*?)["']?\)\s*$/
14
- export const SVG_REGEXP = /https?:\/\/.*\.(?:svg)/i
15
- export const BACKGROUND_REGEX = /^background(Image|Size|Repeat|Position)$/
16
- export const TEXT_PROPS_REGEX = /ellipsizeMode|numberOfLines|allowFontScaling/
19
+ export const SVG_REGEXP = /\.svg(?:[?#].*)?$/i
20
+ export const BACKGROUND_STYLE_MAP: Record<string, boolean> = {
21
+ backgroundImage: true,
22
+ backgroundSize: true,
23
+ backgroundRepeat: true,
24
+ backgroundPosition: true
25
+ }
26
+ export const TEXT_PROPS_MAP: Record<string, boolean> = {
27
+ ellipsizeMode: true,
28
+ numberOfLines: true
29
+ }
17
30
  export const DEFAULT_FONT_SIZE = 16
18
31
  export const HIDDEN_STYLE = {
19
32
  opacity: 0
20
33
  }
34
+ export const DEFAULT_BOX_SIZING_STYLE = {
35
+ boxSizing: 'content-box'
36
+ }
21
37
 
22
38
  declare const __mpx_mode__: 'ios' | 'android' | 'harmony'
23
39
 
@@ -30,9 +46,19 @@ const varUseRegExp = /var\(/
30
46
  const unoVarDecRegExp = /^--un-/
31
47
  const unoVarUseRegExp = /var\(--un-/
32
48
  const calcUseRegExp = /calc\(/
33
- const calcPercentExp = /^calc\(.*-?\d+(\.\d+)?%.*\)$/
34
49
  const envUseRegExp = /env\(/
35
- const filterRegExp = /(calc|env|%)/
50
+ const boxSizingAffectingStyleMap: Record<string, boolean> = {
51
+ padding: true,
52
+ paddingTop: true,
53
+ paddingRight: true,
54
+ paddingBottom: true,
55
+ paddingLeft: true,
56
+ borderWidth: true,
57
+ borderTopWidth: true,
58
+ borderRightWidth: true,
59
+ borderBottomWidth: true,
60
+ borderLeftWidth: true
61
+ }
36
62
 
37
63
  const safeAreaInsetMap: Record<string, 'top' | 'right' | 'bottom' | 'left'> = {
38
64
  'safe-area-inset-top': 'top',
@@ -43,6 +69,25 @@ const safeAreaInsetMap: Record<string, 'top' | 'right' | 'bottom' | 'left'> = {
43
69
 
44
70
  export const extendObject = Object.assign
45
71
 
72
+ export function getDefaultAllowFontScaling (): boolean {
73
+ return global.__mpx?.config?.rnConfig?.allowFontScaling ?? false
74
+ }
75
+
76
+ export function transformBoxSizing (style: Record<string, any> = {}, hasBoxSizingAffectingStyle = false) {
77
+ if (hasBoxSizingAffectingStyle && style.boxSizing === undefined) {
78
+ style.boxSizing = global.__mpx?.config?.rnConfig?.defaultBoxSizing ?? DEFAULT_BOX_SIZING_STYLE.boxSizing
79
+ }
80
+ return style
81
+ }
82
+
83
+ export function isBoxSizingAffectingStyle (key: string) {
84
+ return hasOwn(boxSizingAffectingStyleMap, key)
85
+ }
86
+
87
+ function isTextStyle (key: string) {
88
+ return hasOwn(TEXT_STYLE_MAP, key) || key.startsWith('font') || key.startsWith('text')
89
+ }
90
+
46
91
  function getSafeAreaInset (name: string, navigation: Record<string, any> | undefined) {
47
92
  const insets = extendObject({}, initialWindowMetrics?.insets, navigation?.insets)
48
93
  return insets[safeAreaInsetMap[name]]
@@ -107,12 +152,14 @@ export function isText (ele: ReactNode): ele is ReactElement {
107
152
  return false
108
153
  }
109
154
 
110
- export function every (children: ReactNode, callback: (children: ReactNode) => boolean) {
111
- const childrenArray = Array.isArray(children) ? children : [children]
112
- return childrenArray.every((child) => callback(child))
155
+ export function isStringChildren (children: ReactNode) {
156
+ if (typeof children === 'string') return true
157
+ if (!Array.isArray(children)) return false
158
+ return children.every((child) => typeof child === 'string')
113
159
  }
114
160
 
115
161
  type GroupData<T> = Record<string, Partial<T>>
162
+
116
163
  export function groupBy<T extends Record<string, any>> (
117
164
  obj: T,
118
165
  callback: (key: string, val: T[keyof T]) => string,
@@ -126,24 +173,21 @@ export function groupBy<T extends Record<string, any>> (
126
173
  return group
127
174
  }
128
175
 
129
- export function splitStyle<T extends Record<string, any>> (styleObj: T): {
176
+ export function splitStyle<T extends Record<string, any>> (styleObj: T, sideEffect?: (key: string, val: T[keyof T]) => void): {
130
177
  textStyle?: Partial<T>
131
178
  backgroundStyle?: Partial<T>
132
179
  innerStyle?: Partial<T>
133
180
  } {
134
- return groupBy(styleObj, (key) => {
135
- if (TEXT_STYLE_REGEX.test(key)) {
181
+ return groupBy(styleObj, (key, val) => {
182
+ sideEffect && sideEffect(key, val)
183
+ if (isTextStyle(key)) {
136
184
  return 'textStyle'
137
- } else if (BACKGROUND_REGEX.test(key)) {
185
+ } else if (hasOwn(BACKGROUND_STYLE_MAP, key)) {
138
186
  return 'backgroundStyle'
139
187
  } else {
140
188
  return 'innerStyle'
141
189
  }
142
- }) as {
143
- textStyle: Partial<T>
144
- backgroundStyle: Partial<T>
145
- innerStyle: Partial<T>
146
- }
190
+ })
147
191
  }
148
192
  const radiusPercentRule: Record<string, 'height' | 'width'> = {
149
193
  borderTopLeftRadius: 'width',
@@ -334,8 +378,9 @@ export function parseValues (str: string, char = ' ') {
334
378
  // parse string transform, eg: transform: 'rotateX(45deg) rotateZ(0.785398rad)'
335
379
  function parseTransform (transformStr: string) {
336
380
  const values = parseValues(transformStr)
337
- // Todo transform 排序不一致时,transform动画会闪烁,故这里同样的排序输出 transform
338
- values.sort()
381
+ // Todo 2 RN下顺序不一致转换结果不一致,故这里不处理,动画前后transform 排序不一致的问题,由业务调整写法
382
+ // Todo 1 transform 排序不一致时,transform动画会闪烁,故这里同样的排序输出 transform
383
+ // values.sort()
339
384
  const transform: { [propName: string]: string | number | number[] }[] = []
340
385
  values.forEach(item => {
341
386
  const match = item.match(/([/\w]+)\((.+)\)/)
@@ -415,6 +460,7 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { enableV
415
460
  let hasVarDec = false
416
461
  let hasVarUse = false
417
462
  let hasSelfPercent = false
463
+ let hasBoxSizingAffectingStyle = false
418
464
  const varKeyPaths: Array<Array<string>> = []
419
465
  const unoVarKeyPaths: Array<Array<string>> = []
420
466
  const percentKeyPaths: Array<Array<string>> = []
@@ -450,19 +496,20 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { enableV
450
496
  }
451
497
  }
452
498
 
499
+ function boxSizingVisitor ({ key, keyPath }: VisitorArg) {
500
+ if (keyPath.length === 1 && !hasBoxSizingAffectingStyle && isBoxSizingAffectingStyle(key)) {
501
+ hasBoxSizingAffectingStyle = true
502
+ }
503
+ }
504
+
453
505
  function envVisitor ({ value, keyPath }: VisitorArg) {
454
506
  if (envUseRegExp.test(value)) {
455
507
  envKeyPaths.push(keyPath.slice())
456
508
  }
457
509
  }
458
510
 
459
- function calcVisitor ({ key, value, keyPath }: VisitorArg) {
511
+ function calcVisitor ({ value, keyPath }: VisitorArg) {
460
512
  if (calcUseRegExp.test(value)) {
461
- // calc translate & border-radius 的百分比计算
462
- if (hasOwn(selfPercentRule, key) && calcPercentExp.test(value)) {
463
- hasSelfPercent = true
464
- percentKeyPaths.push(keyPath.slice())
465
- }
466
513
  calcKeyPaths.push(keyPath.slice())
467
514
  }
468
515
  }
@@ -479,13 +526,13 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { enableV
479
526
  }
480
527
 
481
528
  function visitOther ({ target, key, value, keyPath }: VisitorArg) {
482
- if (filterRegExp.test(value)) {
529
+ if (typeof value === 'string' && (value.includes('%') || value.includes('calc(') || value.includes('env('))) {
483
530
  [envVisitor, percentVisitor, calcVisitor].forEach(visitor => visitor({ target, key, value, keyPath }))
484
531
  }
485
532
  }
486
533
 
487
534
  // traverse var & generate normalStyle
488
- traverseStyle(styleObj, [varVisitor])
535
+ traverseStyle(styleObj, [varVisitor, boxSizingVisitor])
489
536
  hasVarDec = hasVarDec || !!externalVarContext
490
537
  enableVar = enableVar || hasVarDec || hasVarUse
491
538
  const enableVarRef = useRef(enableVar)
@@ -530,6 +577,9 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { enableV
530
577
  // apply calc
531
578
  transformCalc(normalStyle, calcKeyPaths, (value: string, key: string) => {
532
579
  if (PERCENT_REGEX.test(value)) {
580
+ if (hasOwn(selfPercentRule, key)) {
581
+ hasSelfPercent = true
582
+ }
533
583
  const resolved = resolvePercent(value, key, percentConfig)
534
584
  return typeof resolved === 'number' ? resolved : 0
535
585
  } else {
@@ -551,6 +601,7 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { enableV
551
601
  transformBoxShadow(normalStyle)
552
602
  // transform 字符串格式转化数组格式(先转数组再处理css var)
553
603
  transformTransform(normalStyle)
604
+ transformBoxSizing(normalStyle, hasBoxSizingAffectingStyle)
554
605
 
555
606
  return {
556
607
  hasVarDec,
@@ -613,7 +664,7 @@ export function splitProps<T extends Record<string, any>> (props: T): {
613
664
  innerProps?: Partial<T>
614
665
  } {
615
666
  return groupBy(props, (key) => {
616
- if (TEXT_PROPS_REGEX.test(key)) {
667
+ if (hasOwn(TEXT_PROPS_MAP, key)) {
617
668
  return 'textProps'
618
669
  } else {
619
670
  return 'innerProps'
@@ -667,20 +718,50 @@ export const useLayout = ({ props, hasSelfPercent, setWidth, setHeight, onLayout
667
718
  export interface WrapChildrenConfig {
668
719
  hasVarDec: boolean
669
720
  varContext?: Record<string, any>
670
- textStyle?: TextStyle
671
- textProps?: Record<string, any>
721
+ textPassThrough?: TextPassThroughContextValue | null
672
722
  }
673
723
 
674
- export function wrapChildren (props: Record<string, any> = {}, { hasVarDec, varContext, textStyle, textProps }: WrapChildrenConfig) {
724
+ export interface TextPassThroughValueOptions {
725
+ inheritTextProps?: boolean
726
+ disabled?: boolean
727
+ }
728
+
729
+ export function useTextPassThroughValue (
730
+ textStyle?: TextStyle,
731
+ textProps?: Record<string, any>,
732
+ { inheritTextProps = true, disabled = false }: TextPassThroughValueOptions = {}
733
+ ) {
734
+ const parent = useContext(TextPassThroughContext)
735
+ const valueRef = useRef<TextPassThroughContextValue | null>(null)
736
+
737
+ if (disabled) return null
738
+
739
+ if (!textStyle && !textProps && (inheritTextProps || !parent?.pendingTextProps)) return null
740
+
741
+ const nextTextStyle = textStyle
742
+ ? extendObject({}, parent?.textStyle, textStyle)
743
+ : parent?.textStyle
744
+ const nextTextProps = inheritTextProps
745
+ ? textProps
746
+ ? extendObject({}, parent?.pendingTextProps, textProps)
747
+ : parent?.pendingTextProps
748
+ : textProps
749
+ const nextValue = {
750
+ textStyle: nextTextStyle,
751
+ pendingTextProps: nextTextProps
752
+ }
753
+
754
+ if (diffAndCloneA(valueRef.current, nextValue).diff) {
755
+ valueRef.current = nextValue
756
+ }
757
+
758
+ return valueRef.current
759
+ }
760
+
761
+ export function wrapChildren (props: Record<string, any> = {}, { hasVarDec, varContext, textPassThrough }: WrapChildrenConfig) {
675
762
  let { children } = props
676
- if (textStyle || textProps) {
677
- children = Children.map(children, (child) => {
678
- if (isText(child)) {
679
- const style = extendObject({}, textStyle, child.props.style)
680
- return cloneElement(child, extendObject({}, textProps, { style }))
681
- }
682
- return child
683
- })
763
+ if (textPassThrough) {
764
+ children = <TextPassThroughContext.Provider value={textPassThrough} key='textPassThroughWrap'>{children}</TextPassThroughContext.Provider>
684
765
  }
685
766
  if (hasVarDec && varContext) {
686
767
  children = <VarContext.Provider value={varContext} key='varContextWrap'>{children}</VarContext.Provider>
@@ -754,10 +835,10 @@ export function getCurrentPage (pageId: number | null | undefined) {
754
835
  }
755
836
 
756
837
  export function renderImage (
757
- imageProps: ImageProps | FastImageProps,
838
+ imageProps: ImageProps,
758
839
  enableFastImage = true
759
840
  ) {
760
- let Component: React.ComponentType<ImageProps | FastImageProps> = Image
841
+ let Component = Image
761
842
  if (enableFastImage) {
762
843
  // eslint-disable-next-line @typescript-eslint/no-var-requires
763
844
  const fastImageModule = require('@d11/react-native-fast-image')