@mpxjs/webpack-plugin 2.9.70-alpha.1 → 2.9.70-alpha.2

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 (124) hide show
  1. package/lib/config.js +3 -1
  2. package/lib/file-loader.js +5 -0
  3. package/lib/parser.js +1 -1
  4. package/lib/platform/json/wx/index.js +21 -8
  5. package/lib/platform/style/wx/index.js +51 -54
  6. package/lib/platform/template/wx/component-config/fix-component-name.js +15 -12
  7. package/lib/platform/template/wx/component-config/index.js +1 -1
  8. package/lib/platform/template/wx/component-config/movable-view.js +8 -1
  9. package/lib/platform/template/wx/component-config/picker-view.js +1 -5
  10. package/lib/platform/template/wx/component-config/rich-text.js +8 -0
  11. package/lib/platform/template/wx/component-config/scroll-view.js +1 -1
  12. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  13. package/lib/platform/template/wx/index.js +3 -5
  14. package/lib/react/processScript.js +6 -3
  15. package/lib/react/script-helper.js +5 -1
  16. package/lib/runtime/components/react/context.ts +8 -0
  17. package/lib/runtime/components/react/dist/context.js +0 -2
  18. package/lib/runtime/components/react/dist/getInnerListeners.js +34 -31
  19. package/lib/runtime/components/react/dist/mpx-button.jsx +11 -11
  20. package/lib/runtime/components/react/dist/mpx-canvas/html.js +2 -4
  21. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +5 -1
  22. package/lib/runtime/components/react/dist/mpx-icon/icons/cancel.png +0 -0
  23. package/lib/runtime/components/react/dist/mpx-icon/icons/clear.png +0 -0
  24. package/lib/runtime/components/react/dist/mpx-icon/icons/download.png +0 -0
  25. package/lib/runtime/components/react/dist/mpx-icon/icons/info.png +0 -0
  26. package/lib/runtime/components/react/dist/mpx-icon/icons/search.png +0 -0
  27. package/lib/runtime/components/react/dist/mpx-icon/icons/success.png +0 -0
  28. package/lib/runtime/components/react/dist/mpx-icon/icons/success_no_circle.png +0 -0
  29. package/lib/runtime/components/react/dist/mpx-icon/icons/waiting.png +0 -0
  30. package/lib/runtime/components/react/dist/mpx-icon/icons/warn.png +0 -0
  31. package/lib/runtime/components/react/dist/mpx-icon/index.jsx +50 -0
  32. package/lib/runtime/components/react/dist/mpx-image.jsx +12 -15
  33. package/lib/runtime/components/react/dist/mpx-input.jsx +10 -8
  34. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +92 -57
  35. package/lib/runtime/components/react/dist/mpx-navigator.jsx +1 -1
  36. package/lib/runtime/components/react/dist/mpx-picker/time.jsx +1 -2
  37. package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +10 -14
  38. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +79 -67
  39. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +19 -16
  40. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +1 -1
  41. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +2 -0
  42. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +13 -7
  43. package/lib/runtime/components/react/dist/mpx-swiper.jsx +382 -325
  44. package/lib/runtime/components/react/dist/mpx-view.jsx +15 -13
  45. package/lib/runtime/components/react/dist/mpx-web-view.jsx +22 -118
  46. package/lib/runtime/components/react/dist/pickerFaces.js +1 -6
  47. package/lib/runtime/components/react/dist/pickerVIewContext.js +5 -0
  48. package/lib/runtime/components/react/dist/{pickerViewOverlay.jsx → pickerViewIndicator.jsx} +6 -6
  49. package/lib/runtime/components/react/dist/pickerViewMask.jsx +2 -2
  50. package/lib/runtime/components/react/dist/useAnimationHooks.js +15 -10
  51. package/lib/runtime/components/react/dist/utils.jsx +117 -84
  52. package/lib/runtime/components/react/event.config.ts +25 -26
  53. package/lib/runtime/components/react/getInnerListeners.ts +236 -182
  54. package/lib/runtime/components/react/mpx-button.tsx +27 -69
  55. package/lib/runtime/components/react/mpx-canvas/html.ts +2 -4
  56. package/lib/runtime/components/react/mpx-canvas/index.tsx +44 -46
  57. package/lib/runtime/components/react/mpx-checkbox-group.tsx +15 -13
  58. package/lib/runtime/components/react/mpx-checkbox.tsx +20 -21
  59. package/lib/runtime/components/react/mpx-form.tsx +15 -20
  60. package/lib/runtime/components/react/mpx-icon/icons/cancel.png +0 -0
  61. package/lib/runtime/components/react/mpx-icon/icons/clear.png +0 -0
  62. package/lib/runtime/components/react/mpx-icon/icons/download.png +0 -0
  63. package/lib/runtime/components/react/mpx-icon/icons/info.png +0 -0
  64. package/lib/runtime/components/react/mpx-icon/icons/search.png +0 -0
  65. package/lib/runtime/components/react/mpx-icon/icons/success.png +0 -0
  66. package/lib/runtime/components/react/mpx-icon/icons/success_no_circle.png +0 -0
  67. package/lib/runtime/components/react/mpx-icon/icons/waiting.png +0 -0
  68. package/lib/runtime/components/react/mpx-icon/icons/warn.png +0 -0
  69. package/lib/runtime/components/react/mpx-icon/index.tsx +111 -0
  70. package/lib/runtime/components/react/mpx-image.tsx +99 -47
  71. package/lib/runtime/components/react/mpx-input.tsx +33 -39
  72. package/lib/runtime/components/react/mpx-label.tsx +12 -14
  73. package/lib/runtime/components/react/mpx-movable-area.tsx +10 -16
  74. package/lib/runtime/components/react/mpx-movable-view.tsx +133 -92
  75. package/lib/runtime/components/react/mpx-navigator.tsx +3 -9
  76. package/lib/runtime/components/react/mpx-picker-view-column-item.tsx +76 -0
  77. package/lib/runtime/components/react/mpx-picker-view-column.tsx +206 -183
  78. package/lib/runtime/components/react/mpx-picker-view.tsx +49 -48
  79. package/lib/runtime/components/react/mpx-radio-group.tsx +13 -15
  80. package/lib/runtime/components/react/mpx-radio.tsx +19 -25
  81. package/lib/runtime/components/react/mpx-rich-text/html.ts +40 -0
  82. package/lib/runtime/components/react/mpx-rich-text/index.tsx +115 -0
  83. package/lib/runtime/components/react/mpx-root-portal.tsx +3 -5
  84. package/lib/runtime/components/react/mpx-scroll-view.tsx +62 -49
  85. package/lib/runtime/components/react/mpx-swiper-item.tsx +45 -11
  86. package/lib/runtime/components/react/mpx-swiper.tsx +742 -0
  87. package/lib/runtime/components/react/mpx-switch.tsx +19 -15
  88. package/lib/runtime/components/react/mpx-text.tsx +8 -16
  89. package/lib/runtime/components/react/mpx-textarea.tsx +11 -10
  90. package/lib/runtime/components/react/mpx-view.tsx +28 -77
  91. package/lib/runtime/components/react/mpx-web-view.tsx +94 -59
  92. package/lib/runtime/components/react/pickerFaces.ts +10 -7
  93. package/lib/runtime/components/react/pickerVIewContext.ts +27 -0
  94. package/lib/runtime/components/react/pickerViewIndicator.tsx +34 -0
  95. package/lib/runtime/components/react/pickerViewMask.tsx +30 -0
  96. package/lib/runtime/components/react/types/{getInnerListeners.ts → getInnerListeners.d.ts} +4 -5
  97. package/lib/runtime/components/react/types/global.d.ts +14 -1
  98. package/lib/runtime/components/react/useAnimationHooks.ts +60 -15
  99. package/lib/runtime/components/react/utils.tsx +175 -71
  100. package/lib/runtime/components/web/mpx-checkbox.vue +1 -1
  101. package/lib/runtime/components/web/mpx-picker-view-column.vue +9 -4
  102. package/lib/runtime/components/web/mpx-web-view.vue +34 -20
  103. package/lib/runtime/optionProcessor.js +0 -22
  104. package/lib/style-compiler/plugins/scope-id.js +30 -2
  105. package/lib/template-compiler/compiler.js +96 -29
  106. package/lib/utils/pre-process-json.js +9 -5
  107. package/lib/wxss/loader.js +15 -2
  108. package/package.json +4 -3
  109. package/lib/runtime/components/react/dist/locale-provider.jsx +0 -15
  110. package/lib/runtime/components/react/dist/mpx-icon.jsx +0 -41
  111. package/lib/runtime/components/react/dist/mpx-portal/portal-consumer.jsx +0 -23
  112. package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +0 -124
  113. package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +0 -40
  114. package/lib/runtime/components/react/dist/mpx-portal.jsx +0 -12
  115. package/lib/runtime/components/react/dist/mpx-provider.jsx +0 -31
  116. package/lib/runtime/components/react/dist/types/common.js +0 -1
  117. package/lib/runtime/components/react/dist/types/getInnerListeners.js +0 -1
  118. package/lib/runtime/components/react/mpx-icon.tsx +0 -102
  119. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +0 -527
  120. package/lib/runtime/components/react/mpx-swiper/index.tsx +0 -80
  121. package/lib/runtime/components/react/mpx-swiper/type.ts +0 -87
  122. package/lib/runtime/components/react/pickerOverlay.tsx +0 -32
  123. package/lib/runtime/components/web/event.js +0 -105
  124. /package/lib/runtime/components/react/types/{common.ts → common.d.ts} +0 -0
