@mpxjs/webpack-plugin 2.9.67 → 2.9.69-beta.1

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 (150) hide show
  1. package/lib/index.js +30 -9
  2. package/lib/platform/json/wx/index.js +21 -8
  3. package/lib/platform/style/wx/index.js +51 -54
  4. package/lib/platform/template/wx/component-config/canvas.js +8 -0
  5. package/lib/platform/template/wx/component-config/fix-component-name.js +15 -12
  6. package/lib/platform/template/wx/component-config/index.js +1 -1
  7. package/lib/platform/template/wx/component-config/input.js +1 -1
  8. package/lib/platform/template/wx/component-config/movable-view.js +8 -1
  9. package/lib/platform/template/wx/component-config/rich-text.js +8 -0
  10. package/lib/platform/template/wx/component-config/scroll-view.js +1 -1
  11. package/lib/platform/template/wx/component-config/swiper.js +1 -1
  12. package/lib/platform/template/wx/component-config/textarea.js +1 -1
  13. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  14. package/lib/react/processStyles.js +14 -4
  15. package/lib/react/processTemplate.js +3 -0
  16. package/lib/resolver/AddEnvPlugin.js +1 -0
  17. package/lib/resolver/AddModePlugin.js +9 -8
  18. package/lib/runtime/components/react/context.ts +14 -0
  19. package/lib/runtime/components/react/dist/context.js +4 -0
  20. package/lib/runtime/components/react/dist/event.config.js +24 -24
  21. package/lib/runtime/components/react/dist/getInnerListeners.js +183 -175
  22. package/lib/runtime/components/react/dist/mpx-button.jsx +77 -49
  23. package/lib/runtime/components/react/dist/mpx-canvas/Bus.js +60 -0
  24. package/lib/runtime/components/react/dist/mpx-canvas/CanvasGradient.js +15 -0
  25. package/lib/runtime/components/react/dist/mpx-canvas/CanvasRenderingContext2D.js +84 -0
  26. package/lib/runtime/components/react/dist/mpx-canvas/Image.js +87 -0
  27. package/lib/runtime/components/react/dist/mpx-canvas/ImageData.js +15 -0
  28. package/lib/runtime/components/react/dist/mpx-canvas/constructorsRegistry.js +28 -0
  29. package/lib/runtime/components/react/dist/mpx-canvas/html.js +343 -0
  30. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +232 -0
  31. package/lib/runtime/components/react/dist/mpx-canvas/utils.jsx +89 -0
  32. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +13 -19
  33. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +29 -38
  34. package/lib/runtime/components/react/dist/mpx-form.jsx +16 -19
  35. package/lib/runtime/components/react/dist/mpx-icon.jsx +8 -16
  36. package/lib/runtime/components/react/dist/mpx-image.jsx +291 -0
  37. package/lib/runtime/components/react/dist/mpx-input.jsx +54 -27
  38. package/lib/runtime/components/react/dist/mpx-label.jsx +15 -22
  39. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +13 -16
  40. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +14 -14
  41. package/lib/runtime/components/react/dist/mpx-navigator.jsx +2 -4
  42. package/lib/runtime/components/react/dist/mpx-picker/date.jsx +6 -2
  43. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +5 -3
  44. package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +6 -2
  45. package/lib/runtime/components/react/dist/mpx-picker/region.jsx +6 -2
  46. package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +6 -2
  47. package/lib/runtime/components/react/dist/mpx-picker/time.jsx +10 -15
  48. package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +39 -0
  49. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +171 -88
  50. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +80 -121
  51. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +11 -19
  52. package/lib/runtime/components/react/dist/mpx-radio.jsx +27 -42
  53. package/lib/runtime/components/react/dist/mpx-rich-text/html.js +39 -0
  54. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +62 -0
  55. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +6 -4
  56. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +53 -42
  57. package/lib/runtime/components/react/dist/mpx-simple-text.jsx +11 -0
  58. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +28 -9
  59. package/lib/runtime/components/react/dist/mpx-swiper.jsx +608 -0
  60. package/lib/runtime/components/react/dist/mpx-switch.jsx +20 -10
  61. package/lib/runtime/components/react/dist/mpx-text.jsx +11 -10
  62. package/lib/runtime/components/react/dist/mpx-textarea.jsx +8 -3
  63. package/lib/runtime/components/react/dist/mpx-view.jsx +67 -94
  64. package/lib/runtime/components/react/dist/mpx-web-view.jsx +152 -37
  65. package/lib/runtime/components/react/dist/pickerFaces.js +81 -0
  66. package/lib/runtime/components/react/dist/pickerVIewContext.js +9 -0
  67. package/lib/runtime/components/react/dist/pickerViewMask.jsx +18 -0
  68. package/lib/runtime/components/react/dist/pickerViewOverlay.jsx +23 -0
  69. package/lib/runtime/components/react/dist/useAnimationHooks.js +36 -10
  70. package/lib/runtime/components/react/dist/utils.jsx +129 -24
  71. package/lib/runtime/components/react/event.config.ts +25 -26
  72. package/lib/runtime/components/react/getInnerListeners.ts +238 -202
  73. package/lib/runtime/components/react/mpx-button.tsx +104 -57
  74. package/lib/runtime/components/react/mpx-canvas/Bus.ts +70 -0
  75. package/lib/runtime/components/react/mpx-canvas/CanvasGradient.ts +18 -0
  76. package/lib/runtime/components/react/mpx-canvas/CanvasRenderingContext2D.ts +87 -0
  77. package/lib/runtime/components/react/mpx-canvas/Image.ts +102 -0
  78. package/lib/runtime/components/react/mpx-canvas/ImageData.ts +23 -0
  79. package/lib/runtime/components/react/mpx-canvas/constructorsRegistry.ts +38 -0
  80. package/lib/runtime/components/react/mpx-canvas/html.ts +343 -0
  81. package/lib/runtime/components/react/mpx-canvas/index.tsx +296 -0
  82. package/lib/runtime/components/react/mpx-canvas/utils.tsx +150 -0
  83. package/lib/runtime/components/react/mpx-checkbox-group.tsx +28 -25
  84. package/lib/runtime/components/react/mpx-checkbox.tsx +48 -49
  85. package/lib/runtime/components/react/mpx-form.tsx +25 -28
  86. package/lib/runtime/components/react/mpx-icon.tsx +12 -17
  87. package/lib/runtime/components/react/mpx-image.tsx +436 -0
  88. package/lib/runtime/components/react/mpx-input.tsx +77 -57
  89. package/lib/runtime/components/react/mpx-label.tsx +26 -27
  90. package/lib/runtime/components/react/mpx-movable-area.tsx +18 -23
  91. package/lib/runtime/components/react/mpx-movable-view.tsx +22 -26
  92. package/lib/runtime/components/react/mpx-navigator.tsx +2 -8
  93. package/lib/runtime/components/react/mpx-picker/date.tsx +5 -2
  94. package/lib/runtime/components/react/mpx-picker/index.tsx +3 -2
  95. package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +5 -2
  96. package/lib/runtime/components/react/mpx-picker/region.tsx +5 -2
  97. package/lib/runtime/components/react/mpx-picker/selector.tsx +5 -2
  98. package/lib/runtime/components/react/mpx-picker/time.tsx +10 -15
  99. package/lib/runtime/components/react/mpx-picker/type.ts +48 -43
  100. package/lib/runtime/components/react/mpx-picker-view-column-item.tsx +88 -0
  101. package/lib/runtime/components/react/mpx-picker-view-column.tsx +276 -112
  102. package/lib/runtime/components/react/mpx-picker-view.tsx +137 -129
  103. package/lib/runtime/components/react/mpx-radio-group.tsx +24 -27
  104. package/lib/runtime/components/react/mpx-radio.tsx +45 -54
  105. package/lib/runtime/components/react/mpx-rich-text/html.ts +40 -0
  106. package/lib/runtime/components/react/mpx-rich-text/index.tsx +115 -0
  107. package/lib/runtime/components/react/mpx-root-portal.tsx +3 -5
  108. package/lib/runtime/components/react/mpx-scroll-view.tsx +83 -73
  109. package/lib/runtime/components/react/mpx-simple-text.tsx +18 -0
  110. package/lib/runtime/components/react/mpx-swiper-item.tsx +41 -12
  111. package/lib/runtime/components/react/mpx-swiper.tsx +690 -0
  112. package/lib/runtime/components/react/mpx-switch.tsx +29 -23
  113. package/lib/runtime/components/react/mpx-text.tsx +14 -18
  114. package/lib/runtime/components/react/mpx-textarea.tsx +11 -10
  115. package/lib/runtime/components/react/mpx-view.tsx +93 -117
  116. package/lib/runtime/components/react/mpx-web-view.tsx +162 -56
  117. package/lib/runtime/components/react/pickerFaces.ts +112 -0
  118. package/lib/runtime/components/react/pickerVIewContext.ts +18 -0
  119. package/lib/runtime/components/react/pickerViewMask.tsx +30 -0
  120. package/lib/runtime/components/react/pickerViewOverlay.tsx +34 -0
  121. package/lib/runtime/components/react/types/common.ts +2 -0
  122. package/lib/runtime/components/react/types/global.d.ts +7 -17
  123. package/lib/runtime/components/react/useAnimationHooks.ts +37 -12
  124. package/lib/runtime/components/react/utils.tsx +169 -29
  125. package/lib/runtime/components/web/getInnerListeners.js +6 -6
  126. package/lib/runtime/components/web/mpx-movable-view.vue +334 -344
  127. package/lib/runtime/components/web/mpx-picker-view-column.vue +75 -75
  128. package/lib/runtime/components/web/mpx-picker.vue +382 -385
  129. package/lib/runtime/components/web/mpx-web-view.vue +175 -161
  130. package/lib/runtime/optionProcessor.js +7 -38
  131. package/lib/runtime/utils.js +2 -0
  132. package/lib/style-compiler/index.js +3 -4
  133. package/lib/style-compiler/plugins/scope-id.js +30 -2
  134. package/lib/style-compiler/strip-conditional-loader.js +118 -0
  135. package/lib/template-compiler/bind-this.js +7 -2
  136. package/lib/template-compiler/compiler.js +66 -39
  137. package/lib/template-compiler/gen-node-react.js +3 -3
  138. package/package.json +6 -4
  139. package/LICENSE +0 -433
  140. package/lib/runtime/components/react/dist/mpx-image/index.jsx +0 -226
  141. package/lib/runtime/components/react/dist/mpx-image/svg.jsx +0 -7
  142. package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +0 -478
  143. package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +0 -68
  144. package/lib/runtime/components/react/dist/mpx-swiper/type.js +0 -1
  145. package/lib/runtime/components/react/mpx-image/index.tsx +0 -345
  146. package/lib/runtime/components/react/mpx-image/svg.tsx +0 -22
  147. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +0 -525
  148. package/lib/runtime/components/react/mpx-swiper/index.tsx +0 -80
  149. package/lib/runtime/components/react/mpx-swiper/type.ts +0 -87
  150. package/lib/runtime/components/web/event.js +0 -105
