@mpxjs/webpack-plugin 2.9.66 → 2.9.69-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/lib/dependencies/RecordGlobalComponentsDependency.js +11 -12
  2. package/lib/dependencies/RecordRuntimeInfoDependency.js +1 -1
  3. package/lib/index.js +29 -8
  4. package/lib/json-compiler/index.js +2 -11
  5. package/lib/loader.js +24 -45
  6. package/lib/native-loader.js +49 -64
  7. package/lib/platform/json/wx/index.js +24 -18
  8. package/lib/platform/style/wx/index.js +49 -47
  9. package/lib/platform/template/wx/component-config/canvas.js +8 -0
  10. package/lib/platform/template/wx/component-config/fix-component-name.js +15 -12
  11. package/lib/platform/template/wx/component-config/index.js +1 -1
  12. package/lib/platform/template/wx/component-config/input.js +1 -1
  13. package/lib/platform/template/wx/component-config/rich-text.js +8 -0
  14. package/lib/platform/template/wx/component-config/swiper.js +1 -1
  15. package/lib/platform/template/wx/component-config/textarea.js +1 -1
  16. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  17. package/lib/react/index.js +4 -3
  18. package/lib/react/processJSON.js +5 -13
  19. package/lib/react/processMainScript.js +7 -3
  20. package/lib/react/processScript.js +3 -4
  21. package/lib/react/processStyles.js +14 -4
  22. package/lib/react/processTemplate.js +5 -2
  23. package/lib/resolver/AddModePlugin.js +20 -7
  24. package/lib/runtime/components/react/context.ts +6 -0
  25. package/lib/runtime/components/react/dist/context.js +2 -0
  26. package/lib/runtime/components/react/dist/event.config.js +24 -24
  27. package/lib/runtime/components/react/dist/getInnerListeners.js +183 -174
  28. package/lib/runtime/components/react/dist/mpx-button.jsx +78 -50
  29. package/lib/runtime/components/react/dist/mpx-canvas/Bus.js +60 -0
  30. package/lib/runtime/components/react/dist/mpx-canvas/CanvasGradient.js +15 -0
  31. package/lib/runtime/components/react/dist/mpx-canvas/CanvasRenderingContext2D.js +84 -0
  32. package/lib/runtime/components/react/dist/mpx-canvas/Image.js +87 -0
  33. package/lib/runtime/components/react/dist/mpx-canvas/ImageData.js +15 -0
  34. package/lib/runtime/components/react/dist/mpx-canvas/constructorsRegistry.js +28 -0
  35. package/lib/runtime/components/react/dist/mpx-canvas/html.js +343 -0
  36. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +232 -0
  37. package/lib/runtime/components/react/dist/mpx-canvas/utils.jsx +89 -0
  38. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +41 -34
  39. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +30 -39
  40. package/lib/runtime/components/react/dist/mpx-form.jsx +47 -41
  41. package/lib/runtime/components/react/dist/mpx-icon.jsx +9 -17
  42. package/lib/runtime/components/react/dist/mpx-image.jsx +291 -0
  43. package/lib/runtime/components/react/dist/mpx-input.jsx +95 -62
  44. package/lib/runtime/components/react/dist/mpx-label.jsx +24 -28
  45. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +20 -30
  46. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +377 -293
  47. package/lib/runtime/components/react/dist/mpx-navigator.jsx +3 -5
  48. package/lib/runtime/components/react/dist/mpx-picker/date.jsx +6 -2
  49. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +5 -3
  50. package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +6 -2
  51. package/lib/runtime/components/react/dist/mpx-picker/region.jsx +6 -2
  52. package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +6 -2
  53. package/lib/runtime/components/react/dist/mpx-picker/time.jsx +10 -15
  54. package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +39 -0
  55. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +160 -88
  56. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +80 -121
  57. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +39 -34
  58. package/lib/runtime/components/react/dist/mpx-radio.jsx +28 -43
  59. package/lib/runtime/components/react/dist/mpx-rich-text/html.js +39 -0
  60. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +63 -0
  61. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +7 -5
  62. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +77 -51
  63. package/lib/runtime/components/react/dist/mpx-simple-text.jsx +11 -0
  64. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +5 -3
  65. package/lib/runtime/components/react/dist/mpx-swiper.jsx +606 -0
  66. package/lib/runtime/components/react/dist/mpx-switch.jsx +28 -11
  67. package/lib/runtime/components/react/dist/mpx-text.jsx +12 -11
  68. package/lib/runtime/components/react/dist/mpx-textarea.jsx +9 -4
  69. package/lib/runtime/components/react/dist/mpx-view.jsx +66 -62
  70. package/lib/runtime/components/react/dist/mpx-web-view.jsx +113 -36
  71. package/lib/runtime/components/react/dist/pickerFaces.js +81 -0
  72. package/lib/runtime/components/react/dist/pickerVIewContext.js +9 -0
  73. package/lib/runtime/components/react/dist/pickerViewMask.jsx +18 -0
  74. package/lib/runtime/components/react/dist/pickerViewOverlay.jsx +23 -0
  75. package/lib/runtime/components/react/dist/useAnimationHooks.js +126 -12
  76. package/lib/runtime/components/react/dist/utils.jsx +80 -24
  77. package/lib/runtime/components/react/event.config.ts +25 -26
  78. package/lib/runtime/components/react/getInnerListeners.ts +237 -198
  79. package/lib/runtime/components/react/mpx-button.tsx +105 -58
  80. package/lib/runtime/components/react/mpx-canvas/Bus.ts +70 -0
  81. package/lib/runtime/components/react/mpx-canvas/CanvasGradient.ts +18 -0
  82. package/lib/runtime/components/react/mpx-canvas/CanvasRenderingContext2D.ts +87 -0
  83. package/lib/runtime/components/react/mpx-canvas/Image.ts +102 -0
  84. package/lib/runtime/components/react/mpx-canvas/ImageData.ts +23 -0
  85. package/lib/runtime/components/react/mpx-canvas/constructorsRegistry.ts +38 -0
  86. package/lib/runtime/components/react/mpx-canvas/html.ts +343 -0
  87. package/lib/runtime/components/react/mpx-canvas/index.tsx +296 -0
  88. package/lib/runtime/components/react/mpx-canvas/utils.tsx +150 -0
  89. package/lib/runtime/components/react/mpx-checkbox-group.tsx +77 -51
  90. package/lib/runtime/components/react/mpx-checkbox.tsx +49 -50
  91. package/lib/runtime/components/react/mpx-form.tsx +62 -57
  92. package/lib/runtime/components/react/mpx-icon.tsx +13 -18
  93. package/lib/runtime/components/react/mpx-image.tsx +436 -0
  94. package/lib/runtime/components/react/mpx-input.tsx +139 -117
  95. package/lib/runtime/components/react/mpx-label.tsx +36 -34
  96. package/lib/runtime/components/react/mpx-movable-area.tsx +26 -39
  97. package/lib/runtime/components/react/mpx-movable-view.tsx +455 -337
  98. package/lib/runtime/components/react/mpx-navigator.tsx +3 -9
  99. package/lib/runtime/components/react/mpx-picker/date.tsx +5 -2
  100. package/lib/runtime/components/react/mpx-picker/index.tsx +3 -2
  101. package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +5 -2
  102. package/lib/runtime/components/react/mpx-picker/region.tsx +5 -2
  103. package/lib/runtime/components/react/mpx-picker/selector.tsx +5 -2
  104. package/lib/runtime/components/react/mpx-picker/time.tsx +10 -15
  105. package/lib/runtime/components/react/mpx-picker/type.ts +48 -43
  106. package/lib/runtime/components/react/mpx-picker-view-column.tsx +236 -104
  107. package/lib/runtime/components/react/mpx-picker-view.tsx +132 -122
  108. package/lib/runtime/components/react/mpx-radio-group.tsx +77 -54
  109. package/lib/runtime/components/react/mpx-radio.tsx +46 -55
  110. package/lib/runtime/components/react/mpx-rich-text/html.ts +40 -0
  111. package/lib/runtime/components/react/mpx-rich-text/index.tsx +121 -0
  112. package/lib/runtime/components/react/mpx-root-portal.tsx +4 -6
  113. package/lib/runtime/components/react/mpx-scroll-view.tsx +122 -76
  114. package/lib/runtime/components/react/mpx-simple-text.tsx +18 -0
  115. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +6 -4
  116. package/lib/runtime/components/react/mpx-swiper/index.tsx +2 -1
  117. package/lib/runtime/components/react/mpx-swiper-item.tsx +4 -3
  118. package/lib/runtime/components/react/mpx-switch.tsx +39 -25
  119. package/lib/runtime/components/react/mpx-text.tsx +15 -19
  120. package/lib/runtime/components/react/mpx-textarea.tsx +12 -11
  121. package/lib/runtime/components/react/mpx-view.tsx +93 -77
  122. package/lib/runtime/components/react/mpx-web-view.tsx +117 -55
  123. package/lib/runtime/components/react/pickerFaces.ts +104 -0
  124. package/lib/runtime/components/react/pickerOverlay.tsx +32 -0
  125. package/lib/runtime/components/react/types/common.ts +2 -0
  126. package/lib/runtime/components/react/types/global.d.ts +5 -17
  127. package/lib/runtime/components/react/useAnimationHooks.ts +127 -18
  128. package/lib/runtime/components/react/useNodesRef.ts +1 -0
  129. package/lib/runtime/components/react/utils.tsx +113 -27
  130. package/lib/runtime/components/web/getInnerListeners.js +6 -6
  131. package/lib/runtime/components/web/mpx-movable-view.vue +334 -344
  132. package/lib/runtime/components/web/mpx-picker-view-column.vue +75 -75
  133. package/lib/runtime/components/web/mpx-picker.vue +382 -385
  134. package/lib/runtime/components/web/mpx-web-view.vue +175 -161
  135. package/lib/runtime/optionProcessor.js +7 -38
  136. package/lib/runtime/optionProcessorReact.js +0 -15
  137. package/lib/runtime/swanHelper.wxs +1 -1
  138. package/lib/runtime/utils.js +2 -0
  139. package/lib/style-compiler/index.js +1 -1
  140. package/lib/style-compiler/plugins/scope-id.js +31 -2
  141. package/lib/template-compiler/bind-this.js +7 -2
  142. package/lib/template-compiler/compiler.js +118 -56
  143. package/lib/template-compiler/gen-node-react.js +3 -3
  144. package/lib/template-compiler/index.js +4 -4
  145. package/lib/utils/pre-process-json.js +117 -0
  146. package/lib/web/index.js +5 -4
  147. package/lib/web/processJSON.js +5 -13
  148. package/lib/web/processTemplate.js +2 -2
  149. package/package.json +6 -4
  150. package/LICENSE +0 -433
  151. package/lib/runtime/components/react/dist/mpx-image/index.jsx +0 -226
  152. package/lib/runtime/components/react/dist/mpx-image/svg.jsx +0 -7
  153. package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +0 -478
  154. package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +0 -68
  155. package/lib/runtime/components/react/dist/mpx-swiper/type.js +0 -1
  156. package/lib/runtime/components/react/mpx-image/index.tsx +0 -346
  157. package/lib/runtime/components/react/mpx-image/svg.tsx +0 -22
  158. package/lib/runtime/components/web/event.js +0 -105