@@ -316,8 +316,7 @@ var handleError = function (err, message) {
316
316
  document.removeEventListener('message', handleIncomingMessage);
317
317
  };
318
318
 
319
- function handleIncomingMessage(e) {
320
- var data = JSON.parse(e.data);
319
+ function handleIncomingMessage(data) {
321
320
  if (Array.isArray(data)) {
322
321
  for (var i = 0; i < data.length; i++) {
323
322
  try {
@@ -335,8 +334,7 @@ function handleIncomingMessage(e) {
335
334
  }
336
335
  }
337
336
 
338
- window.addEventListener('message', handleIncomingMessage);
339
- document.addEventListener('message', handleIncomingMessage);
337
+ window.mpxWebviewMessageCallback = handleIncomingMessage
340
338
  </script>
341
339
 
342
340
 
@@ -9,7 +9,7 @@
9
9
  * ✔ bindlongtap
10
10
  * ✔ binderror
11
11
  */
12
- import React, { useRef, useState, useCallback, useEffect, forwardRef, JSX, TouchEvent, MutableRefObject } from 'react'
12
+ import React, { createElement, useRef, useState, useCallback, useEffect, forwardRef, JSX, TouchEvent, MutableRefObject } from 'react'
13
13
  import { View, Platform, StyleSheet, NativeSyntheticEvent } from 'react-native'
14
14
  import { WebView } from 'react-native-webview'
15
15
  import useNodesRef, { HandlerRef } from '../useNodesRef'
@@ -106,7 +106,11 @@ const _Canvas = forwardRef<HandlerRef<CanvasProps & View, CanvasProps>, CanvasPr
106
106
  useEffect(() => {
107
107
  const webviewPostMessage = (message: WebviewMessage) => {
108
108
  if (canvasRef.current.webview) {
109
- canvasRef.current.webview.postMessage(JSON.stringify(message))
109
+ const jsCode = `
110
+ window.mpxWebviewMessageCallback(${JSON.stringify(message)});
111
+ true;
112
+ `
113
+ canvasRef.current.webview.injectJavaScript(jsCode)
110
114
  }
111
115
  }
112
116
 
@@ -249,54 +253,48 @@ const _Canvas = forwardRef<HandlerRef<CanvasProps & View, CanvasProps>, CanvasPr
249
253
 
250
254
  if (Platform.OS === 'android') {
251
255
  const isAndroid9 = Platform.Version >= 28
252
- return (
253
- <View {...innerProps}>
254
- <WebView
255
- ref={(element) => {
256
- if (canvasRef.current) {
257
- canvasRef.current.webview = element
258
- }
259
- }}
260
- style={[
261
- isAndroid9 ? stylesheet.webviewAndroid9 : stylesheet.webview,
262
- { height, width }
263
- ]}
264
- source={{ html }}
265
- originWhitelist={originWhitelist}
266
- onMessage={onMessage}
267
- onLoad={onLoad}
268
- overScrollMode="never"
269
- mixedContentMode="always"
270
- scalesPageToFit={false}
271
- javaScriptEnabled
272
- domStorageEnabled
273
- thirdPartyCookiesEnabled
274
- allowUniversalAccessFromFileURLs
275
- />
276
- </View>
277
- )
278
- }
279
-
280
- return (
281
- <View
282
- {...innerProps}
283
- >
284
- <WebView
285
- ref={(element) => {
256
+ return createElement(View, innerProps, createElement(
257
+ WebView,
258
+ {
259
+ ref: (element) => {
286
260
  if (canvasRef.current) {
287
261
  canvasRef.current.webview = element
288
262
  }
289
- }}
290
- style={[stylesheet.webview, { height, width }]}
291
- source={{ html }}
292
- originWhitelist={originWhitelist}
293
- onMessage={onMessage}
294
- onLoad={onLoad}
295
- scrollEnabled={false}
296
- />
297
- </View>
298
- )
263
+ },
264
+ style: [
265
+ isAndroid9 ? stylesheet.webviewAndroid9 : stylesheet.webview,
266
+ { height, width }
267
+ ],
268
+ source: { html },
269
+ originWhitelist: originWhitelist,
270
+ onMessage: onMessage,
271
+ onLoad: onLoad,
272
+ overScrollMode: 'never',
273
+ mixedContentMode: 'always',
274
+ scalesPageToFit: false,
275
+ javaScriptEnabled: true,
276
+ domStorageEnabled: true,
277
+ thirdPartyCookiesEnabled: true,
278
+ allowUniversalAccessFromFileURLs: true
279
+ })
280
+ )
281
+ }
282
+
283
+ return createElement(View, innerProps, createElement(WebView, {
284
+ ref: (element) => {
285
+ if (canvasRef.current) {
286
+ canvasRef.current.webview = element
287
+ }
288
+ },
289
+ style: [stylesheet.webview, { height, width }],
290
+ source: { html },
291
+ originWhitelist: originWhitelist,
292
+ onMessage: onMessage,
293
+ onLoad: onLoad,
294
+ scrollEnabled: false
295
+ }))
299
296
  })
297
+
300
298
  _Canvas.displayName = 'mpxCanvas'
301
299
 
302
300
  export default _Canvas
@@ -8,7 +8,8 @@ import {
8
8
  ReactNode,
9
9
  useContext,
10
10
  useMemo,
11
- useEffect
11
+ useEffect,
12
+ createElement
12
13
  } from 'react'
13
14
  import {
14
15
  View,
@@ -156,20 +157,21 @@ const CheckboxGroup = forwardRef<
156
157
  notifyChange
157
158
  }
158
159
  }, [])
159
- return (
160
- <View {...innerProps}>
161
- <CheckboxGroupContext.Provider value={contextValue}>
160
+
161
+ return createElement(
162
+ View,
163
+ innerProps,
164
+ createElement(
165
+ CheckboxGroupContext.Provider,
166
+ { value: contextValue },
167
+ wrapChildren(
168
+ props,
162
169
  {
163
- wrapChildren(
164
- props,
165
- {
166
- hasVarDec,
167
- varContext: varContextRef.current
168
- }
169
- )
170
+ hasVarDec,
171
+ varContext: varContextRef.current
170
172
  }
171
- </CheckboxGroupContext.Provider>
172
- </View>
173
+ )
174
+ )
173
175
  )
174
176
  })
