@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.
Files changed (103) hide show
  1. package/lib/config.js +2 -1
  2. package/lib/index.js +1 -1
  3. package/lib/platform/json/wx/index.js +6 -3
  4. package/lib/platform/style/wx/index.js +23 -12
  5. package/lib/platform/template/wx/component-config/button.js +19 -2
  6. package/lib/platform/template/wx/component-config/canvas.js +4 -0
  7. package/lib/platform/template/wx/component-config/checkbox-group.js +4 -0
  8. package/lib/platform/template/wx/component-config/checkbox.js +4 -0
  9. package/lib/platform/template/wx/component-config/cover-image.js +7 -1
  10. package/lib/platform/template/wx/component-config/cover-view.js +4 -0
  11. package/lib/platform/template/wx/component-config/fix-component-name.js +3 -2
  12. package/lib/platform/template/wx/component-config/form.js +7 -1
  13. package/lib/platform/template/wx/component-config/icon.js +4 -0
  14. package/lib/platform/template/wx/component-config/image.js +7 -1
  15. package/lib/platform/template/wx/component-config/input.js +18 -3
  16. package/lib/platform/template/wx/component-config/label.js +4 -0
  17. package/lib/platform/template/wx/component-config/movable-area.js +7 -1
  18. package/lib/platform/template/wx/component-config/movable-view.js +12 -3
  19. package/lib/platform/template/wx/component-config/navigator.js +4 -0
  20. package/lib/platform/template/wx/component-config/picker-view-column.js +4 -0
  21. package/lib/platform/template/wx/component-config/picker-view.js +7 -1
  22. package/lib/platform/template/wx/component-config/picker.js +7 -1
  23. package/lib/platform/template/wx/component-config/radio-group.js +4 -0
  24. package/lib/platform/template/wx/component-config/radio.js +4 -0
  25. package/lib/platform/template/wx/component-config/rich-text.js +4 -0
  26. package/lib/platform/template/wx/component-config/root-portal.js +4 -0
  27. package/lib/platform/template/wx/component-config/scroll-view.js +10 -2
  28. package/lib/platform/template/wx/component-config/swiper-item.js +7 -1
  29. package/lib/platform/template/wx/component-config/swiper.js +12 -3
  30. package/lib/platform/template/wx/component-config/switch.js +4 -0
  31. package/lib/platform/template/wx/component-config/text.js +24 -3
  32. package/lib/platform/template/wx/component-config/textarea.js +17 -2
  33. package/lib/platform/template/wx/component-config/unsupported.js +7 -0
  34. package/lib/platform/template/wx/component-config/video.js +10 -2
  35. package/lib/platform/template/wx/component-config/view.js +11 -1
  36. package/lib/platform/template/wx/component-config/web-view.js +4 -0
  37. package/lib/platform/template/wx/index.js +42 -75
  38. package/lib/react/processScript.js +1 -18
  39. package/lib/runtime/components/react/dist/event.config.js +1 -0
  40. package/lib/runtime/components/react/dist/getInnerListeners.js +18 -7
  41. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +1 -1
  42. package/lib/runtime/components/react/dist/mpx-inline-text.jsx +11 -0
  43. package/lib/runtime/components/react/dist/mpx-input.jsx +3 -6
  44. package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +2 -2
  45. package/lib/runtime/components/react/dist/mpx-picker/date.jsx +194 -68
  46. package/lib/runtime/components/react/dist/mpx-picker/dateData.js +17 -0
  47. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +178 -96
  48. package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +79 -139
  49. package/lib/runtime/components/react/dist/mpx-picker/region.jsx +190 -90
  50. package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +60 -75
  51. package/lib/runtime/components/react/dist/mpx-picker/time.jsx +100 -228
  52. package/lib/runtime/components/react/dist/{mpx-picker-view.jsx → mpx-picker-view/index.jsx} +3 -3
  53. package/lib/runtime/components/react/dist/{mpx-picker-view-column.jsx → mpx-picker-view-column/index.jsx} +64 -16
  54. package/lib/runtime/components/react/dist/{mpx-picker-view-column-item.jsx → mpx-picker-view-column/pickerViewColumnItem.jsx} +8 -5
  55. package/lib/runtime/components/react/dist/{pickerFaces.js → mpx-picker-view-column/pickerViewFaces.js} +6 -0
  56. package/lib/runtime/components/react/dist/mpx-popup/index.jsx +61 -0
  57. package/lib/runtime/components/react/dist/mpx-popup/popupBase.jsx +92 -0
  58. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +192 -25
  59. package/lib/runtime/components/react/dist/mpx-simple-text.jsx +8 -7
  60. package/lib/runtime/components/react/dist/mpx-simple-view.jsx +11 -15
  61. package/lib/runtime/components/react/dist/mpx-video.jsx +3 -3
  62. package/lib/runtime/components/react/dist/mpx-web-view.jsx +7 -4
  63. package/lib/runtime/components/react/dist/utils.jsx +2 -1
  64. package/lib/runtime/components/react/event.config.ts +2 -0
  65. package/lib/runtime/components/react/getInnerListeners.ts +28 -25
  66. package/lib/runtime/components/react/mpx-canvas/index.tsx +2 -2
  67. package/lib/runtime/components/react/mpx-inline-text.tsx +18 -0
  68. package/lib/runtime/components/react/mpx-input.tsx +2 -6
  69. package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +1 -1
  70. package/lib/runtime/components/react/mpx-picker/date.tsx +226 -69
  71. package/lib/runtime/components/react/mpx-picker/dateData.ts +22 -0
  72. package/lib/runtime/components/react/mpx-picker/index.tsx +239 -118
  73. package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +96 -139
  74. package/lib/runtime/components/react/mpx-picker/region.tsx +217 -89
  75. package/lib/runtime/components/react/mpx-picker/selector.tsx +75 -80
  76. package/lib/runtime/components/react/mpx-picker/time.tsx +119 -236
  77. package/lib/runtime/components/react/mpx-picker/type.ts +85 -71
  78. package/lib/runtime/components/react/{mpx-picker-view.tsx → mpx-picker-view/index.tsx} +7 -7
  79. package/lib/runtime/components/react/{mpx-picker-view-column.tsx → mpx-picker-view-column/index.tsx} +70 -19
  80. package/lib/runtime/components/react/{mpx-picker-view-column-item.tsx → mpx-picker-view-column/pickerViewColumnItem.tsx} +8 -5
  81. package/lib/runtime/components/react/{pickerFaces.ts → mpx-picker-view-column/pickerViewFaces.ts} +7 -0
  82. package/lib/runtime/components/react/mpx-popup/index.tsx +86 -0
  83. package/lib/runtime/components/react/mpx-popup/popupBase.tsx +130 -0
  84. package/lib/runtime/components/react/mpx-scroll-view.tsx +249 -43
  85. package/lib/runtime/components/react/mpx-simple-text.tsx +10 -8
  86. package/lib/runtime/components/react/mpx-simple-view.tsx +11 -16
  87. package/lib/runtime/components/react/mpx-video.tsx +2 -2
  88. package/lib/runtime/components/react/mpx-web-view.tsx +7 -4
  89. package/lib/runtime/components/react/types/getInnerListeners.d.ts +5 -1
  90. package/lib/runtime/components/react/types/global.d.ts +1 -1
  91. package/lib/runtime/components/react/utils.tsx +3 -2
  92. package/lib/runtime/components/web/mini-video-controls.min.js +1 -1
  93. package/lib/runtime/components/web/mpx-input.vue +1 -1
  94. package/lib/runtime/stringify.wxs +2 -2
  95. package/lib/template-compiler/compiler.js +8 -8
  96. package/lib/utils/env.js +1 -1
  97. package/package.json +4 -5
  98. /package/lib/runtime/components/react/dist/{pickerVIewContext.js → mpx-picker-view/pickerVIewContext.js} +0 -0
  99. /package/lib/runtime/components/react/dist/{pickerViewIndicator.jsx → mpx-picker-view-column/pickerViewIndicator.jsx} +0 -0
  100. /package/lib/runtime/components/react/dist/{pickerViewMask.jsx → mpx-picker-view-column/pickerViewMask.jsx} +0 -0
  101. /package/lib/runtime/components/react/{pickerVIewContext.ts → mpx-picker-view/pickerVIewContext.ts} +0 -0
  102. /package/lib/runtime/components/react/{pickerViewIndicator.tsx → mpx-picker-view-column/pickerViewIndicator.tsx} +0 -0
  103. /package/lib/runtime/components/react/{pickerViewMask.tsx → mpx-picker-view-column/pickerViewMask.tsx} +0 -0
@@ -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 './utils'
5
- import useNodesRef, { HandlerRef } from './useNodesRef'
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 './mpx-picker-view-column-item'
9
- import { PickerViewColumnAnimationContext } from './pickerVIewContext'
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
- children?: React.ReactNode
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': boolean
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 touching = useRef(false)
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
- touching.current ||
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
- }, isAndroid ? 200 : 0)
144
- activeIndex.current = initialIndex
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 (touching.current || scrolling.current) {
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
- touching.current = true
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
- touching.current = false
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 (touching.current || scrolling.current) {
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
- {renderScollView()}
301
- {renderMask()}
302
- {renderIndicator()}
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 { wrapChildren, extendObject } from './utils'
5
- import { createFaces } from './pickerFaces'
6
- import { usePickerViewColumnAnimationContext, usePickerViewStyleContext } from './pickerVIewContext'
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={[{ height: itemHeight, width: itemWidth }, animatedStyles]}
68
+ style={[
69
+ { height: itemHeight, width: itemWidth, pointerEvents: 'none' },
70
+ animatedStyles
71
+ ]}
69
72
  >
70
- {realItem}
73
+ {realItem}
71
74
  </Reanimated.View>
72
75
  )
73
76
  }
@@ -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