@@ -1,11 +1,13 @@
1
- import { forwardRef, JSX, useEffect, useRef } from 'react'
2
- import { noop, warn } from '@mpxjs/utils'
1
+ import { forwardRef, JSX, useRef, useContext, useMemo, createElement } 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 } from 'react-native-webview/lib/WebViewTypes'
10
+ import { RouteContext } from './context'
9
11
 
10
12
  type OnMessageCallbackEvent = {
11
13
  detail: {
@@ -28,29 +30,25 @@ interface WebViewProps {
28
30
  }
29
31
 
30
32
  interface PayloadData {
31
- data?: Record<string, any>
33
+ [x: string]: any
32
34
  }
33
35
 
34
36
  type MessageData = {
35
37
  payload?: PayloadData,
38
+ args?: Array<any>,
36
39
  type?: string,
37
40
  callbackId?: number
38
41
  }
39
42
 
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
43
+ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((props, ref): JSX.Element | null => {
44
+ const { src, bindmessage, bindload, binderror } = props
45
+ const mpx = global.__mpx
51
46
  if (props.style) {
52
47
  warn('The web-view component does not support the style prop.')
53
48
  }
49
+ const pageId = useContext(RouteContext)
50
+ const currentPage = useMemo(() => getCurrentPage(pageId), [pageId])
51
+ const webViewRef = useRef<WebView>(null)
54
52
  const defaultWebViewStyle = {
55
53
  position: 'absolute' as 'absolute' | 'relative' | 'static',
56
54
  left: 0 as number,
@@ -59,28 +57,14 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
59
57
  bottom: 0 as number
60
58
  }
61
59
 
62
- const webViewRef = useRef<WebView>(null)
63
60
  useNodesRef<WebView, WebViewProps>(props, ref, webViewRef, {
64
- defaultStyle: defaultWebViewStyle
61
+ style: defaultWebViewStyle
65
62
  })
66
63
 
67
- const _messageList: any[] = []
68
- const handleUnload = () => {
69
- // 这里是 WebView 销毁前执行的逻辑
70
- bindmessage(getCustomEvent('messsage', {}, {
71
- detail: {
72
- data: _messageList
73
- },
74
- layoutRef: webViewRef
75
- }))
64
+ if (!src) {
65
+ return null
76
66
  }
77
67
 
78
- useEffect(() => {
79
- // 组件卸载时执行
80
- return () => {
81
- handleUnload()
82
- }
83
- }, [])
84
68
  const _load = function (res: WebViewNavigationEvent) {
85
69
  const result = {
86
70
  type: 'load',
@@ -101,6 +85,36 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
101
85
  }
102
86
  binderror(result)
103
87
  }
88
+ const injectedJavaScript = `
89
+ if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
90
+ var _documentTitle = document.title;
91
+ window.ReactNativeWebView.postMessage(JSON.stringify({
92
+ type: 'setTitle',
93
+ payload: {
94
+ _documentTitle: _documentTitle
95
+ }
96
+ }))
97
+ Object.defineProperty(document, 'title', {
98
+ set (val) {
99
+ _documentTitle = val
100
+ window.ReactNativeWebView.postMessage(JSON.stringify({
101
+ type: 'setTitle',
102
+ payload: {
103
+ _documentTitle: _documentTitle
104
+ }
105
+ }))
106
+ },
107
+ get () {
108
+ return _documentTitle
109
+ }
110
+ });
111
+ }
112
+ `
113
+ const _changeUrl = function (navState: WebViewNavigation) {
114
+ if (navState.navigationType) { // navigationType这个事件在页面开始加载时和页面加载完成时都会被触发所以判断这个避免其他无效触发执行该逻辑
115
+ currentPage.__webViewUrl = navState.url
116
+ }
117
+ }
104
118
  const _message = function (res: WebViewMessageEvent) {
105
119
  let data: MessageData = {}
106
120
  let asyncCallback
@@ -110,58 +124,106 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
110
124
  if (typeof nativeEventData === 'string') {
111
125
  data = JSON.parse(nativeEventData)
112
126
  }
113
- } catch (e) {
114
- data = {}
115
- }
127
+ } catch (e) {}
128
+ const args = data.args
116
129
  const postData: PayloadData = data.payload || {}
117
- switch (data.type) {
130
+ const params = Array.isArray(args) ? args : [postData]
131
+ const type = data.type
132
+ switch (type) {
133
+ case 'setTitle':
134
+ { // case下不允许直接声明,包个块解决该问题
135
+ const title = postData._documentTitle
136
+ if (title) {
137
+ const navigation = getFocusedNavigation()
138
+ navigation && navigation.setOptions({ title })
139
+ }
140
+ }
141
+ break
118
142
  case 'postMessage':
119
- _messageList.push(postData.data)
143
+ bindmessage && bindmessage(getCustomEvent('messsage', {}, { // RN组件销毁顺序与小程序不一致,所以改成和支付宝消息一致
144
+ detail: {
145
+ data: params[0]?.data
146
+ }
147
+ }))
120
148
  asyncCallback = Promise.resolve({
121
149
  errMsg: 'invokeWebappApi:ok'
122
150
  })
123
151
  break
124
152
  case 'navigateTo':
125
- asyncCallback = navObj.navigateTo(postData)
153
+ asyncCallback = navObj.navigateTo(...params)
126
154
  break
127
155
  case 'navigateBack':
128
- asyncCallback = navObj.navigateBack(postData)
156
+ asyncCallback = navObj.navigateBack(...params)
129
157
  break
130
158
  case 'redirectTo':
131
- asyncCallback = navObj.redirectTo(postData)
159
+ asyncCallback = navObj.redirectTo(...params)
132
160
  break
133
161
  case 'switchTab':
134
- asyncCallback = navObj.switchTab(postData)
162
+ asyncCallback = navObj.switchTab(...params)
135
163
  break
136
164
  case 'reLaunch':
137
- asyncCallback = navObj.reLaunch(postData)
165
+ asyncCallback = navObj.reLaunch(...params)
166
+ break
167
+ default:
168
+ if (type) {
169
+ const implement = mpx.config.webviewConfig.apiImplementations && mpx.config.webviewConfig.apiImplementations[type]
170
+ if (isFunction(implement)) {
171
+ asyncCallback = Promise.resolve(implement(...params))
172
+ } else {
173
+ /* eslint-disable prefer-promise-reject-errors */
174
+ asyncCallback = Promise.reject({
175
+ errMsg: `未在apiImplementations中配置${type}方法`
176
+ })
177
+ }
178
+ }
138
179
  break
139
180
  }
140
181
 
141
182
  asyncCallback && asyncCallback.then((res: any) => {
142
183
  if (webViewRef.current?.postMessage) {
143
184
  const test = JSON.stringify({
144
- type: data.type,
185
+ type,
145
186
  callbackId: data.callbackId,
146
187
  result: res
147
188
  })
148
189
  webViewRef.current.postMessage(test)
149
190
  }
191
+ }).catch((error: any) => {
192
+ if (webViewRef.current?.postMessage) {
193
+ const test = JSON.stringify({
194
+ type,
195
+ callbackId: data.callbackId,
196
+ error
197
+ })
198
+ webViewRef.current.postMessage(test)
199
+ }
150
200
  })
151
201
  }
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>)
202
+ const events = {}
203
+
204
+ if (bindload) {
205
+ extendObject(events, {
206
+ onLoad: _load
207
+ })
208
+ }
209
+ if (binderror) {
210
+ extendObject(events, {
211
+ onError: _error
212
+ })
213
+ }
214
+ extendObject(events, {
215
+ onMessage: _message
216
+ })
217
+
218
+ return createElement(Portal, null, createElement(WebView, extendObject({
219
+ style: defaultWebViewStyle,
220
+ source: { uri: src },
221
+ ref: webViewRef,
222
+ javaScriptEnabled: true,
223
+ onNavigationStateChange: _changeUrl
224
+ }, events)))
163
225
  })
164
226
 
165
- _WebView.displayName = 'mpx-web-view'
227
+ _WebView.displayName = 'MpxWebview'
166
228
 
167
229
  export default _WebView
@@ -0,0 +1,104 @@
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
+ screenHeight: number
12
+ }
13
+
14
+ export const degToRad = (deg: number) => (Math.PI * deg) / 180
15
+
16
+ // Calculates the height of the element after rotating it relative to the user's screen.
17
+ const calcHeight = (degree: number, itemHeight: number) =>
18
+ itemHeight * Math.cos(degToRad(degree))
19
+
20
+ export const calcPickerHeight = (faces: Faces[], itemHeight: number) => {
21
+ if (faces.length === 7) {
22
+ return itemHeight * 5
23
+ }
24
+ return faces.reduce((r, v) => r + calcHeight(Math.abs(v.deg), itemHeight), 0)
25
+ }
26
+
27
+ export const createFaces = (
28
+ itemHeight: number,
29
+ visibleCount: number
30
+ ): Faces[] => {
31
+ // e.g [30, 60, 90]
32
+ const getDegreesRelativeCenter = () => {
33
+ const maxStep = Math.trunc((visibleCount + 2) / 2) // + 2 because there are 2 more faces at 90 degrees
34
+ const stepDegree = 90 / maxStep
35
+
36
+ const result = []
37
+ for (let i = 1; i <= maxStep; i++) {
38
+ result.push(i * stepDegree)
39
+ }
40
+ return result
41
+ }
42
+
43
+ const getScreenHeightsAndOffsets = <T extends readonly number[]>(
44
+ degrees: T
45
+ ): [T, T] => {
46
+ const screenHeights = degrees.map((deg) =>
47
+ calcHeight(deg, itemHeight)
48
+ ) as unknown as T
49
+ const freeSpaces = screenHeights.map(
50
+ (screenHeight) => itemHeight - screenHeight
51
+ )
52
+ const offsets = freeSpaces.map((freeSpace, index) => {
53
+ let offset = freeSpace / 2
54
+ for (let i = 0; i < index; i++) {
55
+ offset += freeSpaces[i]
56
+ }
57
+ return offset
58
+ }) as unknown as T
59
+ return [screenHeights, offsets]
60
+ }
61
+
62
+ const getOpacity = (index: number) => {
63
+ const map: Record<number, number> = {
64
+ 0: 0,
65
+ 1: 0.2,
66
+ 2: 0.35,
67
+ 3: 0.45,
68
+ 4: 0.5
69
+ }
70
+ return map[index] ?? Math.min(1, map[4] + index * 0.5)
71
+ }
72
+
73
+ const degrees = getDegreesRelativeCenter()
74
+ const [screenHeight, offsets] = getScreenHeightsAndOffsets(degrees)
75
+
76
+ return [
77
+ // top items
78
+ ...degrees
79
+ .map<Faces>((degree, index) => {
80
+ return {
81
+ index: -1 * (index + 1),
82
+ deg: degree,
83
+ opacity: getOpacity(degrees.length - 1 - index),
84
+ offsetY: -1 * offsets[index],
85
+ screenHeight: screenHeight[index]
86
+ }
87
+ })
88
+ .reverse(),
89
+
90
+ // center item
91
+ { index: 0, deg: 0, opacity: 1, offsetY: 0, screenHeight: itemHeight },
92
+
93
+ // bottom items
94
+ ...degrees.map<Faces>((degree, index) => {
95
+ return {
96
+ index: index + 1,
97
+ deg: -1 * degree,
98
+ opacity: getOpacity(degrees.length - 1 - index),
99
+ offsetY: offsets[index],
100
+ screenHeight: screenHeight[index]
101
+ }
102
+ })
103
+ ]
104
+ }
@@ -0,0 +1,32 @@
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 Overlay = ({ 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
+ },
24
+ selection: {
25
+ borderTopWidth: 1,
26
+ borderBottomWidth: 1,
27
+ borderColor: 'rgba(0, 0, 0, 0.05)',
28
+ alignSelf: 'stretch'
29
+ }
30
+ })
31
+
32
+ export default React.memo(Overlay)
@@ -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,7 @@
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
-
17
1
  declare module '@mpxjs/utils' {
18
2
  export function isEmptyObject (obj: Object): boolean
3
+ export function isFunction (fn: unknown): boolean
4
+ export function isNumber (num: unknown): boolean
19
5
  export function hasOwn (obj: Object, key: string): boolean
20
6
  export function noop (...arg: any): void
21
7
  export function diffAndCloneA<A, B> (a: A, b?: B): {
@@ -26,13 +12,15 @@ declare module '@mpxjs/utils' {
26
12
  export function isObject (value): value is Object
27
13
  export function error (msg: string, location?: string, e?: any): void
28
14
  export function warn (msg: string, location?: string, e?: any): void
15
+ export function collectDataset (props: Record<string, any>, needParse?: boolean): Record<string, any>
29
16
  export function getFocusedNavigation (): {
30
17
  insets: {
31
18
  top: number
32
19
  bottom: number
33
20
  left: number
34
21
  right: number
35
- }
22
+ },
23
+ setOptions: (params: Record<string, any>) => void
36
24
  } | undefined
37
25
  }
38
26
 
@@ -16,9 +16,6 @@ import {
16
16
  import { ExtendedViewStyle } from './types/common'
17
17
  import type { _ViewProps } from './mpx-view'
18
18
 
19
- // type TransformKey = 'translateX' | 'translateY' | 'rotate' | 'rotateX' | 'rotateY' | 'rotateZ' | 'scaleX' | 'scaleY' | 'skewX' | 'skewY'
20
- // type NormalKey = 'opacity' | 'backgroundColor' | 'width' | 'height' | 'top' | 'right' | 'bottom' | 'left' | 'transformOrigin'
21
- // type RuleKey = TransformKey | NormalKey
22
19
  type AnimatedOption = {
23
20
  duration: number
24
21
  delay: number
@@ -84,20 +81,101 @@ const InitialValue: ExtendedViewStyle = Object.assign({
84
81
  transformOrigin: ['50%', '50%', 0]
85
82
  }, TransformInitial)
86
83
  const TransformOrigin = 'transformOrigin'
87
- // deg 角度
88
- // const isDeg = (key: RuleKey) => ['rotateX', 'rotateY', 'rotateZ', 'rotate', 'skewX', 'skewY'].includes(key)
89
- // 背景色
90
- // const isBg = (key: RuleKey) => key === 'backgroundColor'
91
84
  // transform
92
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
+ }
108
+ // parse string transform, eg: transform: 'rotateX(45deg) rotateZ(0.785398rad)'
109
+ const parseTransform = (transformStr: string) => {
110
+ const values = parseValues(transformStr)
111
+ const transform: {[propName: string]: string|number|number[]}[] = []
112
+ values.forEach(item => {
113
+ const match = item.match(/([/\w]+)\(([^)]+)\)/)
114
+ if (match && match.length >= 3) {
115
+ let key = match[1]
116
+ const val = match[2]
117
+ switch (key) {
118
+ case 'translateX':
119
+ case 'translateY':
120
+ case 'scaleX':
121
+ case 'scaleY':
122
+ case 'rotateX':
123
+ case 'rotateY':
124
+ case 'rotateZ':
125
+ case 'rotate':
126
+ case 'skewX':
127
+ case 'skewY':
128
+ case 'perspective':
129
+ // 单个值处理
130
+ transform.push({ [key]: global.__formatValue(val) })
131
+ break
132
+ case 'matrix':
133
+ case 'matrix3d':
134
+ transform.push({ [key]: parseValues(val, ',').map(val => +val) })
135
+ break
136
+ case 'translate':
137
+ case 'scale':
138
+ case 'skew':
139
+ case 'rotate3d': // x y z angle
140
+ case 'translate3d': // x y 支持 z不支持
141
+ case 'scale3d': // x y 支持 z不支持
142
+ {
143
+ // 2 个以上的值处理
144
+ key = key.replace('3d', '')
145
+ const vals = parseValues(val, ',').splice(0, key === 'rotate' ? 4 : 3)
146
+ // scale(.5) === scaleX(.5) scaleY(.5)
147
+ if (vals.length === 1 && key === 'scale') {
148
+ vals.push(vals[0])
149
+ }
150
+ const xyz = ['X', 'Y', 'Z']
151
+ transform.push(...vals.map((v, index) => {
152
+ return { [`${key}${xyz[index] || ''}`]: global.__formatValue(v.trim()) }
153
+ }))
154
+ break
155
+ }
156
+ }
157
+ }
158
+ })
159
+ return transform
160
+ }
161
+ // format style
162
+ const formatStyle = (style: ExtendedViewStyle): ExtendedViewStyle => {
163
+ if (!style.transform || Array.isArray(style.transform)) return style
164
+ return Object.assign({}, style, {
165
+ transform: parseTransform(style.transform)
166
+ })
167
+ }
93
168
 
94
169
  export default function useAnimationHooks<T, P> (props: _ViewProps) {
95
- const { style: originalStyle = {}, animation } = props
170
+ const { style = {}, animation } = props
171
+ const originalStyle = formatStyle(style)
96
172
  // id 标识
97
173
  const id = animation?.id || -1
98
174
  // 有动画样式的 style key
99
175
  const animatedStyleKeys = useSharedValue([] as (string|string[])[])
100
- const animatedKeys = useRef({} as {[propName: keyof ExtendedViewStyle]: Boolean})
176
+ // 记录动画key的style样式值 没有的话设置为false
177
+ const animatedKeys = useRef({} as {[propName: keyof ExtendedViewStyle]: boolean})
178
+ // const animatedKeys = useRef({} as {[propName: keyof ExtendedViewStyle]: boolean|number|string})
101
179
  // ** 全量 style prop sharedValue
102
180
  // 不能做增量的原因:
103
181
  // 1 尝试用 useRef,但 useAnimatedStyle 访问后的 ref 不能在增加新的值,被冻结
@@ -119,6 +197,16 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
119
197
  // 驱动动画
120
198
  createAnimation(keys)
121
199
  }, [id])