175
177
 
@@ -13,7 +13,8 @@ import {
13
13
  ReactNode,
14
14
  useContext,
15
15
  Dispatch,
16
- SetStateAction
16
+ SetStateAction,
17
+ createElement
17
18
  } from 'react'
18
19
  import {
19
20
  View,
@@ -206,28 +207,26 @@ const Checkbox = forwardRef<HandlerRef<View, CheckboxProps>, CheckboxProps>(
206
207
  }
207
208
  }, [checked])
208
209
 
209
- return (
210
- <View {...innerProps}>
211
- <View style={defaultStyle}>
212
- <Icon
213
- type='success_no_circle'
214
- size={18}
215
- color={disabled ? '#ADADAD' : color}
216
- style={isChecked ? styles.iconChecked : styles.icon}
217
- />
218
- </View>
210
+ return createElement(View, innerProps,
211
+ createElement(
212
+ View,
213
+ { style: defaultStyle },
214
+ createElement(Icon, {
215
+ type: 'success_no_circle',
216
+ size: 18,
217
+ color: disabled ? '#ADADAD' : color,
218
+ style: isChecked ? styles.iconChecked : styles.icon
219
+ })
220
+ ),
221
+ wrapChildren(
222
+ props,
219
223
  {
220
- wrapChildren(
221
- props,
222
- {
223
- hasVarDec,
224
- varContext: varContextRef.current,
225
- textStyle,
226
- textProps
227
- }
228
- )
224
+ hasVarDec,
225
+ varContext: varContextRef.current,
226
+ textStyle,
227
+ textProps
229
228
  }
230
- </View>
229
+ )
231
230
  )
232
231
  }
