@mpxjs/webpack-plugin 2.9.69-beta.2 → 2.9.69-beta.3

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 (35) hide show
  1. package/lib/index.js +1 -17
  2. package/lib/platform/style/wx/index.js +18 -18
  3. package/lib/platform/template/wx/component-config/movable-view.js +1 -8
  4. package/lib/platform/template/wx/component-config/scroll-view.js +1 -1
  5. package/lib/resolver/AddEnvPlugin.js +0 -1
  6. package/lib/resolver/AddModePlugin.js +0 -1
  7. package/lib/runtime/components/react/context.ts +0 -8
  8. package/lib/runtime/components/react/getInnerListeners.ts +5 -3
  9. package/lib/runtime/components/react/mpx-input.tsx +1 -1
  10. package/lib/runtime/components/react/mpx-movable-view.tsx +1 -1
  11. package/lib/runtime/components/react/mpx-picker-view-column.tsx +159 -177
  12. package/lib/runtime/components/react/mpx-picker-view.tsx +37 -35
  13. package/lib/runtime/components/react/mpx-rich-text/index.tsx +18 -12
  14. package/lib/runtime/components/react/mpx-scroll-view.tsx +13 -30
  15. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +527 -0
  16. package/lib/runtime/components/react/mpx-swiper/index.tsx +80 -0
  17. package/lib/runtime/components/react/mpx-swiper/type.ts +87 -0
  18. package/lib/runtime/components/react/mpx-swiper-item.tsx +10 -38
  19. package/lib/runtime/components/react/mpx-view.tsx +51 -11
  20. package/lib/runtime/components/react/mpx-web-view.tsx +13 -57
  21. package/lib/runtime/components/react/pickerFaces.ts +7 -15
  22. package/lib/runtime/components/react/{pickerViewOverlay.tsx → pickerOverlay.tsx} +3 -5
  23. package/lib/runtime/components/react/types/global.d.ts +1 -3
  24. package/lib/runtime/components/react/useAnimationHooks.ts +1 -1
  25. package/lib/runtime/components/react/utils.tsx +5 -75
  26. package/lib/style-compiler/index.js +4 -3
  27. package/lib/template-compiler/compiler.js +14 -9
  28. package/lib/utils/hump-dash.js +1 -1
  29. package/lib/utils/pre-process-json.js +9 -5
  30. package/package.json +1 -1
  31. package/lib/runtime/components/react/mpx-picker-view-column-item.tsx +0 -88
  32. package/lib/runtime/components/react/mpx-swiper.tsx +0 -690
  33. package/lib/runtime/components/react/pickerVIewContext.ts +0 -18
  34. package/lib/runtime/components/react/pickerViewMask.tsx +0 -30
  35. package/lib/style-compiler/strip-conditional-loader.js +0 -118
package/lib/index.js CHANGED
@@ -54,13 +54,11 @@ const wxssLoaderPath = normalize.lib('wxss/index')
54
54
  const wxmlLoaderPath = normalize.lib('wxml/loader')
55
55
  const wxsLoaderPath = normalize.lib('wxs/loader')
56
56
  const styleCompilerPath = normalize.lib('style-compiler/index')
57
- const styleStripConditaionalPath = normalize.lib('style-compiler/strip-conditional-loader')
58
57
  const templateCompilerPath = normalize.lib('template-compiler/index')
59
58
  const jsonCompilerPath = normalize.lib('json-compiler/index')
60
59
  const jsonThemeCompilerPath = normalize.lib('json-compiler/theme')
61
60
  const jsonPluginCompilerPath = normalize.lib('json-compiler/plugin')
62
61
  const extractorPath = normalize.lib('extractor')
63
- const selectorPath = normalize.lib('selector')
64
62
  const async = require('async')
65
63
  const { parseQuery } = require('loader-utils')
66
64
  const stringifyLoadersAndResource = require('./utils/stringify-loaders-resource')
@@ -1777,7 +1775,7 @@ try {
1777
1775
  })
1778
1776
 