200
+ // 同步style更新
201
+ // useEffect(() => {
202
+ // Object.keys(animatedKeys.current).forEach(key => {
203
+ // const originVal = getOriginalStyleVal(key, isTransform(key))
204
+ // if (originVal && animatedKeys.current[key] !== originVal) {
205
+ // animatedKeys.current[key] = originVal
206
+ // shareValMap[key].value = originVal
207
+ // }
208
+ // })
209
+ // }, [style])
122
210
  // ** 清空动画
123
211
  useEffect(() => {
124
212
  return () => {
@@ -152,12 +240,15 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
152
240
  }
153
241
  // 添加每个key的多次step动画
154
242
  animatedKeys.forEach(key => {
155
- let toVal = (rules.get(key) || transform.get(key)) as number|string
156
243
  // key不存在,第一轮取shareValMap[key]value,非第一轮取上一轮的
157
- if (!toVal) {
158
- toVal = index > 0 ? lastValueMap[key] : shareValMap[key].value
159
- }
160
- 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)
161
252
  needSetCallback = false
162
253
  if (!sequence[key]) {
163
254
  sequence[key] = [animation]
@@ -165,7 +256,7 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
165
256
  sequence[key].push(animation)
166
257
  }
167
258
  // 更新一下 lastValueMap
168
- lastValueMap[key] = toVal
259
+ lastValueMap[key] = toVal!
169
260
  })
170
261
  // 赋值驱动动画
171
262
  animatedKeys.forEach((key) => {
@@ -181,9 +272,8 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
181
272
  : withTiming(value, { duration, easing })
182
273
  return delay ? withDelay(delay, animation) : animation
183
274
  }
184
- // 获取初始值(prop style or 默认值)
185
275
  function getInitialVal (key: keyof ExtendedViewStyle, isTransform = false) {
186
- if (isTransform && originalStyle.transform?.length) {
276
+ if (isTransform && Array.isArray(originalStyle.transform)) {
187
277
  let initialVal = InitialValue[key]
188
278
  // 仅支持 { transform: [{rotateX: '45deg'}, {rotateZ: '0.785398rad'}] } 格式的初始样式
189
279
  originalStyle.transform.forEach(item => {
@@ -193,12 +283,31 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
193
283
  }
194
284
  return originalStyle[key] === undefined ? InitialValue[key] : originalStyle[key]
195
285
  }
286
+ // 从 prop style 中获取样式初始值 没有为undefined
287
+ // function getOriginalStyleVal (key: keyof ExtendedViewStyle, isTransform = false) {
288
+ // if (isTransform && Array.isArray(originalStyle.transform)) {
289
+ // let initialVal = undefined // InitialValue[key]
290
+ // // 仅支持 { transform: [{rotateX: '45deg'}, {rotateZ: '0.785398rad'}] } 格式的初始样式
291
+ // originalStyle.transform.forEach(item => {
292
+ // if (item[key] !== undefined) initialVal = item[key]
293
+ // })
294
+ // return initialVal
295
+ // }
296
+ // return originalStyle[key] // === undefined ? InitialValue[key] : originalStyle[key]
297
+ // }
298
+ // 获取动画shareVal初始值(prop style or 默认值)
299
+ // function getInitialVal (key: keyof ExtendedViewStyle, isTransform = false) {
300
+ // const originalVal = getOriginalStyleVal(key, isTransform)
301
+ // return originalVal === undefined ? InitialValue[key] : originalStyle[key]
302
+ // }
196
303
  // 循环 animation actions 获取所有有动画的 style prop name
197
304
  function getAnimatedStyleKeys () {
198
305
  return (animation?.actions || []).reduce((keyMap, action) => {
199
306
  const { rules, transform } = action
200
307
  const ruleArr = [...rules.keys(), ...transform.keys()]
201
308
  ruleArr.forEach(key => {
309
+ // const originalVal = getOriginalStyleVal(key, isTransform(key))
310
+ // if (!keyMap[key]) keyMap[key] = originalVal === undefined ? false : originalVal
202
311
  if (!keyMap[key]) keyMap[key] = true
203
312
  })
204
313
  return keyMap
@@ -243,6 +352,6 @@ export default function useAnimationHooks<T, P> (props: _ViewProps) {
243
352
  styles[key] = shareValMap[key].value
244
353
  }
245
354
  return styles
246
- }, Object.assign({}, originalStyle) as ExtendedViewStyle)
355
+ }, {} as ExtendedViewStyle)
247
356
  })
248
357
  }
@@ -1,4 +1,5 @@
1
1
  import { useRef, useImperativeHandle, RefObject, ForwardedRef } from 'react'
2
+ import { useAnimatedRef } from 'react-native-reanimated'
2
3
 
3
4
  type Obj = Record<string, any>
4
5