233
232
  )
@@ -5,7 +5,7 @@
5
5
  * ✔ bindreset
6
6
  */
7
7
  import { View } from 'react-native'
8
- import { JSX, useRef, forwardRef, ReactNode, useMemo, useCallback } from 'react'
8
+ import { JSX, useRef, forwardRef, ReactNode, useMemo, createElement } from 'react'
9
9
  import useNodesRef, { HandlerRef } from './useNodesRef'
10
10
  import useInnerProps, { getCustomEvent } from './getInnerListeners'
11
11
  import { FormContext } from './context'
@@ -102,25 +102,20 @@ const _Form = forwardRef<HandlerRef<View, FormProps>, FormProps>((fromProps: For
102
102
  reset
103
103
  }
104
104
  }, [])
105
- return (
106
- <View
107
- {...innerProps}
108
- >
109
- <FormContext.Provider value={contextValue}>
110
- {
111
- wrapChildren(
112
- props,
113
- {
114
- hasVarDec,
115
- varContext: varContextRef.current,
116
- textStyle,
117
- textProps
118
- }
119
- )
120
- }
121
- </FormContext.Provider>
122
- </View>
123
- )
105
+
106
+ return createElement(View, innerProps, createElement(
107
+ FormContext.Provider,
108
+ { value: contextValue },
109
+ wrapChildren(
110
+ props,
111
+ {
112
+ hasVarDec,
113
+ varContext: varContextRef.current,
114
+ textStyle,
115
+ textProps
116
+ }
117
+ )
118
+ ))
124
119
  })
