@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.
- package/lib/dependencies/RecordGlobalComponentsDependency.js +11 -12
- package/lib/dependencies/RecordRuntimeInfoDependency.js +1 -1
- package/lib/index.js +29 -8
- package/lib/json-compiler/index.js +2 -11
- package/lib/loader.js +24 -45
- package/lib/native-loader.js +49 -64
- package/lib/platform/json/wx/index.js +24 -18
- package/lib/platform/style/wx/index.js +49 -47
- package/lib/platform/template/wx/component-config/canvas.js +8 -0
- package/lib/platform/template/wx/component-config/fix-component-name.js +15 -12
- package/lib/platform/template/wx/component-config/index.js +1 -1
- package/lib/platform/template/wx/component-config/input.js +1 -1
- package/lib/platform/template/wx/component-config/rich-text.js +8 -0
- package/lib/platform/template/wx/component-config/swiper.js +1 -1
- package/lib/platform/template/wx/component-config/textarea.js +1 -1
- package/lib/platform/template/wx/component-config/unsupported.js +1 -1
- package/lib/react/index.js +4 -3
- package/lib/react/processJSON.js +5 -13
- package/lib/react/processMainScript.js +7 -3
- package/lib/react/processScript.js +3 -4
- package/lib/react/processStyles.js +14 -4
- package/lib/react/processTemplate.js +5 -2
- package/lib/resolver/AddModePlugin.js +20 -7
- package/lib/runtime/components/react/context.ts +6 -0
- package/lib/runtime/components/react/dist/context.js +2 -0
- package/lib/runtime/components/react/dist/event.config.js +24 -24
- package/lib/runtime/components/react/dist/getInnerListeners.js +183 -174
- package/lib/runtime/components/react/dist/mpx-button.jsx +78 -50
- package/lib/runtime/components/react/dist/mpx-canvas/Bus.js +60 -0
- package/lib/runtime/components/react/dist/mpx-canvas/CanvasGradient.js +15 -0
- package/lib/runtime/components/react/dist/mpx-canvas/CanvasRenderingContext2D.js +84 -0
- package/lib/runtime/components/react/dist/mpx-canvas/Image.js +87 -0
- package/lib/runtime/components/react/dist/mpx-canvas/ImageData.js +15 -0
- package/lib/runtime/components/react/dist/mpx-canvas/constructorsRegistry.js +28 -0
- package/lib/runtime/components/react/dist/mpx-canvas/html.js +343 -0
- package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +232 -0
- package/lib/runtime/components/react/dist/mpx-canvas/utils.jsx +89 -0
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +41 -34
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +30 -39
- package/lib/runtime/components/react/dist/mpx-form.jsx +47 -41
- package/lib/runtime/components/react/dist/mpx-icon.jsx +9 -17
- package/lib/runtime/components/react/dist/mpx-image.jsx +291 -0
- package/lib/runtime/components/react/dist/mpx-input.jsx +95 -62
- package/lib/runtime/components/react/dist/mpx-label.jsx +24 -28
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +20 -30
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +377 -293
- package/lib/runtime/components/react/dist/mpx-navigator.jsx +3 -5
- package/lib/runtime/components/react/dist/mpx-picker/date.jsx +6 -2
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +5 -3
- package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +6 -2
- package/lib/runtime/components/react/dist/mpx-picker/region.jsx +6 -2
- package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +6 -2
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +10 -15
- package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +39 -0
- package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +160 -88
- package/lib/runtime/components/react/dist/mpx-picker-view.jsx +80 -121
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +39 -34
- package/lib/runtime/components/react/dist/mpx-radio.jsx +28 -43
- package/lib/runtime/components/react/dist/mpx-rich-text/html.js +39 -0
- package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +63 -0
- package/lib/runtime/components/react/dist/mpx-root-portal.jsx +7 -5
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +77 -51
- package/lib/runtime/components/react/dist/mpx-simple-text.jsx +11 -0
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +5 -3
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +606 -0
- package/lib/runtime/components/react/dist/mpx-switch.jsx +28 -11
- package/lib/runtime/components/react/dist/mpx-text.jsx +12 -11
- package/lib/runtime/components/react/dist/mpx-textarea.jsx +9 -4
- package/lib/runtime/components/react/dist/mpx-view.jsx +66 -62
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +113 -36
- package/lib/runtime/components/react/dist/pickerFaces.js +81 -0
- package/lib/runtime/components/react/dist/pickerVIewContext.js +9 -0
- package/lib/runtime/components/react/dist/pickerViewMask.jsx +18 -0
- package/lib/runtime/components/react/dist/pickerViewOverlay.jsx +23 -0
- package/lib/runtime/components/react/dist/useAnimationHooks.js +126 -12
- package/lib/runtime/components/react/dist/utils.jsx +80 -24
- package/lib/runtime/components/react/event.config.ts +25 -26
- package/lib/runtime/components/react/getInnerListeners.ts +237 -198
- package/lib/runtime/components/react/mpx-button.tsx +105 -58
- package/lib/runtime/components/react/mpx-canvas/Bus.ts +70 -0
- package/lib/runtime/components/react/mpx-canvas/CanvasGradient.ts +18 -0
- package/lib/runtime/components/react/mpx-canvas/CanvasRenderingContext2D.ts +87 -0
- package/lib/runtime/components/react/mpx-canvas/Image.ts +102 -0
- package/lib/runtime/components/react/mpx-canvas/ImageData.ts +23 -0
- package/lib/runtime/components/react/mpx-canvas/constructorsRegistry.ts +38 -0
- package/lib/runtime/components/react/mpx-canvas/html.ts +343 -0
- package/lib/runtime/components/react/mpx-canvas/index.tsx +296 -0
- package/lib/runtime/components/react/mpx-canvas/utils.tsx +150 -0
- package/lib/runtime/components/react/mpx-checkbox-group.tsx +77 -51
- package/lib/runtime/components/react/mpx-checkbox.tsx +49 -50
- package/lib/runtime/components/react/mpx-form.tsx +62 -57
- package/lib/runtime/components/react/mpx-icon.tsx +13 -18
- package/lib/runtime/components/react/mpx-image.tsx +436 -0
- package/lib/runtime/components/react/mpx-input.tsx +139 -117
- package/lib/runtime/components/react/mpx-label.tsx +36 -34
- package/lib/runtime/components/react/mpx-movable-area.tsx +26 -39
- package/lib/runtime/components/react/mpx-movable-view.tsx +455 -337
- package/lib/runtime/components/react/mpx-navigator.tsx +3 -9
- package/lib/runtime/components/react/mpx-picker/date.tsx +5 -2
- package/lib/runtime/components/react/mpx-picker/index.tsx +3 -2
- package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +5 -2
- package/lib/runtime/components/react/mpx-picker/region.tsx +5 -2
- package/lib/runtime/components/react/mpx-picker/selector.tsx +5 -2
- package/lib/runtime/components/react/mpx-picker/time.tsx +10 -15
- package/lib/runtime/components/react/mpx-picker/type.ts +48 -43
- package/lib/runtime/components/react/mpx-picker-view-column.tsx +236 -104
- package/lib/runtime/components/react/mpx-picker-view.tsx +132 -122
- package/lib/runtime/components/react/mpx-radio-group.tsx +77 -54
- package/lib/runtime/components/react/mpx-radio.tsx +46 -55
- package/lib/runtime/components/react/mpx-rich-text/html.ts +40 -0
- package/lib/runtime/components/react/mpx-rich-text/index.tsx +121 -0
- package/lib/runtime/components/react/mpx-root-portal.tsx +4 -6
- package/lib/runtime/components/react/mpx-scroll-view.tsx +122 -76
- package/lib/runtime/components/react/mpx-simple-text.tsx +18 -0
- package/lib/runtime/components/react/mpx-swiper/carouse.tsx +6 -4
- package/lib/runtime/components/react/mpx-swiper/index.tsx +2 -1
- package/lib/runtime/components/react/mpx-swiper-item.tsx +4 -3
- package/lib/runtime/components/react/mpx-switch.tsx +39 -25
- package/lib/runtime/components/react/mpx-text.tsx +15 -19
- package/lib/runtime/components/react/mpx-textarea.tsx +12 -11
- package/lib/runtime/components/react/mpx-view.tsx +93 -77
- package/lib/runtime/components/react/mpx-web-view.tsx +117 -55
- package/lib/runtime/components/react/pickerFaces.ts +104 -0
- package/lib/runtime/components/react/pickerOverlay.tsx +32 -0
- package/lib/runtime/components/react/types/common.ts +2 -0
- package/lib/runtime/components/react/types/global.d.ts +5 -17
- package/lib/runtime/components/react/useAnimationHooks.ts +127 -18
- package/lib/runtime/components/react/useNodesRef.ts +1 -0
- package/lib/runtime/components/react/utils.tsx +113 -27
- package/lib/runtime/components/web/getInnerListeners.js +6 -6
- package/lib/runtime/components/web/mpx-movable-view.vue +334 -344
- package/lib/runtime/components/web/mpx-picker-view-column.vue +75 -75
- package/lib/runtime/components/web/mpx-picker.vue +382 -385
- package/lib/runtime/components/web/mpx-web-view.vue +175 -161
- package/lib/runtime/optionProcessor.js +7 -38
- package/lib/runtime/optionProcessorReact.js +0 -15
- package/lib/runtime/swanHelper.wxs +1 -1
- package/lib/runtime/utils.js +2 -0
- package/lib/style-compiler/index.js +1 -1
- package/lib/style-compiler/plugins/scope-id.js +31 -2
- package/lib/template-compiler/bind-this.js +7 -2
- package/lib/template-compiler/compiler.js +118 -56
- package/lib/template-compiler/gen-node-react.js +3 -3
- package/lib/template-compiler/index.js +4 -4
- package/lib/utils/pre-process-json.js +117 -0
- package/lib/web/index.js +5 -4
- package/lib/web/processJSON.js +5 -13
- package/lib/web/processTemplate.js +2 -2
- package/package.json +6 -4
- package/LICENSE +0 -433
- package/lib/runtime/components/react/dist/mpx-image/index.jsx +0 -226
- package/lib/runtime/components/react/dist/mpx-image/svg.jsx +0 -7
- package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +0 -478
- package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +0 -68
- package/lib/runtime/components/react/dist/mpx-swiper/type.js +0 -1
- package/lib/runtime/components/react/mpx-image/index.tsx +0 -346
- package/lib/runtime/components/react/mpx-image/svg.tsx +0 -22
- package/lib/runtime/components/web/event.js +0 -105
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { forwardRef, JSX,
|
|
2
|
-
import {
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
61
|
+
style: defaultWebViewStyle
|
|
65
62
|
})
|
|
66
63
|
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
115
|
-
}
|
|
127
|
+
} catch (e) {}
|
|
128
|
+
const args = data.args
|
|
116
129
|
const postData: PayloadData = data.payload || {}
|
|
117
|
-
|
|
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
|
-
|
|
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(
|
|
153
|
+
asyncCallback = navObj.navigateTo(...params)
|
|
126
154
|
break
|
|
127
155
|
case 'navigateBack':
|
|
128
|
-
asyncCallback = navObj.navigateBack(
|
|
156
|
+
asyncCallback = navObj.navigateBack(...params)
|
|
129
157
|
break
|
|
130
158
|
case 'redirectTo':
|
|
131
|
-
asyncCallback = navObj.redirectTo(
|
|
159
|
+
asyncCallback = navObj.redirectTo(...params)
|
|
132
160
|
break
|
|
133
161
|
case 'switchTab':
|
|
134
|
-
asyncCallback = navObj.switchTab(
|
|
162
|
+
asyncCallback = navObj.switchTab(...params)
|
|
135
163
|
break
|
|
136
164
|
case 'reLaunch':
|
|
137
|
-
asyncCallback = navObj.reLaunch(
|
|
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
|
|
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
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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 = '
|
|
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)
|
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
|
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
|
-
},
|
|
355
|
+
}, {} as ExtendedViewStyle)
|
|
247
356
|
})
|
|
248
357
|
}
|