1779
1777
  const typeLoaderProcessInfo = {
1780
- styles: ['node_modules/css-loader', wxssLoaderPath, styleCompilerPath, styleStripConditaionalPath],
1778
+ styles: ['node_modules/css-loader', wxssLoaderPath, styleCompilerPath],
1781
1779
  template: ['node_modules/html-loader', wxmlLoaderPath, templateCompilerPath]
1782
1780
  }
1783
1781
 
@@ -1835,20 +1833,6 @@ try {
1835
1833
  loader: extractorPath
1836
1834
  })
1837
1835
  }
1838
- if (type === 'styles') {
1839
- // 判断最后一个loader是否是 selectorPath, 如果是,则在sectorPath之前插入strip-conditional
1840
- const lastLoader = loaders[loaders.length - 1]
1841
- if (lastLoader.loader.includes(selectorPath)) {
1842
- loaders.splice(loaders.length - 1, 0, {
1843
- loader: styleStripConditaionalPath
1844
- })
1845
- } else {
1846
- // 在最后一个插入strip-conditional
1847
- loaders.push({
1848
- loader: styleStripConditaionalPath
1849
- })
1850
- }
1851
- }
1852
1836
  createData.resource = addQuery(createData.resource, { mpx: MPX_PROCESSED_FLAG }, true)
1853
1837
  }
1854
1838
  // mpxStyleOptions 为 mpx style 文件的标识,避免 Vue 文件插入 styleCompiler 后导致 vue scoped 样式隔离失效