125
120
 
126
121
  _Form.displayName = 'MpxForm'
@@ -0,0 +1,111 @@
1
+ /**
2
+ * ✔ type
3
+ * ✔ size
4
+ * ✔ color
5
+ */
6
+ import { JSX, forwardRef, useRef, createElement } from 'react'
7
+ import { Text, TextStyle, Image } from 'react-native'
8
+ import useInnerProps from '../getInnerListeners'
9
+ import useNodesRef, { HandlerRef } from '../useNodesRef'
10
+ import { useLayout, useTransformStyle, extendObject } from '../utils'
11
+ import Success from './icons/success.png'
12
+ import SuccessNoCircle from './icons/success_no_circle.png'
13
+ import Info from './icons/info.png'
14
+ import Warn from './icons/warn.png'
15
+ import Waiting from './icons/waiting.png'
16
+ import Cancel from './icons/cancel.png'
17
+ import Download from './icons/download.png'
18
+ import Search from './icons/search.png'
19
+ import Clear from './icons/clear.png'
20
+
21
+ export type IconType =
22
+ | 'success'
23
+ | 'success_no_circle'
24
+ | 'info'
25
+ | 'warn'
26
+ | 'waiting'
27
+ | 'cancel'
28
+ | 'download'
29
+ | 'search'
30
+ | 'clear'
31
+
32
+ export interface IconProps {
33
+ type: IconType
34
+ size?: number
35
+ color?: string
36
+ style?: TextStyle & Record<string, any>
37
+ 'enable-offset'?: boolean
38
+ 'enable-var'?: boolean
39
+ 'external-var-context'?: Record<string, any>
40
+ 'parent-font-size'?: number
41
+ 'parent-width'?: number
42
+ 'parent-height'?: number
43
+ }
44
+
45
+ const IconTypeMap = new Map<IconType, string>([
46
+ ['success', Success],
47
+ ['success_no_circle', SuccessNoCircle],
48
+ ['info', Info],
49
+ ['warn', Warn],
50
+ ['waiting', Waiting],
51
+ ['cancel', Cancel],
52
+ ['download', Download],
53
+ ['search', Search],
54
+ ['clear', Clear]
55
+ ])
56
+
57
+ const Icon = forwardRef<HandlerRef<Text, IconProps>, IconProps>(
58
+ (props, ref): JSX.Element => {
59
+ const {
60
+ type,
61
+ size = 23,
62
+ color,
63
+ style = {},
64
+ 'enable-var': enableVar,
65
+ 'external-var-context': externalVarContext,
66
+ 'parent-font-size': parentFontSize,
67
+ 'parent-width': parentWidth,
68
+ 'parent-height': parentHeight
69
+ } = props
70
+
71
+ const source = IconTypeMap.get(type)
72
+
73
+ const defaultStyle = { width: ~~size, height: ~~size }
74
+
75
+ const styleObj = extendObject({}, defaultStyle, style)
76
+
77
+ const {
78
+ hasSelfPercent,
79
+ normalStyle,
80
+ setWidth,
81
+ setHeight
82
+ } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
83
+
84
+ const nodeRef = useRef(null)
85
+ useNodesRef(props, ref, nodeRef, { style: normalStyle })
86
+
87
+ const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef })
88
+
89
+ const innerProps = useInnerProps(
90
+ props,
91
+ extendObject(
92
+ {
93
+ ref: nodeRef,
94
+ source,
95
+ style: extendObject({}, normalStyle, layoutStyle, { tintColor: color })
96
+ },
97
+ layoutProps
98
+ ),
99
+ [],
100
+ {
101
+ layoutRef
102
+ }
103
+ )
104
+
105
+ return createElement(Image, innerProps)
106
+ }
107
+ )
108
+
109
+ Icon.displayName = 'MpxIcon'
110
+
111
+ export default Icon
@@ -10,7 +10,7 @@
10
10
  * ✔ bindtap