@@ -1,11 +1,14 @@
1
- import { forwardRef, JSX, useEffect, useRef } from 'react'
2
- import { noop, warn } from '@mpxjs/utils'
1
+ import { forwardRef, JSX, useRef, useContext, useMemo, createElement, useCallback, useEffect } from 'react'
2
+ import { warn, getFocusedNavigation, isFunction } from '@mpxjs/utils'
3
3
  import { Portal } from '@ant-design/react-native'
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 { WebViewNavigationEvent, WebViewErrorEvent, WebViewMessageEvent } from 'react-native-webview/lib/WebViewTypes'
8
+ import { getCurrentPage, extendObject } from './utils'
9
+ import { WebViewNavigationEvent, WebViewErrorEvent, WebViewMessageEvent, WebViewNavigation, WebViewProgressEvent } from 'react-native-webview/lib/WebViewTypes'
10
+ import { RouteContext } from './context'
11
+ import { BackHandler } from 'react-native'
9
12
 
10
13
  type OnMessageCallbackEvent = {
11
14
  detail: {
@@ -28,29 +31,25 @@ interface WebViewProps {
28
31
  }
29
32
 
30
33
  interface PayloadData {
31
- data?: Record<string, any>
34
+ [x: string]: any
32
35
  }
33
36
 
34
37
  type MessageData = {
35
38
  payload?: PayloadData,
39
+ args?: Array<any>,
36
40
  type?: string,
37
41
  callbackId?: number
38
42
  }
39
43
 
40
- interface NativeEvent {
41
- url: string,
42
- data: string
43
- }
44
-
45
- interface FormRef {
46
- postMessage: (value: any) => void;
47
- }
48
-
49
- const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((props, ref): JSX.Element => {
50
- const { src = '', bindmessage = noop, bindload = noop, binderror = noop } = props
44
+ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((props, ref): JSX.Element | null => {
45
+ const { src, bindmessage, bindload, binderror } = props
46
+ const mpx = global.__mpx
51
47
  if (props.style) {
52
48
  warn('The web-view component does not support the style prop.')
53
49
  }
50
+ const pageId = useContext(RouteContext)
51
+ const currentPage = useMemo(() => getCurrentPage(pageId), [pageId])
52
+ const webViewRef = useRef<WebView>(null)
54
53
  const defaultWebViewStyle = {
55
54
  position: 'absolute' as 'absolute' | 'relative' | 'static',
56
55
  left: 0 as number,
@@ -58,29 +57,44 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
58
57
  top: 0 as number,
59
58
  bottom: 0 as number
60
59
  }
60
+ const canGoBack = useRef<boolean>(false)
61
61
 
62
- const webViewRef = useRef<WebView>(null)
63
- useNodesRef<WebView, WebViewProps>(props, ref, webViewRef, {
64
- defaultStyle: defaultWebViewStyle
65
- })
62
+ const onAndroidBackPress = useCallback(() => {
63
+ if (canGoBack.current) {
64
+ webViewRef.current?.goBack()
65
+ return true
66
+ }
67
+ return false
68
+ }, [canGoBack])
66
69
 
67
- const _messageList: any[] = []
68
- const handleUnload = () => {
69
- // 这里是 WebView 销毁前执行的逻辑
70
- bindmessage(getCustomEvent('messsage', {}, {
71
- detail: {
72
- data: _messageList
73
- },
74
- layoutRef: webViewRef
75
- }))
76
- }
70
+ const beforeRemoveHandle = useCallback((e: Event) => {
71
+ if (canGoBack.current) {
72
+ webViewRef.current?.goBack()
73
+ e.preventDefault()
74
+ }
75
+ }, [canGoBack])
76
+
77
+ const navigation = getFocusedNavigation()
78
+
79
+ navigation?.addListener('beforeRemove', beforeRemoveHandle)
77
80
 
78
81
  useEffect(() => {
79
- // 组件卸载时执行
80
- return () => {
81
- handleUnload()
82
+ if (__mpx_mode__ === 'android') {
83
+ BackHandler.addEventListener('hardwareBackPress', onAndroidBackPress)
84
+ return () => {
85
+ BackHandler.removeEventListener('hardwareBackPress', onAndroidBackPress)
86
+ }
82
87
  }
83
88
  }, [])
89
+
90
+ useNodesRef<WebView, WebViewProps>(props, ref, webViewRef, {
91
+ style: defaultWebViewStyle
92
+ })
93
+
94
+ if (!src) {
95
+ return null
96
+ }
97
+
84
98
  const _load = function (res: WebViewNavigationEvent) {
85
99
  const result = {
86
100
  type: 'load',
@@ -101,6 +115,50 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
101
115
  }
102
116
  binderror(result)
103
117
  }
118
+ const injectedJavaScript = `
119
+ if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
120
+ var _documentTitle = document.title;
121
+ window.ReactNativeWebView.postMessage(JSON.stringify({
122
+ type: 'setTitle',
123
+ payload: {
124
+ _documentTitle: _documentTitle
125
+ }
126
+ }))
127
+ Object.defineProperty(document, 'title', {
128
+ set (val) {
129
+ _documentTitle = val
130
+ window.ReactNativeWebView.postMessage(JSON.stringify({
131
+ type: 'setTitle',
132
+ payload: {
133
+ _documentTitle: _documentTitle
134
+ }
135
+ }))
136
+ },
137
+ get () {
138
+ return _documentTitle
139
+ }
140
+ });
141
+ }
142
+ true;
143
+ `
144
+ const sendMessage = function(params: string) {
145
+ return `
146
+ window.mpxWebviewMessageCallback(${params})
147
+ true;
148
+ `
149
+ }
150
+ const _changeUrl = function (navState: WebViewNavigation) {
151
+ if (navState.navigationType) { // navigationType这个事件在页面开始加载时和页面加载完成时都会被触发所以判断这个避免其他无效触发执行该逻辑
152
+ canGoBack.current = navState.canGoBack
153
+ currentPage.__webViewUrl = navState.url
154
+ }
155
+ }
156
+
157
+ const _onLoadProgress = function (event: WebViewProgressEvent) {
158
+ if (__mpx_mode__ === 'android') {
159
+ canGoBack.current = event.nativeEvent.canGoBack
160
+ }
161
+ }
104
162
  const _message = function (res: WebViewMessageEvent) {
105
163
  let data: MessageData = {}
106
164
  let asyncCallback
@@ -110,56 +168,104 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
110
168
  if (typeof nativeEventData === 'string') {
111
169
  data = JSON.parse(nativeEventData)
112
170
  }
113
- } catch (e) {
114
- data = {}
115
- }
171
+ } catch (e) {}
172
+ const args = data.args
116
173
  const postData: PayloadData = data.payload || {}
117
- switch (data.type) {
174
+ const params = Array.isArray(args) ? args : [postData]
175
+ const type = data.type
176
+ switch (type) {
177
+ case 'setTitle':
178
+ { // case下不允许直接声明,包个块解决该问题
179
+ const title = postData._documentTitle
180
+ if (title) {
181
+ navigation && navigation.setOptions({ title })
182
+ }
183
+ }
184
+ break
118
185
  case 'postMessage':
119
- _messageList.push(postData.data)
186
+ bindmessage && bindmessage(getCustomEvent('messsage', {}, { // RN组件销毁顺序与小程序不一致,所以改成和支付宝消息一致
187
+ detail: {
188
+ data: params[0]?.data
189
+ }
190
+ }))
120
191
  asyncCallback = Promise.resolve({
121
192
  errMsg: 'invokeWebappApi:ok'
122
193
  })
123
194
  break
124
195
  case 'navigateTo':
125
- asyncCallback = navObj.navigateTo(postData)
196
+ asyncCallback = navObj.navigateTo(...params)
126
197
  break
127
198
  case 'navigateBack':
128
- asyncCallback = navObj.navigateBack(postData)
199
+ asyncCallback = navObj.navigateBack(...params)
129
200
  break
130
201
  case 'redirectTo':
131
- asyncCallback = navObj.redirectTo(postData)
202
+ asyncCallback = navObj.redirectTo(...params)
132
203
  break
133
204
  case 'switchTab':
134
- asyncCallback = navObj.switchTab(postData)
205
+ asyncCallback = navObj.switchTab(...params)
135
206
  break
136
207
  case 'reLaunch':
137
- asyncCallback = navObj.reLaunch(postData)
208
+ asyncCallback = navObj.reLaunch(...params)
209
+ break
210
+ default:
211
+ if (type) {
212
+ const implement = mpx.config.webviewConfig.apiImplementations && mpx.config.webviewConfig.apiImplementations[type]
213
+ if (isFunction(implement)) {
214
+ asyncCallback = Promise.resolve(implement(...params))
215
+ } else {
216
+ /* eslint-disable prefer-promise-reject-errors */
217
+ asyncCallback = Promise.reject({
218
+ errMsg: `未在apiImplementations中配置${type}方法`
219
+ })
220
+ }
221
+ }
138
222
  break
139
223
  }
140
224
 
141
225
  asyncCallback && asyncCallback.then((res: any) => {
142
226
  if (webViewRef.current?.postMessage) {
143
- const test = JSON.stringify({
144
- type: data.type,
227
+ const result = JSON.stringify({
228
+ type,
145
229
  callbackId: data.callbackId,
146
230
  result: res
147
231
  })
148
- webViewRef.current.postMessage(test)
232
+ webViewRef.current.injectJavaScript(sendMessage(result))
149
233
  }
234
+ }).catch((error: any) => {
235
+ if (webViewRef.current?.postMessage) {
236
+ const result = JSON.stringify({
237
+ type,
238
+ callbackId: data.callbackId,
239
+ error
240
+ })
241
+ webViewRef.current.injectJavaScript(sendMessage(result))
242
+ }
243
+ })
244
+ }
245
+ const events = {}
246
+
247
+ if (bindload) {
248
+ extendObject(events, {
249
+ onLoad: _load
150
250
  })
151
251
  }
152
- return (<Portal>
153
- <WebView
154
- style={defaultWebViewStyle}
155
- source={{ uri: src }}
156
- ref={webViewRef}
157
- onLoad={_load}
158
- onError={_error}
159
- onMessage={_message}
160
- javaScriptEnabled={true}
161
- ></WebView>
162
- </Portal>)
252
+ if (binderror) {
253
+ extendObject(events, {
254
+ onError: _error
255
+ })
256
+ }
257
+
258
+ return createElement(Portal, null, createElement(WebView, extendObject({
259
+ style: defaultWebViewStyle,
260
+ source: { uri: src },
261
+ ref: webViewRef,
262
+ javaScriptEnabled: true,
263
+ onNavigationStateChange: _changeUrl,
264
+ onMessage: _message,
265
+ injectedJavaScript: injectedJavaScript,
266
+ onLoadProgress: _onLoadProgress,
267
+ allowsBackForwardNavigationGestures: true
268
+ }, events)))
163
269
  })
164
270
 
165
271
  _WebView.displayName = 'MpxWebview'
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Borrowed from open-source code: https://github.com/quidone/react-native-wheel-picker
3
+ * Special thanks to the authors for their contribution to the open-source community.
4
+ */
5
+
6
+ export type Faces = {
7
+ index: number
8
+ deg: number
9
+ offsetY: number
10
+ opacity: number
11
+ scale: number
12
+ screenHeight: number
13
+ }
14
+
15
+ export const degToRad = (deg: number) => (Math.PI * deg) / 180
16
+
17
+ // Calculates the height of the element after rotating it relative to the user's screen.
18
+ const calcHeight = (degree: number, itemHeight: number) =>
19
+ itemHeight * Math.cos(degToRad(degree))
20
+
21
+ export const calcPickerHeight = (faces: Faces[], itemHeight: number) => {
22
+ if (faces.length === 7) {
23
+ return itemHeight * 5
24
+ }
25
+ return faces.reduce((r, v) => r + calcHeight(Math.abs(v.deg), itemHeight), 0)
26
+ }
27
+
28
+ export const createFaces = (
29
+ itemHeight: number,
30
+ visibleCount: number
31
+ ): Faces[] => {
32
+ // e.g [30, 60, 90]
33
+ const getDegreesRelativeCenter = () => {
34
+ const maxStep = Math.trunc((visibleCount + 2) / 2) // + 2 because there are 2 more faces at 90 degrees
35
+ const stepDegree = 90 / maxStep
36
+
37
+ const result: number[] = []
38
+ for (let i = 1; i <= maxStep; i++) {
39
+ result.push(i * stepDegree)
40
+ }
41
+ return result
42
+ }
43
+
44
+ const getScreenHeightsAndOffsets = <T extends readonly number[]>(
45
+ degrees: T
46
+ ): [T, T] => {
47
+ const screenHeights = degrees.map((deg) =>
48
+ calcHeight(deg, itemHeight)
49
+ ) as unknown as T
50
+ const freeSpaces = screenHeights.map(
51
+ (screenHeight) => itemHeight - screenHeight
52
+ )
53
+ const offsets = freeSpaces.map((freeSpace, index) => {
54
+ let offset = freeSpace / 2
55
+ for (let i = 0; i < index; i++) {
56
+ offset += freeSpaces[i]
57
+ }
58
+ if (index === 0) {
59
+ offset *= 0.6
60
+ }
61
+ return offset
62
+ }) as unknown as T
63
+ return [screenHeights, offsets]
64
+ }
65
+
66
+ const getOpacity = (index: number) => {
67
+ const map: Record<number, number> = {
68
+ 0: 0,
69
+ 1: 0.8,
70
+ 2: 0.9 // 0.35
71
+ // 3: 0.45, // 0.45
72
+ // 4: 0.5 // 0.5
73
+ }
74
+ return map[index] ?? Math.min(1, map[2] + index * 0.05)
75
+ }
76
+
77
+ const degrees = getDegreesRelativeCenter()
78
+ const [screenHeight, offsets] = getScreenHeightsAndOffsets(degrees)
79
+
80
+ const scales = [1, 0.925, 0.8]
81
+
82
+ return [
83
+ // top items
84
+ ...degrees
85
+ .map<Faces>((degree, index) => {
86
+ return {
87
+ index: -1 * (index + 1),
88
+ deg: degree,
89
+ opacity: getOpacity(degrees.length - 1 - index),
90
+ offsetY: -1 * offsets[index],
91
+ scale: scales[index],
92
+ screenHeight: screenHeight[index]
93
+ }
94
+ })
95
+ .reverse(),
96
+
97
+ // center item
98
+ { index: 0, deg: 0, opacity: 1, offsetY: 0, scale: 1, screenHeight: itemHeight },
99
+
100
+ // bottom items
101
+ ...degrees.map<Faces>((degree, index) => {
102
+ return {
103
+ index: index + 1,
104
+ deg: -1 * degree,
105
+ opacity: getOpacity(degrees.length - 1 - index),
106
+ offsetY: offsets[index],
107
+ scale: scales[index],
108
+ screenHeight: screenHeight[index]
109
+ }
110
+ })
111
+ ]
112
+ }
@@ -0,0 +1,18 @@
1
+ import { createContext, useContext } from 'react'
2
+ import { SharedValue } from 'react-native-reanimated'
3
+
4
+ type ContextValue = SharedValue<number>
5
+
6
+ export const PickerViewColumnAnimationContext = createContext<
7
+ ContextValue | undefined
8
+ >(undefined)
9
+
10
+ export const usePickerViewColumnAnimationContext = () => {
11
+ const value = useContext(PickerViewColumnAnimationContext)
12
+ if (value === undefined) {
13
+ throw new Error(
14
+ 'usePickerViewColumnAnimationContext must be called from within PickerViewColumnAnimationContext.Provider!'
15
+ )
16
+ }
17
+ return value
18
+ }
@@ -0,0 +1,30 @@
1
+ import React from 'react'
2
+ import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native'
3
+ import LinearGradient from 'react-native-linear-gradient'
4
+
5
+ type OverlayProps = {
6
+ itemHeight: number
7
+ maskContainerStyle?: StyleProp<ViewStyle>
8
+ }
9
+
10
+ const _PickerViewMask = ({
11
+ itemHeight,
12
+ maskContainerStyle
13
+ }: OverlayProps) => {
14
+ return (
15
+ <View style={[styles.overlayContainer, maskContainerStyle]} pointerEvents={'none'}>
16
+ <LinearGradient colors={['rgba(255,255,255,1)', 'rgba(255,255,255,0.5)']} style={{ flex: 1 }} />
17
+ <View style={{ height: itemHeight }} />
18
+ <LinearGradient colors={['rgba(255,255,255,0.5)', 'rgba(255,255,255,1)']} style={{ flex: 1 }} />
19
+ </View>
20
+ )
21
+ }
22
+ const styles = StyleSheet.create({
23
+ overlayContainer: {
24
+ ...StyleSheet.absoluteFillObject,
25
+ zIndex: 100
26
+ }
27
+ })
28
+
29
+ _PickerViewMask.displayName = 'MpxPickerViewMask'
30
+ export default _PickerViewMask
@@ -0,0 +1,34 @@
1
+ import React from 'react'
2
+ import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native'
3
+
4
+ type OverlayProps = {
5
+ itemHeight: number
6
+ overlayItemStyle?: StyleProp<ViewStyle>
7
+ overlayContainerStyle?: StyleProp<ViewStyle>
8
+ }
9
+
10
+ const _PickerViewOverlay = ({ itemHeight, overlayItemStyle, overlayContainerStyle }: OverlayProps) => {
11
+ return (
12
+ <View style={[styles.overlayContainer, overlayContainerStyle]} pointerEvents={'none'}>
13
+ <View style={[styles.selection, { height: itemHeight }, overlayItemStyle]} />
14
+ </View>
15
+ )
16
+ }
17
+
18
+ const styles = StyleSheet.create({
19
+ overlayContainer: {
20
+ ...StyleSheet.absoluteFillObject,
21
+ justifyContent: 'center',
22
+ alignItems: 'center',
23
+ zIndex: 200
24
+ },
25
+ selection: {
26
+ borderTopWidth: 1,
27
+ borderBottomWidth: 1,
28
+ borderColor: 'rgba(0, 0, 0, 0.05)',
29
+ alignSelf: 'stretch'
30
+ }
31
+ })
32
+
33
+ _PickerViewOverlay.displayName = 'MpxPickerViewOverlay'
34
+ export default _PickerViewOverlay
@@ -16,3 +16,5 @@ export type ExtendedViewStyle = ViewStyle & {
16
16
  export type ExtendedFunctionComponent = FunctionComponent & {
17
17
  isCustomText?: boolean
18
18
  }
19
+
20
+ export type AnyFunc = (...args: ReadonlyArray<any>) => any
@@ -1,21 +1,8 @@
1
- declare module 'react-native-svg/css' {
2
- import type { ImageSourcePropType, StyleProp, ImageStyle } from 'react-native'
3
- import type { SvgProps as SvgCssUriProps } from 'react-native-svg'
4
-
5
- export const SvgCssUri: React.ComponentType<SvgCssUriProps & { uri?: string }>
6
-
7
- export interface WithLocalSvgProps {
8
- asset: ImageSourcePropType
9
- style?: StyleProp<ImageStyle>
10
- width?: string | number
11
- height?: string | number
12
- }
13
-
14
- export const WithLocalSvg: React.ComponentType<WithLocalSvgProps>
15
- }
16
-
1
+ declare let __mpx_mode__: 'wx' | 'ali' | 'swan' | 'qq' | 'tt' | 'web' | 'dd' | 'qa' | 'jd' | 'android' | 'ios'
17
2
  declare module '@mpxjs/utils' {
18
3
  export function isEmptyObject (obj: Object): boolean
4
+ export function isFunction (fn: unknown): boolean
5
+ export function isNumber (num: unknown): boolean
19
6
  export function hasOwn (obj: Object, key: string): boolean
20
7
  export function noop (...arg: any): void
21
8
  export function diffAndCloneA<A, B> (a: A, b?: B): {
@@ -26,13 +13,16 @@ declare module '@mpxjs/utils' {
26
13
  export function isObject (value): value is Object
27
14
  export function error (msg: string, location?: string, e?: any): void
28
15
  export function warn (msg: string, location?: string, e?: any): void
16
+ export function collectDataset (props: Record<string, any>, needParse?: boolean): Record<string, any>
29
17
  export function getFocusedNavigation (): {
30
18
  insets: {
31
19
  top: number
32
20
  bottom: number
33
21
  left: number
34
22
  right: number
35
- }
23
+ },
24
+ setOptions: (params: Record<string, any>) => void,
25
+ addListener: (eventName: string, callback: (e: Event) => void) => void
36
26
  } | undefined
37
27
  }
38
28
 
@@ -83,12 +83,34 @@ const InitialValue: ExtendedViewStyle = Object.assign({
83
83
  const TransformOrigin = 'transformOrigin'
84
84
  // transform
85
85
  const isTransform = (key: string) => Object.keys(TransformInitial).includes(key)
86
+ // 多value解析
87
+ const parseValues = (str: string, char = ' ') => {
88
+ let stack = 0
89
+ let temp = ''
90
+ const result = []
91
+ for (let i = 0; i < str.length; i++) {
92
+ if (str[i] === '(') {
93
+ stack++
94
+ } else if (str[i] === ')') {
95
+ stack--
96
+ }
97
+ // 非括号内 或者 非分隔字符且非空
98
+ if (stack !== 0 || (str[i] !== char && str[i] !== ' ')) {
99
+ temp += str[i]
100
+ }
101
+ if ((stack === 0 && str[i] === char) || i === str.length - 1) {
102
+ result.push(temp)
103
+ temp = ''
104
+ }
105
+ }
106
+ return result
107
+ }
86
108
  // parse string transform, eg: transform: 'rotateX(45deg) rotateZ(0.785398rad)'
87
109
  const parseTransform = (transformStr: string) => {
88
- const values = transformStr.trim().split(/\s+/)
110
+ const values = parseValues(transformStr)
89
111
  const transform: {[propName: string]: string|number|number[]}[] = []
90
112
  values.forEach(item => {
91
- const match = item.match(/([/\w]+)\(([^)]+)\)/)
113
+ const match = item.match(/([/\w]+)\((.+)\)/)
92
114
  if (match && match.length >= 3) {
93
115
  let key = match[1]
94
116
  const val = match[2]
@@ -109,7 +131,7 @@ const parseTransform = (transformStr: string) => {
109
131
  break
110
132
  case 'matrix':
111
133
  case 'matrix3d':
112
- transform.push({ [key]: val.split(',').map(val => +val) })
134
+ transform.push({ [key]: parseValues(val, ',').map(val => +val) })
113
135
  break
114
136
  case 'translate':
115
137
  case 'scale':
@@ -120,8 +142,8 @@ const parseTransform = (transformStr: string) => {
120
142
  {
121
143
  // 2 个以上的值处理
122
144
  key = key.replace('3d', '')
123
- const vals = val.split(',', key === 'rotate' ? 4 : 3)
124
- // scale(.5) === scaleX(.5) scaleY(.5) 这里处理一下
145
+ const vals = parseValues(val, ',').splice(0, key === 'rotate' ? 4 : 3)
146
+ // scale(.5) === scaleX(.5) scaleY(.5)
125
147
  if (vals.length === 1 && key === 'scale') {
126
148
  vals.push(vals[0])
127
149
  }
@@ -218,12 +240,15 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
218
240
  }
219
241
  // 添加每个key的多次step动画
220
242
  animatedKeys.forEach(key => {
221
- let toVal = (rules.get(key) || transform.get(key))
222
243
  // key不存在,第一轮取shareValMap[key]value,非第一轮取上一轮的
223
- if (toVal === undefined) {
224
- toVal = index > 0 ? lastValueMap[key] : shareValMap[key].value
225
- }
226
- const animation = getAnimation({ key, value: toVal }, { delay, duration, easing }, needSetCallback ? setTransformOrigin : undefined)
244
+ const toVal = rules.get(key) !== undefined
245
+ ? rules.get(key)
246
+ : transform.get(key) !== undefined
247
+ ? transform.get(key)
248
+ : index > 0
249
+ ? lastValueMap[key]
250
+ : shareValMap[key].value
251
+ const animation = getAnimation({ key, value: toVal! }, { delay, duration, easing }, needSetCallback ? setTransformOrigin : undefined)
227
252
  needSetCallback = false
228
253
  if (!sequence[key]) {
229
254
  sequence[key] = [animation]
@@ -231,7 +256,7 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
231
256
  sequence[key].push(animation)
232
257
  }
233
258
  // 更新一下 lastValueMap
234
- lastValueMap[key] = toVal
259
+ lastValueMap[key] = toVal!
235
260
  })
236
261
  // 赋值驱动动画
237
262
  animatedKeys.forEach((key) => {
@@ -327,6 +352,6 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
327
352
  styles[key] = shareValMap[key].value
328
353
  }
329
354
  return styles
330
- }, Object.assign({}, originalStyle) as ExtendedViewStyle)
355
+ }, {} as ExtendedViewStyle)
331
356
  })
332
357
  }