@@ -374,11 +374,11 @@ module.exports = function getSpec ({ warn, error }) {
374
374
  // transform 转换
375
375
  const formatTransform = ({ prop, value, selector }, { mode }) => {
376
376
  // css var & 数组直接返回
377
- if (Array.isArray(value) || cssVariableExp.test(value)) return { prop, value }
377
+ if (Array.isArray(value) || calcExp.test(value)) return { prop, value }
378
378
  const values = parseValues(value)
379
379
  const transform = []
380
380
  values.forEach(item => {
381
- const match = item.match(/([/\w]+)\((.+)\)/)
381
+ const match = item.match(/([/\w]+)\(([^)]+)\)/)
382
382
  if (match && match.length >= 3) {
383
383
  let key = match[1]
384
384
  const val = match[2]
@@ -407,23 +407,23 @@ module.exports = function getSpec ({ warn, error }) {
407
407
  case 'rotate3d': // x y z angle
408
408
  case 'translate3d': // x y 支持 z不支持
409
409
  case 'scale3d': // x y 支持 z不支持
410
- {
411
- // 2 个以上的值处理
412
- key = key.replace('3d', '')
413
- const vals = parseValues(val, ',').splice(0, key === 'rotate' ? 4 : 3)
414
- // scale(.5) === scaleX(.5) scaleY(.5)
415
- if (vals.length === 1 && key === 'scale') {
416
- vals.push(vals[0])
417
- }
418
- const xyz = ['X', 'Y', 'Z']
419
- transform.push(...vals.map((v, index) => {
420
- if (key !== 'rotate' && index > 1) {
421
- unsupportedPropError({ prop: `${key}Z`, value, selector }, { mode })
410
+ {
411
+ // 2 个以上的值处理
412
+ key = key.replace('3d', '')
413
+ const vals = parseValues(val, ',').splice(0, key === 'rotate' ? 4 : 3)
414
+ // scale(.5) === scaleX(.5) scaleY(.5)
415
+ if (vals.length === 1 && key === 'scale') {
416
+ vals.push(vals[0])
422
417
  }
423
- return { [`${key}${xyz[index] || ''}`]: v.trim() }
424
- }))
425
- break
426
- }
418
+ const xyz = ['X', 'Y', 'Z']
419
+ transform.push(...vals.map((v, index) => {
420
+ if (key !== 'rotate' && index > 1) {
421
+ unsupportedPropError({ prop: `${key}Z`, value, selector }, { mode })
422
+ }
423
+ return { [`${key}${xyz[index] || ''}`]: v.trim() }
424
+ }))
425
+ break
426
+ }
427
427
  case 'translateZ':
428
428
  case 'scaleZ':
429
429
  default:
@@ -2,8 +2,6 @@ const TAG_NAME = 'movable-view'
2
2
 
3
3
  module.exports = function ({ print }) {
4
4
  const aliEventLog = print({ platform: 'ali', tag: TAG_NAME, isError: false, type: 'event' })
5
- const androidEventLog = print({ platform: 'android', tag: TAG_NAME, isError: false, type: 'event' })
6
- const iosEventLog = print({ platform: 'ios', tag: TAG_NAME, isError: false, type: 'event' })
7
5
  const qaPropLog = print({ platform: 'qa', tag: TAG_NAME, isError: false })
8
6
  const androidPropLog = print({ platform: 'android', tag: TAG_NAME, isError: false })
9
7
  const iosPropLog = print({ platform: 'ios', tag: TAG_NAME, isError: false })
@@ -29,7 +27,7 @@ module.exports = function ({ print }) {
29
27
  android: androidPropLog
30
28
  },
31
29
  {
32
- test: /^(damping|friction|scale|scale-min|scale-max|scale-value)$/,
30
+ test: /^(inertia|damping|animation)$/,
33
31
  ios: iosPropLog,
34
32
  android: androidPropLog
35
33
  }
@@ -38,11 +36,6 @@ module.exports = function ({ print }) {
38
36
  {
39
37
  test: /^(htouchmove|vtouchmove)$/,
40
38
  ali: aliEventLog
41
- },
42
- {
43
- test: /^(bindscale)$/,
44
- ios: iosEventLog,
45
- android: androidEventLog
46
39
  }
47
40
  ]
48
41
  }
@@ -53,7 +53,7 @@ module.exports = function ({ print }) {
53
53
  qa: qaPropLog
54
54
  },
55
55
  {
56
- test: /^(refresher-threshold|enable-passive|scroll-anchoring|using-sticky|fast-deceleration|enable-flex)$/,
56
+ test: /^(scroll-into-view|refresher-threshold|enable-passive|scroll-anchoring|using-sticky|fast-deceleration|enable-flex)$/,
57
57
  android: androidPropLog,
58
58
  ios: iosPropLog
59
59
  },
@@ -34,7 +34,6 @@ module.exports = class AddEnvPlugin {
34
34
  if (!extname || !matchCondition(resourcePath, this.fileConditionRules)) return callback()
35
35
  const queryObj = parseQuery(request.query || '?')
36
36
  queryObj.infix = `${queryObj.infix || ''}.${env}`
37
- // css | stylus | less | sass 中 import file 过滤query,避免在对应的 loader 中无法读取到文件
38
37
  obj.query = stringifyQuery(queryObj)
39
38
  obj.path = addInfix(resourcePath, env, extname)
40
39
  obj.relativePath = request.relativePath && addInfix(request.relativePath, env, extname)
@@ -43,7 +43,6 @@ module.exports = class AddModePlugin {
43
43
  resolver.doResolve(target, Object.assign({}, request, obj), 'add mode: ' + mode, resolveContext, (err, result) => {
44
44
  if (defaultMode && !result) {
45
45
  queryObj.infix = `${queryInfix || ''}.${defaultMode}`
46
- // css | stylus | less | sass 中 import file 过滤query,避免在对应的 loader 中无法读取到文件
47
46
  obj.query = stringifyQuery(queryObj)
48
47
  obj.path = addInfix(resourcePath, defaultMode, extname)
49
48
  resolver.doResolve(target, Object.assign({}, request, obj), 'add mode: ' + defaultMode, resolveContext, (err, result) => {
@@ -33,10 +33,6 @@ export interface IntersectionObserver {
33
33
  }
34
34
  }
35
35
 
36
- export interface ScrollViewContextValue {
37
- gestureRef: React.RefObject<any> | null
38
- }
39
-
40
36
  export const MovableAreaContext = createContext({ width: 0, height: 0 })
41
37
 
42
38
  export const FormContext = createContext<FormContextValue | null>(null)
@@ -55,8 +51,4 @@ export const IntersectionObserverContext = createContext<IntersectionObserver |
55
51
 
56
52
  export const RouteContext = createContext<number | null>(null)
57
53
 
58
- export const SwiperContext = createContext({})
59
-
60
54
  export const KeyboardAvoidContext = createContext<KeyboardAvoidContextValue | null>(null)
61
-
62
- export const ScrollViewContext = createContext<ScrollViewContextValue>({ gestureRef: null })
@@ -289,6 +289,7 @@ const useInnerProps = (
289
289
  const eventConfig: { [key: string]: string[] } = {}
290
290
  const config = rawConfig || {
291
291
  layoutRef: { current: {} },
292
+ disableTouch: false,
292
293
  disableTap: false
293
294
  }
294
295
  const removeProps = [
@@ -316,10 +317,11 @@ const useInnerProps = (
316
317
  }
317
318
  }
318
319
 
320
+ if (!rawEventKeys.length || config.disableTouch) {
321
+ return omit(propsRef.current, removeProps)
322
+ }
323
+
319
324
  const events = useMemo(() => {
320
- if (!rawEventKeys.length) {
321
- return {}
322
- }
323
325
  const transformedEventKeys = rawEventKeys.reduce((acc: string[], key) => {
324
326
  if (propsRef.current[key]) {
325
327
  return acc.concat(eventConfig[key])
@@ -149,7 +149,7 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
149
149
  'parent-font-size': parentFontSize,
150
150
  'parent-width': parentWidth,
151
151
  'parent-height': parentHeight,
152
- 'adjust-position': adjustPosition = false,
152
+ 'adjust-position': adjustPosition = true,
153
153
  bindinput,
154
154
  bindfocus,
155
155
  bindblur,
@@ -11,7 +11,7 @@
11
11
  * ✘ scale-min
12
12
  * ✘ scale-max
13
13
  * ✘ scale-value
14
- * animation
14
+ * animation
15
15
  * ✔ bindchange
16
16
  * ✘ bindscale
17
17
  * ✔ htouchmove
@@ -1,18 +1,17 @@
1
- import React, { forwardRef, useRef, useState, useMemo, useEffect, useCallback } from 'react'
2
- import { LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent, SafeAreaView, ScrollView, StyleSheet, View } from 'react-native'
3
- import Reanimated, { AnimatedRef, useAnimatedRef, useScrollViewOffset } from 'react-native-reanimated'
4
- import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, useDebounceCallback, useStableCallback, isIOS } from './utils'
1
+
2
+ import { View, Animated, SafeAreaView, NativeScrollEvent, NativeSyntheticEvent, LayoutChangeEvent, ScrollView } from 'react-native'
3
+ import React, { forwardRef, useRef, useState, useMemo, useCallback, useEffect } from 'react'
4
+ import { useTransformStyle, splitStyle, splitProps, wrapChildren, useLayout, usePrevious } from './utils'
5
5
  import useNodesRef, { HandlerRef } from './useNodesRef'
6
- import PickerOverlay from './pickerViewOverlay'
7
- import PickerMask from './pickerViewMask'
8
- import MpxPickerVIewColumnItem from './mpx-picker-view-column-item'
9
- import { PickerViewColumnAnimationContext } from './pickerVIewContext'
6
+ import { createFaces } from './pickerFaces'
7
+ import PickerOverlay from './pickerOverlay'
10
8
 
11
9
  interface ColumnProps {
12
10
  children?: React.ReactNode
13
11
  columnData: React.ReactNode[]
14
- columnStyle: Record<string, any>
15
12
  initialIndex: number
13
+ onColumnItemRawHChange: Function
14
+ getInnerLayout: Function
16
15
  onSelectChange: Function
17
16
  style: {
18
17
  [key: string]: any
@@ -23,23 +22,25 @@ interface ColumnProps {
23
22
  height: number
24
23
  itemHeight: number
25
24
  }
26
- pickerMaskStyle: Record<string, any>
27
25
  pickerOverlayStyle: Record<string, any>
28
26
  columnIndex: number
29
27
  }
30
28
 
29
+ // 默认的单个选项高度
30
+ const DefaultPickerItemH = 36
31
+ // 默认一屏可见选项个数
31
32
  const visibleCount = 5
32
33
 
33
34
  const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>, ColumnProps>((props: ColumnProps, ref) => {
34
35
  const {
35
36
  columnData,
36
37
  columnIndex,
37
- columnStyle,
38
38
  initialIndex,
39
39
  onSelectChange,
40
+ onColumnItemRawHChange,
41
+ getInnerLayout,
40
42
  style,
41
43
  wrapperStyle,
42
- pickerMaskStyle,
43
44
  pickerOverlayStyle,
44
45
  'enable-var': enableVar,
45
46
  'external-var-context': externalVarContext
@@ -53,42 +54,27 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
53
54
  setWidth,
54
55
  setHeight
55
56
  } = useTransformStyle(style, { enableVar, externalVarContext })
56
- const { textStyle: textStyleFromParent = {} } = splitStyle(columnStyle)
57
- const { textStyle = {} } = splitStyle(normalStyle)
57
+ const { textStyle } = splitStyle(normalStyle)
58
58
  const { textProps } = splitProps(props)
59
- const scrollViewRef = useAnimatedRef<Reanimated.ScrollView>()
60
- const offsetYShared = useScrollViewOffset(scrollViewRef as AnimatedRef<Reanimated.ScrollView>)
59
+ const scrollViewRef = useRef<ScrollView>(null)
61
60
 
62
- useNodesRef(props, ref, scrollViewRef as AnimatedRef<ScrollView>, {
61
+ useNodesRef(props, ref, scrollViewRef, {
63
62
  style: normalStyle
64
63
  })
65
64
 
66
- const { height: pickerH, itemHeight } = wrapperStyle
67
- const [itemRawH, setItemRawH] = useState(itemHeight)
65
+ const { height: pickerH, itemHeight = DefaultPickerItemH } = wrapperStyle
66
+ const [itemRawH, setItemRawH] = useState(0) // 单个选项真实渲染高度
68
67
  const maxIndex = useMemo(() => columnData.length - 1, [columnData])
69
- const prevScrollingInfo = useRef({ index: initialIndex, y: 0 })
70
68
  const touching = useRef(false)
71
69
  const scrolling = useRef(false)
72
70
  const activeIndex = useRef(initialIndex)
73
71
  const prevIndex = usePrevious(initialIndex)
74
72
  const prevMaxIndex = usePrevious(maxIndex)
75
73
 
76
- const {
77
- layoutProps
78
- } = useLayout({
79
- props,
80
- hasSelfPercent,
81
- setWidth,
82
- setHeight,
83
- nodeRef: scrollViewRef
84
- })
85
-
86
- // console.log('[mpx-picker-view-column], render ---> columnIndex=', columnIndex, 'initialIndex=', initialIndex, 'columnData=', columnData.length, 'pickerH=', pickerH, 'itemRawH=', itemRawH, 'itemHeight=', itemHeight)
87
-
88
- const paddingHeight = useMemo(
89
- () => Math.round((pickerH - itemHeight) / 2),
90
- [pickerH, itemHeight]
91
- )
74
+ const initialOffset = useMemo(() => ({
75
+ x: 0,
76
+ y: itemRawH * initialIndex
77
+ }), [itemRawH])
92
78
 
93
79
  const snapToOffsets = useMemo(
94
80
  () => columnData.map((_, i) => i * itemRawH),
@@ -96,34 +82,12 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
96
82
  )
97
83
 
98
84
  const contentContainerStyle = useMemo(() => {
99
- return [{ paddingVertical: paddingHeight }]
100
- }, [paddingHeight])
101
-
102
- const getIndex = useCallback((y: number) => {
103
- const calc = Math.round(y / itemRawH)
104
- return Math.max(0, Math.min(calc, maxIndex))
105
- }, [itemRawH, maxIndex])
106
-
107
- const getYofIndex = useCallback((index: number) => {
108
- return index * itemRawH
109
- }, [itemRawH])
110
-
111
- const stableResetScrollPosition = useStableCallback((y: number) => {
112
- console.log('[mpx-picker-view-column], reset --->', 'columnIndex=', columnIndex, 'y=', y, touching.current, scrolling.current)
113
- if (touching.current || scrolling.current) {
114
- return
115
- }
116
- // needReset.current = true
117
- if (y % itemRawH !== 0) {
118
- scrolling.current = true
119
- const targetIndex = getIndex(y)
120
- const targetY = getYofIndex(targetIndex)
121
- scrollViewRef.current?.scrollTo({ x: 0, y: targetY, animated: false })
122
- } else {
123
- onMomentumScrollEnd({ nativeEvent: { contentOffset: { y } } })
124
- }
125
- })
126
- const debounceResetScrollPosition = useDebounceCallback(stableResetScrollPosition, 10)
85
+ return [
86
+ {
87
+ paddingVertical: Math.round(pickerH - itemRawH) / 2
88
+ }
89
+ ]
90
+ }, [pickerH, itemRawH])
127
91
 
128
92
  useEffect(() => {
129
93
  if (
@@ -138,170 +102,188 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
138
102
  ) {
139
103
  return
140
104
  }
141
- setTimeout(() => {
142
- scrollViewRef.current?.scrollTo({
143
- x: 0,
144
- y: getYofIndex(initialIndex),
145
- animated: false
146
- })
147
- }, isAndroid ? 200 : 0)
105
+
148
106
  activeIndex.current = initialIndex
107
+ scrollViewRef.current.scrollTo({
108
+ x: 0,
109
+ y: itemRawH * initialIndex,
110
+ animated: false
111
+ })
149
112
  }, [itemRawH, initialIndex])
150
113
 
151
- const onContentSizeChange = (_w: number, h: number) => {
152
- const y = getYofIndex(initialIndex)
153
- if (y <= h) {
154
- setTimeout(() => {
155
- scrollViewRef.current?.scrollTo({ x: 0, y, animated: false })
156
- }, 0)
157
- }
114
+ const onScrollViewLayout = () => {
115
+ getInnerLayout && getInnerLayout(layoutRef)
116
+ }
117
+
118
+ const {
119
+ layoutRef,
120
+ layoutProps
121
+ } = useLayout({
122
+ props,
123
+ hasSelfPercent,
124
+ setWidth,
125
+ setHeight,
126
+ nodeRef: scrollViewRef,
127
+ onLayout: onScrollViewLayout
128
+ })
129
+
130
+ const onContentSizeChange = (w: number, h: number) => {
131
+ scrollViewRef.current?.scrollTo({
132
+ x: 0,
133
+ y: itemRawH * initialIndex,
134
+ animated: false
135
+ })
158
136
  }
159
137
 
160
138
  const onItemLayout = (e: LayoutChangeEvent) => {
161
139
  const { height: rawH } = e.nativeEvent.layout
162
140
  if (rawH && itemRawH !== rawH) {
163
141
  setItemRawH(rawH)
142
+ onColumnItemRawHChange(rawH)
164
143
  }
165
144
  }
166
145
 
167
- const onScrollBeginDrag = () => {
168
- isIOS && debounceResetScrollPosition.clear()
146
+ const onTouchStart = () => {
169
147
  touching.current = true
170
- prevScrollingInfo.current = {
171
- index: activeIndex.current,
172
- y: getYofIndex(activeIndex.current)
173
- }
174
148
  }
175
149
 
176
- const onScrollEndDrag = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
150
+ const onTouchEnd = () => {
151
+ touching.current = false
152
+ }
153
+
154
+ const onTouchCancel = () => {
177
155
  touching.current = false
178
- const { y } = e.nativeEvent.contentOffset
179
- if (isIOS) {
180
- if (y > 0 && y < snapToOffsets[maxIndex]) {
181
- debounceResetScrollPosition(y)
182
- }
183
- }
184
156
  }
185
157
 
186
158
  const onMomentumScrollBegin = () => {
187
- isIOS && debounceResetScrollPosition.clear()
188
159
  scrolling.current = true
189
160
  }
190
161
 
191
- const onMomentumScrollEnd = (e: NativeSyntheticEvent<NativeScrollEvent> | { nativeEvent: { contentOffset: { y: number } } }) => {
162
+ const onMomentumScrollEnd = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
192
163
  scrolling.current = false
193
- const { y: scrollY } = e.nativeEvent.contentOffset
194
- if (isIOS && scrollY % itemRawH !== 0) {
195
- return debounceResetScrollPosition(scrollY)
164
+ if (!itemRawH) {
165
+ return
196
166
  }
197
- const calcIndex = getIndex(scrollY)
167
+ const { y: scrollY } = e.nativeEvent.contentOffset
168
+ let calcIndex = Math.round(scrollY / itemRawH)
198
169
  activeIndex.current = calcIndex
199
170
  if (calcIndex !== initialIndex) {
171
+ calcIndex = Math.max(0, Math.min(calcIndex, maxIndex)) || 0
200
172
  onSelectChange(calcIndex)
201
173
  }
202
174
  }
203
175
 
204
- const onScroll = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
205
- const { y } = e.nativeEvent.contentOffset
206
- if (isAndroid) {
207
- return
208
- }
209
- // 全局注册的震动触感 hook
210
- const pickerVibrate = global.__mpx.config.rnConfig.pickerVibrate
211
- if (typeof pickerVibrate !== 'function') {
212
- return
213
- }
214
- const { index: prevIndex, y: _y } = prevScrollingInfo.current
215
- if (touching.current || scrolling.current) {
216
- if (Math.abs(y - _y) >= itemRawH) {
217
- const currentId = getIndex(y)
218
- if (currentId !== prevIndex) {
219
- prevScrollingInfo.current = {
220
- index: currentId,
221
- y: getYofIndex(currentId)
222
- }
223
- // vibrateShort({ type: 'selection' })
224
- pickerVibrate()
225
- }
176
+ const offsetY = useRef(new Animated.Value(0)).current
177
+
178
+ const onScroll = useMemo(
179
+ () =>
180
+ Animated.event([{ nativeEvent: { contentOffset: { y: offsetY } } }], {
181
+ useNativeDriver: true
182
+ }),
183
+ [offsetY]
184
+ )
185
+
186
+ const faces = useMemo(() => createFaces(itemRawH, visibleCount), [itemRawH])
187
+
188
+ const getTransform = useCallback(
189
+ (index: number) => {
190
+ const inputRange = faces.map((f) => itemRawH * (index + f.index))
191
+ return {
192
+ opacity: offsetY.interpolate({
193
+ inputRange: inputRange,
194
+ outputRange: faces.map((x) => x.opacity),
195
+ extrapolate: 'clamp'
196
+ }),
197
+ rotateX: offsetY.interpolate({
198
+ inputRange: inputRange,
199
+ outputRange: faces.map((x) => `${x.deg}deg`),
200
+ extrapolate: 'extend'
201
+ }),
202
+ translateY: offsetY.interpolate({
203
+ inputRange: inputRange,
204
+ outputRange: faces.map((x) => x.offsetY),
205
+ extrapolate: 'extend'
206
+ })
226
207
  }
227
- }
228
- }
208
+ },
209
+ [offsetY, faces, itemRawH]
210
+ )
229
211
 
230
212
  const renderInnerchild = () =>
231
- columnData.map((item: React.ReactElement, index: number) => {
213
+ columnData.map((item: React.ReactNode, index: number) => {
214
+ const InnerProps = index === 0 ? { onLayout: onItemLayout } : {}
215
+ const strKey = `picker-column-${columnIndex}-${index}`
216
+ const { opacity, rotateX, translateY } = getTransform(index)
232
217
  return (
233
- <MpxPickerVIewColumnItem
234
- key={index}
235
- item={item}
236
- index={index}
237
- itemHeight={itemHeight}
238
- textStyleFromParent={textStyleFromParent}
239
- textStyle={textStyle}
240
- hasVarDec={hasVarDec}
241
- varContext={varContextRef.current}
242
- textProps={textProps}
243
- visibleCount={visibleCount}
244
- onItemLayout={onItemLayout}
245
- />
218
+ <Animated.View
219
+ key={strKey}
220
+ {...InnerProps}
221
+ style={[
222
+ {
223
+ height: itemHeight || DefaultPickerItemH,
224
+ width: '100%',
225
+ opacity,
226
+ transform: [
227
+ { translateY },
228
+ { rotateX },
229
+ { perspective: 1000 } // 适配 Android
230
+ ]
231
+ }
232
+ ]}
233
+ >
234
+ {wrapChildren(
235
+ { children: item },
236
+ {
237
+ hasVarDec,
238
+ varContext: varContextRef.current,
239
+ textStyle,
240
+ textProps
241
+ }
242
+ )}
243
+ </Animated.View>
246
244
  )
247
245
  })
248
246
 
249
247
  const renderScollView = () => {
250
248
  return (
251
- <PickerViewColumnAnimationContext.Provider value={offsetYShared}>
252
- <Reanimated.ScrollView
253
- ref={scrollViewRef}
254
- bounces={true}
255
- horizontal={false}
256
- nestedScrollEnabled={true}
257
- removeClippedSubviews={false}
258
- showsVerticalScrollIndicator={false}
259
- showsHorizontalScrollIndicator={false}
260
- scrollEventThrottle={16}
261
- {...layoutProps}
262
- style={[{ width: '100%' }]}
263
- decelerationRate="fast"
264
- snapToOffsets={snapToOffsets}
265
- onScroll={onScroll}
266
- onScrollBeginDrag={onScrollBeginDrag}
267
- onScrollEndDrag={onScrollEndDrag}
268
- onMomentumScrollBegin={onMomentumScrollBegin}
269
- onMomentumScrollEnd={onMomentumScrollEnd}
270
- onContentSizeChange={onContentSizeChange}
271
- contentContainerStyle={contentContainerStyle}
272
- >
273
- {renderInnerchild()}
274
- </Reanimated.ScrollView>
275
- </PickerViewColumnAnimationContext.Provider>
249
+ <Animated.ScrollView
250
+ ref={scrollViewRef}
251
+ bounces={true}
252
+ horizontal={false}
253
+ pagingEnabled={false}
254
+ nestedScrollEnabled={true}
255
+ removeClippedSubviews={true}
256
+ showsVerticalScrollIndicator={false}
257
+ showsHorizontalScrollIndicator={false}
258
+ {...layoutProps}
259
+ scrollEventThrottle={16}
260
+ contentContainerStyle={contentContainerStyle}
261
+ contentOffset={initialOffset}
262
+ snapToOffsets={snapToOffsets}
263
+ onContentSizeChange={onContentSizeChange}
264
+ onScroll={onScroll}
265
+ onTouchStart={onTouchStart}
266
+ onTouchEnd={onTouchEnd}
267
+ onTouchCancel={onTouchCancel}
268
+ onMomentumScrollBegin={onMomentumScrollBegin}
269
+ onMomentumScrollEnd={onMomentumScrollEnd}
270
+ >
271
+ {renderInnerchild()}
272
+ </Animated.ScrollView>
276
273
  )
277
274
  }
278
275
 
279
276
  const renderOverlay = () => (
280
- <PickerOverlay
281
- itemHeight={itemHeight}
282
- overlayItemStyle={pickerOverlayStyle}
283
- />
284
- )
285
-
286
- const renderMask = () => (
287
- <PickerMask
288
- itemHeight={itemHeight}
289
- maskContainerStyle={pickerMaskStyle}
290
- />
277
+ <PickerOverlay itemHeight={itemHeight} overlayItemStyle={pickerOverlayStyle} />
291
278
  )
292
279
 
293
280
  return (
294
- <SafeAreaView style={[styles.wrapper, normalStyle]}>
281
+ <SafeAreaView style={[{ display: 'flex', flex: 1 }]}>
295
282
  {renderScollView()}
296
- {renderMask()}
297
283
  {renderOverlay()}
298
284
  </SafeAreaView>
299
285
  )
300
286
  })
301
287
 
302
- const styles = StyleSheet.create({
303
- wrapper: { display: 'flex', flex: 1 }
304
- })
305
-
306
288
  _PickerViewColumn.displayName = 'MpxPickerViewColumn'
307
289
  export default _PickerViewColumn