11
11
  * ✔ DEFAULT_SIZE
12
12
  */
13
- import { useEffect, useMemo, useState, useRef, forwardRef } from 'react'
13
+ import { useEffect, useMemo, useState, useRef, forwardRef, createElement } from 'react'
14
14
  import {
15
15
  Image as RNImage,
16
16
  View,
@@ -22,10 +22,11 @@ import {
22
22
  DimensionValue,
23
23
  ImageLoadEventData
24
24
  } from 'react-native'
25
+ import { noop } from '@mpxjs/utils'
25
26
  import { SvgCssUri } from 'react-native-svg/css'
26
27
  import useInnerProps, { getCustomEvent } from './getInnerListeners'
27
28
  import useNodesRef, { HandlerRef } from './useNodesRef'
28
- import { SVG_REGEXP, useLayout, useTransformStyle, extendObject } from './utils'
29
+ import { SVG_REGEXP, useLayout, useTransformStyle, renderImage, extendObject } from './utils'
29
30
 
30
31
  export type Mode =
31
32
  | 'scaleToFill'
@@ -48,16 +49,25 @@ export interface ImageProps {
48
49
  mode?: Mode
49
50
  svg?: boolean
50
51
  style?: ImageStyle & Record<string, any>
51
- 'enable-offset'?: boolean;
52
+ 'enable-offset'?: boolean
52
53
  'enable-var'?: boolean
53
54
  'external-var-context'?: Record<string, any>
54
55
  'parent-font-size'?: number
55
56
  'parent-width'?: number
56
57
  'parent-height'?: number
58
+ 'enable-fast-image'?: boolean
57
59
  bindload?: (evt: NativeSyntheticEvent<ImageLoadEventData> | unknown) => void
58
60
  binderror?: (evt: NativeSyntheticEvent<ImageErrorEventData> | unknown) => void
59
61
  }
60
62
 
63
+ interface ImageState {
64
+ viewWidth?: number
65
+ viewHeight?: number
66
+ imageWidth?: number
67
+ imageHeight?: number
68
+ ratio?: number
69
+ }
70
+
61
71
  const DEFAULT_IMAGE_WIDTH = 320
62
72
  const DEFAULT_IMAGE_HEIGHT = 240
63
73
 
@@ -101,6 +111,7 @@ const Image = forwardRef<HandlerRef<RNImage, ImageProps>, ImageProps>((props, re
101
111
  'enable-var': enableVar,
102
112
  'external-var-context': externalVarContext,
103
113
  'parent-font-size': parentFontSize,
114
+ 'enable-fast-image': enableFastImage,
104
115
  'parent-width': parentWidth,
105
116
  'parent-height': parentHeight,
106
117
  bindload,
@@ -119,23 +130,13 @@ const Image = forwardRef<HandlerRef<RNImage, ImageProps>, ImageProps>((props, re
119
130
  { overflow: 'hidden' }
120
131
  )
121
132
 
122
- const nodeRef = useRef(null)
123
-
124
- const onLayout = ({ nativeEvent: { layout: { width, height } } }: LayoutChangeEvent) => {
125
- setViewWidth(width)
126
- setViewHeight(height)
127
- }
128
-
129
- const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
133
+ const state = useRef<ImageState>({})
130
134
 
135
+ const nodeRef = useRef(null)
131
136
  useNodesRef(props, ref, nodeRef, {
132
- style: normalStyle
137
+ defaultStyle
133
138
  })
134
139
 
135
- const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef, onLayout })
136
-
137
- const { width, height } = normalStyle
138
-
139
140
  const isSvg = SVG_REGEXP.test(src)
140
141
  const isWidthFixMode = mode === 'widthFix'
141
142
  const isHeightFixMode = mode === 'heightFix'
@@ -143,11 +144,40 @@ const Image = forwardRef<HandlerRef<RNImage, ImageProps>, ImageProps>((props, re
143
144
  const isLayoutMode = isWidthFixMode || isHeightFixMode || isCropMode
144
145
  const resizeMode: ImageResizeMode = ModeMap.get(mode) || 'stretch'
145
146
 
147
+ const onLayout = ({ nativeEvent: { layout: { width, height } } }: LayoutChangeEvent) => {
148
+ state.current.viewWidth = width
149
+ state.current.viewHeight = height
150
+
151
+ if (state.current.imageWidth && state.current.imageHeight && state.current.ratio) {
152
+ setViewWidth(width)
153
+ setViewHeight(height)
154
+ setRatio(state.current.ratio)
155
+ setImageWidth(state.current.imageWidth)
156
+ setImageHeight(state.current.imageHeight)
157
+ state.current = {}
158
+ setLoaded(true)
159
+ }
160
+ }
161
+
162
+ const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
163
+
164
+ const { layoutRef, layoutStyle, layoutProps } = useLayout({
165
+ props,
166
+ hasSelfPercent,
167
+ setWidth,
168
+ setHeight,
169
+ nodeRef,
170
+ onLayout: isLayoutMode ? onLayout : noop
171
+ })
172
+
173
+ const { width, height } = normalStyle
174
+
146
175
  const [viewWidth, setViewWidth] = useState(isNumber(width) ? width : 0)
147
176
  const [viewHeight, setViewHeight] = useState(isNumber(height) ? height : 0)
148
177
  const [imageWidth, setImageWidth] = useState(0)
149
178
  const [imageHeight, setImageHeight] = useState(0)
150
179
  const [ratio, setRatio] = useState(0)
180
+ const [loaded, setLoaded] = useState(!isLayoutMode)
151
181
 
152
182
  const fixedHeight = useMemo(() => {
153
183
  const fixed = viewWidth * ratio
@@ -327,9 +357,23 @@ const Image = forwardRef<HandlerRef<RNImage, ImageProps>, ImageProps>((props, re
327
357
  useEffect(() => {
328
358
  if (!isSvg && isLayoutMode) {
329
359
  RNImage.getSize(src, (width: number, height: number) => {
330
- setRatio(!width ? 0 : height / width)
331
- setImageWidth(width)
332
- setImageHeight(height)
360
+ state.current.imageWidth = width
361
+ state.current.imageHeight = height
362
+ state.current.ratio = !width ? 0 : height / width
363
+
364
+ if (isWidthFixMode
365
+ ? state.current.viewWidth
366
+ : isHeightFixMode
367
+ ? state.current.viewHeight
368
+ : state.current.viewWidth && state.current.viewHeight) {
369
+ state.current.viewWidth && setViewWidth(state.current.viewWidth)
370
+ state.current.viewHeight && setViewHeight(state.current.viewHeight)
371
+ setRatio(!width ? 0 : height / width)
372
+ setImageWidth(width)
373
+ setImageHeight(height)
374
+ state.current = {}
375
+ setLoaded(true)
376
+ }
333
377
  })
334
378
  }
335
379
  }, [src, isSvg, isLayoutMode])
@@ -359,36 +403,44 @@ const Image = forwardRef<HandlerRef<RNImage, ImageProps>, ImageProps>((props, re
359
403
  }
360
404
  )
361
405
 
362
- return (
363
- <View {...innerProps}>
406
+ const SvgImage = createElement(
407
+ View,
408
+ innerProps,
409
+ createElement(SvgCssUri, {
410
+ uri: src,
411
+ onLayout: onSvgLoad,
412
+ onError: binderror && onSvgError,
413
+ style: extendObject(
414
+ { transformOrigin: 'top left' },
415
+ modeStyle
416
+ )
417
+ })
418
+ )
419
+
420
+ const BaseImage = renderImage(
421
+ extendObject(
364
422
  {
365
- isSvg
366
- ? <SvgCssUri
367
- uri={src}
368
- onLayout={onSvgLoad}
369
- onError={binderror && onSvgError}
370
- style={extendObject(
371
- { transformOrigin: 'top left' },
372
- modeStyle
373
- )}
374
- />
375
- : <RNImage
376
- source={{ uri: src }}
377
- resizeMode={resizeMode}
378
- onLoad={bindload && onImageLoad}
379
- onError={binderror && onImageError}
380
- style={extendObject(
381
- {
382
- transformOrigin: 'top left',
383
- width: isCropMode ? imageWidth : '100%',
384
- height: isCropMode ? imageHeight : '100%'
385
- },
386
- isCropMode ? modeStyle : {}
387
- )}
388
- />
389
- }
390
- </View>
423
+ source: { uri: src },
424
+ resizeMode: resizeMode,
425
+ onLoad: bindload && onImageLoad,
426
+ onError: binderror && onImageError,
427
+ style: extendObject(
428
+ {
429
+ transformOrigin: 'top left',
430
+ width: isCropMode ? imageWidth : '100%',
431
+ height: isCropMode ? imageHeight : '100%'
432
+ },
433
+ isCropMode ? modeStyle : {}
434
+ )
435
+ },
436
+ isLayoutMode ? {} : innerProps
437
+ ),
438
+ enableFastImage
391
439
  )
440
+
441
+ const LayoutImage = createElement(View, innerProps, loaded && BaseImage)
442
+
443
+ return isSvg ? SvgImage : isLayoutMode ? LayoutImage : BaseImage
392
444
  })
393
445
 
394
446
  Image.displayName = 'mpx-image'