@mpxjs/webpack-plugin 2.10.3 → 2.10.4
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/config.js +2 -1
- package/lib/index.js +1 -1
- package/lib/platform/json/wx/index.js +6 -3
- package/lib/platform/style/wx/index.js +23 -12
- package/lib/platform/template/wx/component-config/button.js +19 -2
- package/lib/platform/template/wx/component-config/canvas.js +4 -0
- package/lib/platform/template/wx/component-config/checkbox-group.js +4 -0
- package/lib/platform/template/wx/component-config/checkbox.js +4 -0
- package/lib/platform/template/wx/component-config/cover-image.js +7 -1
- package/lib/platform/template/wx/component-config/cover-view.js +4 -0
- package/lib/platform/template/wx/component-config/fix-component-name.js +3 -2
- package/lib/platform/template/wx/component-config/form.js +7 -1
- package/lib/platform/template/wx/component-config/icon.js +4 -0
- package/lib/platform/template/wx/component-config/image.js +7 -1
- package/lib/platform/template/wx/component-config/input.js +18 -3
- package/lib/platform/template/wx/component-config/label.js +4 -0
- package/lib/platform/template/wx/component-config/movable-area.js +7 -1
- package/lib/platform/template/wx/component-config/movable-view.js +12 -3
- package/lib/platform/template/wx/component-config/navigator.js +4 -0
- package/lib/platform/template/wx/component-config/picker-view-column.js +4 -0
- package/lib/platform/template/wx/component-config/picker-view.js +7 -1
- package/lib/platform/template/wx/component-config/picker.js +7 -1
- package/lib/platform/template/wx/component-config/radio-group.js +4 -0
- package/lib/platform/template/wx/component-config/radio.js +4 -0
- package/lib/platform/template/wx/component-config/rich-text.js +4 -0
- package/lib/platform/template/wx/component-config/root-portal.js +4 -0
- package/lib/platform/template/wx/component-config/scroll-view.js +10 -2
- package/lib/platform/template/wx/component-config/swiper-item.js +7 -1
- package/lib/platform/template/wx/component-config/swiper.js +12 -3
- package/lib/platform/template/wx/component-config/switch.js +4 -0
- package/lib/platform/template/wx/component-config/text.js +24 -3
- package/lib/platform/template/wx/component-config/textarea.js +17 -2
- package/lib/platform/template/wx/component-config/unsupported.js +7 -0
- package/lib/platform/template/wx/component-config/video.js +10 -2
- package/lib/platform/template/wx/component-config/view.js +11 -1
- package/lib/platform/template/wx/component-config/web-view.js +4 -0
- package/lib/platform/template/wx/index.js +42 -75
- package/lib/react/processScript.js +1 -18
- package/lib/runtime/components/react/dist/event.config.js +1 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +18 -7
- package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-inline-text.jsx +11 -0
- package/lib/runtime/components/react/dist/mpx-input.jsx +3 -6
- package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-picker/date.jsx +194 -68
- package/lib/runtime/components/react/dist/mpx-picker/dateData.js +17 -0
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +178 -96
- package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +79 -139
- package/lib/runtime/components/react/dist/mpx-picker/region.jsx +190 -90
- package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +60 -75
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +100 -228
- package/lib/runtime/components/react/dist/{mpx-picker-view.jsx → mpx-picker-view/index.jsx} +3 -3
- package/lib/runtime/components/react/dist/{mpx-picker-view-column.jsx → mpx-picker-view-column/index.jsx} +64 -16
- package/lib/runtime/components/react/dist/{mpx-picker-view-column-item.jsx → mpx-picker-view-column/pickerViewColumnItem.jsx} +8 -5
- package/lib/runtime/components/react/dist/{pickerFaces.js → mpx-picker-view-column/pickerViewFaces.js} +6 -0
- package/lib/runtime/components/react/dist/mpx-popup/index.jsx +61 -0
- package/lib/runtime/components/react/dist/mpx-popup/popupBase.jsx +92 -0
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +192 -25
- package/lib/runtime/components/react/dist/mpx-simple-text.jsx +8 -7
- package/lib/runtime/components/react/dist/mpx-simple-view.jsx +11 -15
- package/lib/runtime/components/react/dist/mpx-video.jsx +3 -3
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +7 -4
- package/lib/runtime/components/react/dist/utils.jsx +2 -1
- package/lib/runtime/components/react/event.config.ts +2 -0
- package/lib/runtime/components/react/getInnerListeners.ts +28 -25
- package/lib/runtime/components/react/mpx-canvas/index.tsx +2 -2
- package/lib/runtime/components/react/mpx-inline-text.tsx +18 -0
- package/lib/runtime/components/react/mpx-input.tsx +2 -6
- package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +1 -1
- package/lib/runtime/components/react/mpx-picker/date.tsx +226 -69
- package/lib/runtime/components/react/mpx-picker/dateData.ts +22 -0
- package/lib/runtime/components/react/mpx-picker/index.tsx +239 -118
- package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +96 -139
- package/lib/runtime/components/react/mpx-picker/region.tsx +217 -89
- package/lib/runtime/components/react/mpx-picker/selector.tsx +75 -80
- package/lib/runtime/components/react/mpx-picker/time.tsx +119 -236
- package/lib/runtime/components/react/mpx-picker/type.ts +85 -71
- package/lib/runtime/components/react/{mpx-picker-view.tsx → mpx-picker-view/index.tsx} +7 -7
- package/lib/runtime/components/react/{mpx-picker-view-column.tsx → mpx-picker-view-column/index.tsx} +70 -19
- package/lib/runtime/components/react/{mpx-picker-view-column-item.tsx → mpx-picker-view-column/pickerViewColumnItem.tsx} +8 -5
- package/lib/runtime/components/react/{pickerFaces.ts → mpx-picker-view-column/pickerViewFaces.ts} +7 -0
- package/lib/runtime/components/react/mpx-popup/index.tsx +86 -0
- package/lib/runtime/components/react/mpx-popup/popupBase.tsx +130 -0
- package/lib/runtime/components/react/mpx-scroll-view.tsx +249 -43
- package/lib/runtime/components/react/mpx-simple-text.tsx +10 -8
- package/lib/runtime/components/react/mpx-simple-view.tsx +11 -16
- package/lib/runtime/components/react/mpx-video.tsx +2 -2
- package/lib/runtime/components/react/mpx-web-view.tsx +7 -4
- package/lib/runtime/components/react/types/getInnerListeners.d.ts +5 -1
- package/lib/runtime/components/react/types/global.d.ts +1 -1
- package/lib/runtime/components/react/utils.tsx +3 -2
- package/lib/runtime/components/web/mini-video-controls.min.js +1 -1
- package/lib/runtime/components/web/mpx-input.vue +1 -1
- package/lib/runtime/stringify.wxs +2 -2
- package/lib/template-compiler/compiler.js +8 -8
- package/lib/utils/env.js +1 -1
- package/package.json +4 -5
- /package/lib/runtime/components/react/dist/{pickerVIewContext.js → mpx-picker-view/pickerVIewContext.js} +0 -0
- /package/lib/runtime/components/react/dist/{pickerViewIndicator.jsx → mpx-picker-view-column/pickerViewIndicator.jsx} +0 -0
- /package/lib/runtime/components/react/dist/{pickerViewMask.jsx → mpx-picker-view-column/pickerViewMask.jsx} +0 -0
- /package/lib/runtime/components/react/{pickerVIewContext.ts → mpx-picker-view/pickerVIewContext.ts} +0 -0
- /package/lib/runtime/components/react/{pickerViewIndicator.tsx → mpx-picker-view-column/pickerViewIndicator.tsx} +0 -0
- /package/lib/runtime/components/react/{pickerViewMask.tsx → mpx-picker-view-column/pickerViewMask.tsx} +0 -0
package/lib/runtime/components/react/{mpx-picker-view-column.tsx → mpx-picker-view-column/index.tsx}
RENAMED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import React, { forwardRef, useRef, useState, useMemo, useEffect, useCallback } from 'react'
|
|
2
|
-
import { LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent, ScrollView, StyleSheet, View } from 'react-native'
|
|
2
|
+
import { GestureResponderEvent, LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent, ScrollView, StyleSheet, View } from 'react-native'
|
|
3
3
|
import Reanimated, { AnimatedRef, useAnimatedRef, useScrollViewOffset } from 'react-native-reanimated'
|
|
4
|
-
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, isIOS } from '
|
|
5
|
-
import useNodesRef, { HandlerRef } from '
|
|
4
|
+
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, isIOS } from '../utils'
|
|
5
|
+
import useNodesRef, { HandlerRef } from '../useNodesRef'
|
|
6
6
|
import PickerIndicator from './pickerViewIndicator'
|
|
7
7
|
import PickerMask from './pickerViewMask'
|
|
8
|
-
import MpxPickerVIewColumnItem from './
|
|
9
|
-
import { PickerViewColumnAnimationContext } from '
|
|
8
|
+
import MpxPickerVIewColumnItem from './pickerViewColumnItem'
|
|
9
|
+
import { PickerViewColumnAnimationContext } from '../mpx-picker-view/pickerVIewContext'
|
|
10
|
+
import { calcHeightOffsets } from './pickerViewFaces'
|
|
10
11
|
|
|
11
12
|
interface ColumnProps {
|
|
12
|
-
|
|
13
|
+
columnIndex: number
|
|
13
14
|
columnData: React.ReactNode[]
|
|
14
15
|
initialIndex: number
|
|
15
16
|
onSelectChange: Function
|
|
16
17
|
style: {
|
|
17
18
|
[key: string]: any
|
|
18
19
|
}
|
|
19
|
-
'enable-var'
|
|
20
|
+
'enable-var'?: boolean
|
|
20
21
|
'external-var-context'?: Record<string, any>
|
|
21
22
|
wrapperStyle: {
|
|
22
23
|
height: number
|
|
@@ -24,7 +25,6 @@ interface ColumnProps {
|
|
|
24
25
|
}
|
|
25
26
|
pickerMaskStyle: Record<string, any>
|
|
26
27
|
pickerIndicatorStyle: Record<string, any>
|
|
27
|
-
columnIndex: number
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
const visibleCount = 5
|
|
@@ -62,10 +62,11 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
|
|
|
62
62
|
const [itemRawH, setItemRawH] = useState(itemHeight)
|
|
63
63
|
const maxIndex = useMemo(() => columnData.length - 1, [columnData])
|
|
64
64
|
const prevScrollingInfo = useRef({ index: initialIndex, y: 0 })
|
|
65
|
-
const
|
|
65
|
+
const dragging = useRef(false)
|
|
66
66
|
const scrolling = useRef(false)
|
|
67
67
|
const timerResetPosition = useRef<NodeJS.Timeout | null>(null)
|
|
68
68
|
const timerScrollTo = useRef<NodeJS.Timeout | null>(null)
|
|
69
|
+
const timerClickOnce = useRef<NodeJS.Timeout | null>(null)
|
|
69
70
|
const activeIndex = useRef(initialIndex)
|
|
70
71
|
const prevIndex = usePrevious(initialIndex)
|
|
71
72
|
const prevMaxIndex = usePrevious(maxIndex)
|
|
@@ -113,6 +114,13 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
|
|
|
113
114
|
}
|
|
114
115
|
}, [])
|
|
115
116
|
|
|
117
|
+
const clearTimerClickOnce = useCallback(() => {
|
|
118
|
+
if (timerClickOnce.current) {
|
|
119
|
+
clearTimeout(timerClickOnce.current)
|
|
120
|
+
timerClickOnce.current = null
|
|
121
|
+
}
|
|
122
|
+
}, [])
|
|
123
|
+
|
|
116
124
|
useEffect(() => {
|
|
117
125
|
return () => {
|
|
118
126
|
clearTimerResetPosition()
|
|
@@ -124,7 +132,7 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
|
|
|
124
132
|
if (
|
|
125
133
|
!scrollViewRef.current ||
|
|
126
134
|
!itemRawH ||
|
|
127
|
-
|
|
135
|
+
dragging.current ||
|
|
128
136
|
scrolling.current ||
|
|
129
137
|
prevIndex == null ||
|
|
130
138
|
initialIndex === prevIndex ||
|
|
@@ -140,8 +148,8 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
|
|
|
140
148
|
y: initialIndex * itemRawH,
|
|
141
149
|
animated: false
|
|
142
150
|
})
|
|
143
|
-
|
|
144
|
-
|
|
151
|
+
activeIndex.current = initialIndex
|
|
152
|
+
}, isIOS ? 0 : 200)
|
|
145
153
|
}, [itemRawH, maxIndex, initialIndex])
|
|
146
154
|
|
|
147
155
|
const onContentSizeChange = useCallback((_w: number, h: number) => {
|
|
@@ -150,6 +158,7 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
|
|
|
150
158
|
clearTimerScrollTo()
|
|
151
159
|
timerScrollTo.current = setTimeout(() => {
|
|
152
160
|
scrollViewRef.current?.scrollTo({ x: 0, y, animated: false })
|
|
161
|
+
activeIndex.current = initialIndex
|
|
153
162
|
}, 0)
|
|
154
163
|
}
|
|
155
164
|
}, [itemRawH, initialIndex])
|
|
@@ -163,7 +172,7 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
|
|
|
163
172
|
}, [itemRawH])
|
|
164
173
|
|
|
165
174
|
const resetScrollPosition = useCallback((y: number) => {
|
|
166
|
-
if (
|
|
175
|
+
if (dragging.current || scrolling.current) {
|
|
167
176
|
return
|
|
168
177
|
}
|
|
169
178
|
scrolling.current = true
|
|
@@ -191,7 +200,7 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
|
|
|
191
200
|
|
|
192
201
|
const onScrollBeginDrag = useCallback(() => {
|
|
193
202
|
isIOS && clearTimerResetPosition()
|
|
194
|
-
|
|
203
|
+
dragging.current = true
|
|
195
204
|
prevScrollingInfo.current = {
|
|
196
205
|
index: activeIndex.current,
|
|
197
206
|
y: activeIndex.current * itemRawH
|
|
@@ -199,7 +208,7 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
|
|
|
199
208
|
}, [itemRawH])
|
|
200
209
|
|
|
201
210
|
const onScrollEndDrag = useCallback((e: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
202
|
-
|
|
211
|
+
dragging.current = false
|
|
203
212
|
if (isIOS) {
|
|
204
213
|
const { y } = e.nativeEvent.contentOffset
|
|
205
214
|
if (y % itemRawH === 0) {
|
|
@@ -220,7 +229,7 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
|
|
|
220
229
|
}
|
|
221
230
|
const { y } = e.nativeEvent.contentOffset
|
|
222
231
|
const { index: prevIndex, y: _y } = prevScrollingInfo.current
|
|
223
|
-
if (
|
|
232
|
+
if (dragging.current || scrolling.current) {
|
|
224
233
|
if (Math.abs(y - _y) >= itemRawH) {
|
|
225
234
|
const currentId = getIndex(y)
|
|
226
235
|
if (currentId !== prevIndex) {
|
|
@@ -235,6 +244,47 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
|
|
|
235
244
|
}
|
|
236
245
|
}, [itemRawH, getIndex])
|
|
237
246
|
|
|
247
|
+
const offsetHeights = useMemo(() => calcHeightOffsets(itemRawH), [itemRawH])
|
|
248
|
+
|
|
249
|
+
const calcOffset = useCallback((y: number): number | false => {
|
|
250
|
+
const baselineY = activeIndex.current * itemRawH + pickerH / 2
|
|
251
|
+
const diff = Math.abs(y - baselineY)
|
|
252
|
+
const positive = y - baselineY > 0 ? 1 : -1
|
|
253
|
+
const [h1, h2, h3] = offsetHeights
|
|
254
|
+
if (diff > h1 && diff < h3) {
|
|
255
|
+
if (diff < h2) {
|
|
256
|
+
return 1 * positive
|
|
257
|
+
} else {
|
|
258
|
+
return 2 * positive
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return false
|
|
262
|
+
}, [offsetHeights])
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* 和小程序表现对齐,点击(不滑动)非焦点选项自动滚动到对应位置
|
|
266
|
+
*/
|
|
267
|
+
const onClickOnceItem = useCallback((e: GestureResponderEvent) => {
|
|
268
|
+
const { locationY } = e.nativeEvent || {}
|
|
269
|
+
const offsetIndex = calcOffset(locationY)
|
|
270
|
+
if (dragging.current || !offsetIndex) {
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
const targetIndex = activeIndex.current + offsetIndex
|
|
274
|
+
if (targetIndex < 0 || targetIndex > maxIndex) {
|
|
275
|
+
return
|
|
276
|
+
}
|
|
277
|
+
const y = targetIndex * itemRawH
|
|
278
|
+
scrollViewRef.current?.scrollTo({ x: 0, y, animated: true })
|
|
279
|
+
if (isAndroid) {
|
|
280
|
+
// Android scrollTo 不会自动触发 onMomentumScrollEnd,需要手动触发
|
|
281
|
+
clearTimerClickOnce()
|
|
282
|
+
timerClickOnce.current = setTimeout(() => {
|
|
283
|
+
onMomentumScrollEnd({ nativeEvent: { contentOffset: { y } } })
|
|
284
|
+
}, 250)
|
|
285
|
+
}
|
|
286
|
+
}, [itemRawH, maxIndex, calcOffset, onMomentumScrollEnd])
|
|
287
|
+
|
|
238
288
|
const renderInnerchild = () =>
|
|
239
289
|
columnData.map((item: React.ReactElement, index: number) => {
|
|
240
290
|
return (
|
|
@@ -264,6 +314,7 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
|
|
|
264
314
|
showsHorizontalScrollIndicator={false}
|
|
265
315
|
scrollEventThrottle={16}
|
|
266
316
|
{...layoutProps}
|
|
317
|
+
onTouchStart={onClickOnceItem}
|
|
267
318
|
style={[{ width: '100%' }]}
|
|
268
319
|
decelerationRate="fast"
|
|
269
320
|
snapToOffsets={snapToOffsets}
|
|
@@ -297,9 +348,9 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
|
|
|
297
348
|
|
|
298
349
|
return (
|
|
299
350
|
<View style={[styles.wrapper, normalStyle]}>
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
351
|
+
{renderScollView()}
|
|
352
|
+
{renderMask()}
|
|
353
|
+
{renderIndicator()}
|
|
303
354
|
</View>
|
|
304
355
|
)
|
|
305
356
|
})
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { useEffect } from 'react'
|
|
2
2
|
import { LayoutChangeEvent } from 'react-native'
|
|
3
3
|
import Reanimated, { Extrapolation, interpolate, useAnimatedStyle, useSharedValue } from 'react-native-reanimated'
|
|
4
|
-
import {
|
|
5
|
-
import { createFaces } from './
|
|
6
|
-
import { usePickerViewColumnAnimationContext, usePickerViewStyleContext } from '
|
|
4
|
+
import { extendObject } from '../utils'
|
|
5
|
+
import { createFaces } from './pickerViewFaces'
|
|
6
|
+
import { usePickerViewColumnAnimationContext, usePickerViewStyleContext } from '../mpx-picker-view/pickerVIewContext'
|
|
7
7
|
|
|
8
8
|
interface PickerColumnItemProps {
|
|
9
9
|
item: React.ReactElement
|
|
@@ -65,9 +65,12 @@ const PickerViewColumnItem: React.FC<PickerColumnItemProps> = ({
|
|
|
65
65
|
return (
|
|
66
66
|
<Reanimated.View
|
|
67
67
|
key={strKey}
|
|
68
|
-
style={[
|
|
68
|
+
style={[
|
|
69
|
+
{ height: itemHeight, width: itemWidth, pointerEvents: 'none' },
|
|
70
|
+
animatedStyles
|
|
71
|
+
]}
|
|
69
72
|
>
|
|
70
|
-
|
|
73
|
+
{realItem}
|
|
71
74
|
</Reanimated.View>
|
|
72
75
|
)
|
|
73
76
|
}
|
package/lib/runtime/components/react/{pickerFaces.ts → mpx-picker-view-column/pickerViewFaces.ts}
RENAMED
|
@@ -25,6 +25,13 @@ export const calcPickerHeight = (faces: Faces[], itemHeight: number) => {
|
|
|
25
25
|
return faces.reduce((r, v) => r + calcHeight(Math.abs(v.deg), itemHeight), 0)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
export const calcHeightOffsets = (itemHeight: number) => {
|
|
29
|
+
const h1 = itemHeight / 2
|
|
30
|
+
const h2 = h1 + calcHeight(30, itemHeight)
|
|
31
|
+
const h3 = h2 + calcHeight(60, itemHeight)
|
|
32
|
+
return [h1, h2, h3]
|
|
33
|
+
}
|
|
34
|
+
|
|
28
35
|
export const createFaces = (
|
|
29
36
|
itemHeight: number,
|
|
30
37
|
visibleCount: number
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { cloneElement, ReactElement } from 'react'
|
|
2
|
+
import Portal from '../mpx-portal'
|
|
3
|
+
import PopupBase, { PopupBaseProps } from './popupBase'
|
|
4
|
+
|
|
5
|
+
export const enum PopupType {
|
|
6
|
+
PICKER = 'picker',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface IUsePopupOptions {
|
|
10
|
+
modal?: React.ComponentType<PopupBaseProps>
|
|
11
|
+
type?: PopupType
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 根据 type 返回对应的弹窗壳子组件
|
|
16
|
+
*/
|
|
17
|
+
const getPopup = (type?: PopupType): React.ComponentType<PopupBaseProps> => {
|
|
18
|
+
switch (type) {
|
|
19
|
+
case PopupType.PICKER:
|
|
20
|
+
default:
|
|
21
|
+
return PopupBase
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 基于 Portal 封装的 Popup 弹窗组件管理 Hooks
|
|
27
|
+
*/
|
|
28
|
+
const createPopupManager = (options: IUsePopupOptions = {}) => {
|
|
29
|
+
const { modal, type } = options
|
|
30
|
+
const Modal = modal || getPopup(type)
|
|
31
|
+
|
|
32
|
+
let popupKey: number | null = null
|
|
33
|
+
let isOpen = false
|
|
34
|
+
let child: ReactElement | null = null
|
|
35
|
+
|
|
36
|
+
const remove = () => {
|
|
37
|
+
if (popupKey !== null) {
|
|
38
|
+
Portal.remove(popupKey)
|
|
39
|
+
popupKey = null
|
|
40
|
+
}
|
|
41
|
+
isOpen = false
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const open = (
|
|
45
|
+
childComponent: React.ReactNode,
|
|
46
|
+
pageId: number | undefined,
|
|
47
|
+
options?: { contentHeight?: number }
|
|
48
|
+
) => {
|
|
49
|
+
if (!isOpen && pageId != null) {
|
|
50
|
+
isOpen = true
|
|
51
|
+
child = (
|
|
52
|
+
<Modal hide={hide} {...options} visible={false}>
|
|
53
|
+
{childComponent}
|
|
54
|
+
</Modal>
|
|
55
|
+
)
|
|
56
|
+
popupKey = Portal.add(child, pageId)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const update = (updatedChild: ReactElement | null) => {
|
|
61
|
+
if (popupKey !== null && child !== null && updatedChild !== null) {
|
|
62
|
+
child = cloneElement(child, { children: updatedChild })
|
|
63
|
+
Portal.update(popupKey, child)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const _updateVisible = (visible: boolean) => {
|
|
68
|
+
if (popupKey !== null && child !== null) {
|
|
69
|
+
child = cloneElement(child, { visible })
|
|
70
|
+
Portal.update(popupKey, child)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const show = () => _updateVisible(true)
|
|
75
|
+
const hide = () => _updateVisible(false)
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
open,
|
|
79
|
+
show,
|
|
80
|
+
hide,
|
|
81
|
+
update,
|
|
82
|
+
remove
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { createPopupManager }
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native'
|
|
2
|
+
import Animated, {
|
|
3
|
+
useSharedValue,
|
|
4
|
+
useAnimatedStyle,
|
|
5
|
+
withTiming,
|
|
6
|
+
Easing
|
|
7
|
+
} from 'react-native-reanimated'
|
|
8
|
+
import { getWindowInfo } from '@mpxjs/api-proxy'
|
|
9
|
+
import { useUpdateEffect } from '../utils'
|
|
10
|
+
|
|
11
|
+
export interface PopupBaseProps {
|
|
12
|
+
children?: React.ReactNode
|
|
13
|
+
hide?: () => void
|
|
14
|
+
contentHeight?: number
|
|
15
|
+
visible?: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const windowInfo = getWindowInfo()
|
|
19
|
+
const bottom = windowInfo.screenHeight - windowInfo.safeArea.bottom
|
|
20
|
+
const styles = StyleSheet.create({
|
|
21
|
+
mask: {
|
|
22
|
+
left: 0,
|
|
23
|
+
top: 0,
|
|
24
|
+
bottom: 0,
|
|
25
|
+
right: 0,
|
|
26
|
+
backgroundColor: 'rgba(0,0,0,0.6)',
|
|
27
|
+
position: 'absolute',
|
|
28
|
+
zIndex: 1000
|
|
29
|
+
},
|
|
30
|
+
content: {
|
|
31
|
+
backgroundColor: '#ffffff',
|
|
32
|
+
borderTopLeftRadius: 10,
|
|
33
|
+
borderTopRightRadius: 10,
|
|
34
|
+
position: 'absolute',
|
|
35
|
+
bottom: 0,
|
|
36
|
+
left: 0,
|
|
37
|
+
right: 0,
|
|
38
|
+
paddingBottom: bottom
|
|
39
|
+
},
|
|
40
|
+
buttonStyle: {
|
|
41
|
+
fontSize: 18,
|
|
42
|
+
paddingTop: 10,
|
|
43
|
+
paddingBottom: 10
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const MASK_ON = 1 as const
|
|
48
|
+
const MASK_OFF = 0 as const
|
|
49
|
+
const MOVEOUT_HEIGHT = 330 as const
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 类似微信 picker 弹窗的动画效果都可以复用此类容器
|
|
53
|
+
* 其他特定类型的弹窗容器组件可以在此基础上封装,或者扩展实现
|
|
54
|
+
*/
|
|
55
|
+
const PopupBase = (props: PopupBaseProps = {}) => {
|
|
56
|
+
const {
|
|
57
|
+
children,
|
|
58
|
+
hide = () => null,
|
|
59
|
+
contentHeight = MOVEOUT_HEIGHT,
|
|
60
|
+
visible = false
|
|
61
|
+
} = props
|
|
62
|
+
const fade = useSharedValue<number>(MASK_OFF)
|
|
63
|
+
const slide = useSharedValue<number>(contentHeight)
|
|
64
|
+
|
|
65
|
+
const animatedStylesMask = useAnimatedStyle(() => ({
|
|
66
|
+
opacity: fade.value
|
|
67
|
+
}))
|
|
68
|
+
|
|
69
|
+
const animatedStylesContent = useAnimatedStyle(() => ({
|
|
70
|
+
transform: [{ translateY: slide.value }]
|
|
71
|
+
}))
|
|
72
|
+
|
|
73
|
+
const showAimation = () => {
|
|
74
|
+
fade.value = withTiming(MASK_ON, {
|
|
75
|
+
easing: Easing.inOut(Easing.poly(3)),
|
|
76
|
+
duration: 300
|
|
77
|
+
})
|
|
78
|
+
slide.value = withTiming(0, {
|
|
79
|
+
easing: Easing.out(Easing.poly(3)),
|
|
80
|
+
duration: 300
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const hideAnimation = () => {
|
|
85
|
+
fade.value = withTiming(MASK_OFF, {
|
|
86
|
+
easing: Easing.inOut(Easing.poly(3)),
|
|
87
|
+
duration: 300
|
|
88
|
+
})
|
|
89
|
+
slide.value = withTiming(
|
|
90
|
+
contentHeight,
|
|
91
|
+
{
|
|
92
|
+
easing: Easing.inOut(Easing.poly(3)),
|
|
93
|
+
duration: 300
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
useUpdateEffect(() => {
|
|
99
|
+
if (visible) {
|
|
100
|
+
showAimation()
|
|
101
|
+
} else {
|
|
102
|
+
hideAnimation()
|
|
103
|
+
}
|
|
104
|
+
}, [visible])
|
|
105
|
+
|
|
106
|
+
const preventMaskClick = (e: any) => {
|
|
107
|
+
e.stopPropagation()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<Animated.View
|
|
112
|
+
onTouchEnd={hide}
|
|
113
|
+
style={[
|
|
114
|
+
styles.mask,
|
|
115
|
+
animatedStylesMask,
|
|
116
|
+
{ pointerEvents: visible ? 'auto' : 'none' }
|
|
117
|
+
]}
|
|
118
|
+
>
|
|
119
|
+
<Animated.View
|
|
120
|
+
style={[styles.content, animatedStylesContent]}
|
|
121
|
+
onTouchEnd={preventMaskClick}
|
|
122
|
+
>
|
|
123
|
+
{children}
|
|
124
|
+
</Animated.View>
|
|
125
|
+
</Animated.View>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
PopupBase.displayName = 'MpxPopupBase'
|
|
130
|
+
export default PopupBase
|