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

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 (50) hide show
  1. package/lib/index.js +17 -1
  2. package/lib/platform/style/wx/index.js +18 -18
  3. package/lib/platform/template/wx/component-config/movable-view.js +8 -1
  4. package/lib/platform/template/wx/component-config/scroll-view.js +1 -1
  5. package/lib/resolver/AddEnvPlugin.js +1 -0
  6. package/lib/resolver/AddModePlugin.js +1 -0
  7. package/lib/runtime/components/react/context.ts +8 -0
  8. package/lib/runtime/components/react/dist/context.js +2 -0
  9. package/lib/runtime/components/react/dist/getInnerListeners.js +3 -4
  10. package/lib/runtime/components/react/dist/mpx-input.jsx +1 -1
  11. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +1 -1
  12. package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +1 -1
  13. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +54 -52
  14. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +1 -1
  15. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +10 -11
  16. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +21 -6
  17. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +25 -8
  18. package/lib/runtime/components/react/dist/mpx-swiper.jsx +150 -148
  19. package/lib/runtime/components/react/dist/mpx-view.jsx +9 -40
  20. package/lib/runtime/components/react/dist/mpx-web-view.jsx +50 -12
  21. package/lib/runtime/components/react/dist/pickerFaces.js +1 -1
  22. package/lib/runtime/components/react/dist/useAnimationHooks.js +1 -1
  23. package/lib/runtime/components/react/dist/utils.jsx +63 -4
  24. package/lib/runtime/components/react/getInnerListeners.ts +3 -5
  25. package/lib/runtime/components/react/mpx-input.tsx +1 -1
  26. package/lib/runtime/components/react/mpx-movable-view.tsx +1 -1
  27. package/lib/runtime/components/react/mpx-picker-view-column-item.tsx +88 -0
  28. package/lib/runtime/components/react/mpx-picker-view-column.tsx +177 -159
  29. package/lib/runtime/components/react/mpx-picker-view.tsx +35 -37
  30. package/lib/runtime/components/react/mpx-rich-text/index.tsx +12 -18
  31. package/lib/runtime/components/react/mpx-scroll-view.tsx +30 -13
  32. package/lib/runtime/components/react/mpx-swiper-item.tsx +38 -10
  33. package/lib/runtime/components/react/mpx-swiper.tsx +690 -0
  34. package/lib/runtime/components/react/mpx-view.tsx +11 -51
  35. package/lib/runtime/components/react/mpx-web-view.tsx +57 -13
  36. package/lib/runtime/components/react/pickerFaces.ts +15 -7
  37. package/lib/runtime/components/react/pickerVIewContext.ts +18 -0
  38. package/lib/runtime/components/react/pickerViewMask.tsx +30 -0
  39. package/lib/runtime/components/react/{pickerOverlay.tsx → pickerViewOverlay.tsx} +5 -3
  40. package/lib/runtime/components/react/types/global.d.ts +3 -1
  41. package/lib/runtime/components/react/useAnimationHooks.ts +1 -1
  42. package/lib/runtime/components/react/utils.tsx +75 -5
  43. package/lib/style-compiler/index.js +3 -4
  44. package/lib/style-compiler/strip-conditional-loader.js +118 -0
  45. package/lib/template-compiler/compiler.js +9 -14
  46. package/lib/utils/pre-process-json.js +5 -9
  47. package/package.json +1 -1
  48. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +0 -527
  49. package/lib/runtime/components/react/mpx-swiper/index.tsx +0 -80
  50. package/lib/runtime/components/react/mpx-swiper/type.ts +0 -87
package/lib/index.js CHANGED
@@ -54,11 +54,13 @@ 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')
57
58
  const templateCompilerPath = normalize.lib('template-compiler/index')
58
59
  const jsonCompilerPath = normalize.lib('json-compiler/index')
59
60
  const jsonThemeCompilerPath = normalize.lib('json-compiler/theme')
60
61
  const jsonPluginCompilerPath = normalize.lib('json-compiler/plugin')
61
62
  const extractorPath = normalize.lib('extractor')
63
+ const selectorPath = normalize.lib('selector')
62
64
  const async = require('async')
63
65
  const { parseQuery } = require('loader-utils')
64
66
  const stringifyLoadersAndResource = require('./utils/stringify-loaders-resource')
@@ -1775,7 +1777,7 @@ try {
1775
1777
  })
1776
1778
 
1777
1779
  const typeLoaderProcessInfo = {
1778
- styles: ['node_modules/css-loader', wxssLoaderPath, styleCompilerPath],
1780
+ styles: ['node_modules/css-loader', wxssLoaderPath, styleCompilerPath, styleStripConditaionalPath],
1779
1781
  template: ['node_modules/html-loader', wxmlLoaderPath, templateCompilerPath]
1780
1782
  }
1781
1783
 
@@ -1833,6 +1835,20 @@ try {
1833
1835
  loader: extractorPath
1834
1836
  })
1835
1837
  }
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
+ }
1836
1852
  createData.resource = addQuery(createData.resource, { mpx: MPX_PROCESSED_FLAG }, true)
1837
1853
  }
1838
1854
  // 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) || calcExp.test(value)) return { prop, value }
377
+ if (Array.isArray(value) || cssVariableExp.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 })
422
- }
423
- return { [`${key}${xyz[index] || ''}`]: v.trim() }
424
- }))
425
- break
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])
426
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 })
422
+ }
423
+ return { [`${key}${xyz[index] || ''}`]: v.trim() }
424
+ }))
425
+ break
426
+ }
427
427
  case 'translateZ':
428
428
  case 'scaleZ':
429
429
  default:
@@ -2,6 +2,8 @@ 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' })
5
7
  const qaPropLog = print({ platform: 'qa', tag: TAG_NAME, isError: false })
6
8
  const androidPropLog = print({ platform: 'android', tag: TAG_NAME, isError: false })
7
9
  const iosPropLog = print({ platform: 'ios', tag: TAG_NAME, isError: false })
@@ -27,7 +29,7 @@ module.exports = function ({ print }) {
27
29
  android: androidPropLog
28
30
  },
29
31
  {
30
- test: /^(inertia|damping|animation)$/,
32
+ test: /^(damping|friction|scale|scale-min|scale-max|scale-value)$/,
31
33
  ios: iosPropLog,
32
34
  android: androidPropLog
33
35
  }
@@ -36,6 +38,11 @@ module.exports = function ({ print }) {
36
38
  {
37
39
  test: /^(htouchmove|vtouchmove)$/,
38
40
  ali: aliEventLog
41
+ },
42
+ {
43
+ test: /^(bindscale)$/,
44
+ ios: iosEventLog,
45
+ android: androidEventLog
39
46
  }
40
47
  ]
41
48
  }
@@ -53,7 +53,7 @@ module.exports = function ({ print }) {
53
53
  qa: qaPropLog
54
54
  },
55
55
  {
56
- test: /^(scroll-into-view|refresher-threshold|enable-passive|scroll-anchoring|using-sticky|fast-deceleration|enable-flex)$/,
56
+ test: /^(refresher-threshold|enable-passive|scroll-anchoring|using-sticky|fast-deceleration|enable-flex)$/,
57
57
  android: androidPropLog,
58
58
  ios: iosPropLog
59
59
  },
@@ -34,6 +34,7 @@ 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 中无法读取到文件
37
38
  obj.query = stringifyQuery(queryObj)
38
39
  obj.path = addInfix(resourcePath, env, extname)
39
40
  obj.relativePath = request.relativePath && addInfix(request.relativePath, env, extname)
@@ -43,6 +43,7 @@ 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 中无法读取到文件
46
47
  obj.query = stringifyQuery(queryObj)
47
48
  obj.path = addInfix(resourcePath, defaultMode, extname)
48
49
  resolver.doResolve(target, Object.assign({}, request, obj), 'add mode: ' + defaultMode, resolveContext, (err, result) => {
@@ -33,6 +33,10 @@ export interface IntersectionObserver {
33
33
  }
34
34
  }
35
35
 
36
+ export interface ScrollViewContextValue {
37
+ gestureRef: React.RefObject<any> | null
38
+ }
39
+
36
40
  export const MovableAreaContext = createContext({ width: 0, height: 0 })
37
41
 
38
42
  export const FormContext = createContext<FormContextValue | null>(null)
@@ -51,4 +55,8 @@ export const IntersectionObserverContext = createContext<IntersectionObserver |
51
55
 
52
56
  export const RouteContext = createContext<number | null>(null)
53
57
 
58
+ export const SwiperContext = createContext({})
59
+
54
60
  export const KeyboardAvoidContext = createContext<KeyboardAvoidContextValue | null>(null)
61
+
62
+ export const ScrollViewContext = createContext<ScrollViewContextValue>({ gestureRef: null })
@@ -8,4 +8,6 @@ export const PickerContext = createContext(null);
8
8
  export const VarContext = createContext({});
9
9
  export const IntersectionObserverContext = createContext(null);
10
10
  export const RouteContext = createContext(null);
11
+ export const SwiperContext = createContext({});
11
12
  export const KeyboardAvoidContext = createContext(null);
13
+ export const ScrollViewContext = createContext({ gestureRef: null });
@@ -213,7 +213,6 @@ const useInnerProps = (props = {}, additionalProps = {}, userRemoveProps = [], r
213
213
  const eventConfig = {};
214
214
  const config = rawConfig || {
215
215
  layoutRef: { current: {} },
216
- disableTouch: false,
217
216
  disableTap: false
218
217
  };
219
218
  const removeProps = [
@@ -237,10 +236,10 @@ const useInnerProps = (props = {}, additionalProps = {}, userRemoveProps = [], r
237
236
  rawEventKeys.push(key);
238
237
  }
239
238
  }
240
- if (!rawEventKeys.length || config.disableTouch) {
241
- return omit(propsRef.current, removeProps);
242
- }
243
239
  const events = useMemo(() => {
240
+ if (!rawEventKeys.length) {
241
+ return {};
242
+ }
244
243
  const transformedEventKeys = rawEventKeys.reduce((acc, key) => {
245
244
  if (propsRef.current[key]) {
246
245
  return acc.concat(eventConfig[key]);
@@ -54,7 +54,7 @@ const keyboardTypeMap = {
54
54
  }) || ''
55
55
  };
56
56
  const Input = forwardRef((props, ref) => {
57
- const { style = {}, allowFontScaling = false, type = 'text', value, password, 'placeholder-style': placeholderStyle, disabled, maxlength = 140, 'auto-focus': autoFocus, focus, 'confirm-type': confirmType = 'done', 'confirm-hold': confirmHold = false, cursor, 'cursor-color': cursorColor, 'selection-start': selectionStart = -1, 'selection-end': selectionEnd = -1, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'adjust-position': adjustPosition = true, bindinput, bindfocus, bindblur, bindconfirm, bindselectionchange,
57
+ const { style = {}, allowFontScaling = false, type = 'text', value, password, 'placeholder-style': placeholderStyle, disabled, maxlength = 140, 'auto-focus': autoFocus, focus, 'confirm-type': confirmType = 'done', 'confirm-hold': confirmHold = false, cursor, 'cursor-color': cursorColor, 'selection-start': selectionStart = -1, 'selection-end': selectionEnd = -1, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'adjust-position': adjustPosition = false, bindinput, bindfocus, bindblur, bindconfirm, bindselectionchange,
58
58
  // private
59
59
  multiline, 'auto-height': autoHeight, bindlinechange } = props;
60
60
  const formContext = useContext(FormContext);
@@ -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
@@ -3,7 +3,7 @@ import Reanimated, { Extrapolation, interpolate, useAnimatedStyle, useSharedValu
3
3
  import { wrapChildren, extendObject } from './utils';
4
4
  import { createFaces } from './pickerFaces';
5
5
  import { usePickerViewColumnAnimationContext } from './pickerVIewContext';
6
- const _PickerViewColumnItem = ({ item, index, itemHeight, itemWidth, textStyleFromParent, textStyle, hasVarDec, varContext, textProps, visibleCount, onItemLayout }) => {
6
+ const _PickerViewColumnItem = ({ item, index, itemHeight, itemWidth = '100%', textStyleFromParent, textStyle, hasVarDec, varContext, textProps, visibleCount, onItemLayout }) => {
7
7
  const offsetYShared = usePickerViewColumnAnimationContext();
8
8
  const facesShared = useSharedValue(createFaces(itemHeight, visibleCount));
9
9
  useEffect(() => {
@@ -1,8 +1,7 @@
1
1
  import React, { forwardRef, useRef, useState, useMemo, useEffect, useCallback } from 'react';
2
- import { Platform, SafeAreaView, StyleSheet } from 'react-native';
2
+ import { SafeAreaView, StyleSheet } from 'react-native';
3
3
  import Reanimated, { useAnimatedRef, useScrollViewOffset } from 'react-native-reanimated';
4
- import { vibrateShort } from '@mpxjs/api-proxy';
5
- import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious } from './utils';
4
+ import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, useDebounceCallback, useStableCallback, isIOS } from './utils';
6
5
  import useNodesRef from './useNodesRef';
7
6
  import PickerOverlay from './pickerViewOverlay';
8
7
  import PickerMask from './pickerViewMask';
@@ -21,11 +20,8 @@ const _PickerViewColumn = forwardRef((props, ref) => {
21
20
  style: normalStyle
22
21
  });
23
22
  const { height: pickerH, itemHeight } = wrapperStyle;
24
- const [scrollViewWidth, setScrollViewWidth] = useState('100%');
25
- const [itemRawW, setItemRawW] = useState('100%');
26
23
  const [itemRawH, setItemRawH] = useState(itemHeight);
27
24
  const maxIndex = useMemo(() => columnData.length - 1, [columnData]);
28
- const maxScrollViewWidth = useRef(-1);
29
25
  const prevScrollingInfo = useRef({ index: initialIndex, y: 0 });
30
26
  const touching = useRef(false);
31
27
  const scrolling = useRef(false);
@@ -39,13 +35,9 @@ const _PickerViewColumn = forwardRef((props, ref) => {
39
35
  setHeight,
40
36
  nodeRef: scrollViewRef
41
37
  });
42
- // console.log('[mpx-picker-view-column], render ---> columnIndex=', columnIndex, 'initialIndex=', initialIndex, 'columnData=', columnData.length)
43
- // const initialOffset = useMemo(() => ({
44
- // x: 0,
45
- // y: itemRawH * initialIndex
46
- // }), [itemRawH])
38
+ // console.log('[mpx-picker-view-column], render ---> columnIndex=', columnIndex, 'initialIndex=', initialIndex, 'columnData=', columnData.length, 'pickerH=', pickerH, 'itemRawH=', itemRawH, 'itemHeight=', itemHeight)
39
+ const paddingHeight = useMemo(() => Math.round((pickerH - itemHeight) / 2), [pickerH, itemHeight]);
47
40
  const snapToOffsets = useMemo(() => columnData.map((_, i) => i * itemRawH), [columnData, itemRawH]);
48
- const paddingHeight = useMemo(() => Math.round((pickerH - itemRawH) / 2), [pickerH, itemRawH]);
49
41
  const contentContainerStyle = useMemo(() => {
50
42
  return [{ paddingVertical: paddingHeight }];
51
43
  }, [paddingHeight]);
@@ -53,6 +45,26 @@ const _PickerViewColumn = forwardRef((props, ref) => {
53
45
  const calc = Math.round(y / itemRawH);
54
46
  return Math.max(0, Math.min(calc, maxIndex));
55
47
  }, [itemRawH, maxIndex]);
48
+ const getYofIndex = useCallback((index) => {
49
+ return index * itemRawH;
50
+ }, [itemRawH]);
51
+ const stableResetScrollPosition = useStableCallback((y) => {
52
+ console.log('[mpx-picker-view-column], reset --->', 'columnIndex=', columnIndex, 'y=', y, touching.current, scrolling.current);
53
+ if (touching.current || scrolling.current) {
54
+ return;
55
+ }
56
+ // needReset.current = true
57
+ if (y % itemRawH !== 0) {
58
+ scrolling.current = true;
59
+ const targetIndex = getIndex(y);
60
+ const targetY = getYofIndex(targetIndex);
61
+ scrollViewRef.current?.scrollTo({ x: 0, y: targetY, animated: false });
62
+ }
63
+ else {
64
+ onMomentumScrollEnd({ nativeEvent: { contentOffset: { y } } });
65
+ }
66
+ });
67
+ const debounceResetScrollPosition = useDebounceCallback(stableResetScrollPosition, 10);
56
68
  useEffect(() => {
57
69
  if (!scrollViewRef.current ||
58
70
  !itemRawH ||
@@ -64,83 +76,72 @@ const _PickerViewColumn = forwardRef((props, ref) => {
64
76
  maxIndex !== prevMaxIndex) {
65
77
  return;
66
78
  }
67
- // console.log('[mpx-picker-view-column], useEffect ---> columnIndex=', columnIndex, 'initialIndex=', initialIndex, 'y=', itemRawH * initialIndex, `${scrollViewRef.current?.scrollTo}`)
68
79
  setTimeout(() => {
69
80
  scrollViewRef.current?.scrollTo({
70
81
  x: 0,
71
- y: itemRawH * initialIndex,
82
+ y: getYofIndex(initialIndex),
72
83
  animated: false
73
84
  });
74
- }, 0);
85
+ }, isAndroid ? 200 : 0);
75
86
  activeIndex.current = initialIndex;
76
87
  }, [itemRawH, initialIndex]);
77
88
  const onContentSizeChange = (_w, h) => {
78
- const y = itemRawH * initialIndex;
79
- // console.log('[mpx-picker-view-column], onContentSizeChange --->', 'columnIndex=', columnIndex, '_w=', _w, 'h=', h, 'y=', y)
89
+ const y = getYofIndex(initialIndex);
80
90
  if (y <= h) {
81
91
  setTimeout(() => {
82
92
  scrollViewRef.current?.scrollTo({ x: 0, y, animated: false });
83
93
  }, 0);
84
94
  }
85
95
  };
86
- const onScrollViewLayout = (e) => {
87
- const { width } = e.nativeEvent.layout;
88
- const widthInt = Math.ceil(width);
89
- // console.log('[mpx-picker-view-column], onScrollViewLayout --->', 'columnIndex=', columnIndex, 'widthInt=', widthInt, 'scrollViewWidth=', scrollViewWidth)
90
- if (widthInt !== scrollViewWidth) {
91
- const maxW = maxScrollViewWidth.current;
92
- if (maxW !== -1 && widthInt > maxW) {
93
- return;
94
- }
95
- if (maxW === -1) {
96
- maxScrollViewWidth.current = Math.ceil(widthInt * 1.5);
97
- }
98
- setScrollViewWidth(widthInt);
99
- }
100
- if (itemRawW === '100%') {
101
- setItemRawW(widthInt);
102
- }
103
- };
104
96
  const onItemLayout = (e) => {
105
97
  const { height: rawH } = e.nativeEvent.layout;
106
98
  if (rawH && itemRawH !== rawH) {
107
99
  setItemRawH(rawH);
108
100
  }
109
101
  };
110
- const onTouchStart = () => {
102
+ const onScrollBeginDrag = () => {
103
+ isIOS && debounceResetScrollPosition.clear();
111
104
  touching.current = true;
112
105
  prevScrollingInfo.current = {
113
106
  index: activeIndex.current,
114
- y: activeIndex.current * itemRawH
107
+ y: getYofIndex(activeIndex.current)
115
108
  };
116
109
  };
117
- const onTouchEnd = () => {
118
- touching.current = false;
119
- };
120
- const onTouchCancel = () => {
110
+ const onScrollEndDrag = (e) => {
121
111
  touching.current = false;
112
+ const { y } = e.nativeEvent.contentOffset;
113
+ if (isIOS) {
114
+ if (y > 0 && y < snapToOffsets[maxIndex]) {
115
+ debounceResetScrollPosition(y);
116
+ }
117
+ }
122
118
  };
123
119
  const onMomentumScrollBegin = () => {
120
+ isIOS && debounceResetScrollPosition.clear();
124
121
  scrolling.current = true;
125
122
  };
126
123
  const onMomentumScrollEnd = (e) => {
127
124
  scrolling.current = false;
128
- if (!itemRawH) {
129
- return;
130
- }
131
125
  const { y: scrollY } = e.nativeEvent.contentOffset;
132
- let calcIndex = Math.round(scrollY / itemRawH);
126
+ if (isIOS && scrollY % itemRawH !== 0) {
127
+ return debounceResetScrollPosition(scrollY);
128
+ }
129
+ const calcIndex = getIndex(scrollY);
133
130
  activeIndex.current = calcIndex;
134
131
  if (calcIndex !== initialIndex) {
135
- calcIndex = Math.max(0, Math.min(calcIndex, maxIndex)) || 0;
136
132
  onSelectChange(calcIndex);
137
133
  }
138
134
  };
139
135
  const onScroll = (e) => {
140
- if (Platform.OS === 'android') {
136
+ const { y } = e.nativeEvent.contentOffset;
137
+ if (isAndroid) {
138
+ return;
139
+ }
140
+ // 全局注册的震动触感 hook
141
+ const pickerVibrate = global.__mpx.config.rnConfig.pickerVibrate;
142
+ if (typeof pickerVibrate !== 'function') {
141
143
  return;
142
144
  }
143
- const { y } = e.nativeEvent.contentOffset;
144
145
  const { index: prevIndex, y: _y } = prevScrollingInfo.current;
145
146
  if (touching.current || scrolling.current) {
146
147
  if (Math.abs(y - _y) >= itemRawH) {
@@ -148,19 +149,20 @@ const _PickerViewColumn = forwardRef((props, ref) => {
148
149
  if (currentId !== prevIndex) {
149
150
  prevScrollingInfo.current = {
150
151
  index: currentId,
151
- y: currentId * itemRawH
152
+ y: getYofIndex(currentId)
152
153
  };
153
- vibrateShort({ type: 'selection' });
154
+ // vibrateShort({ type: 'selection' })
155
+ pickerVibrate();
154
156
  }
155
157
  }
156
158
  }
157
159
  };
158
160
  const renderInnerchild = () => columnData.map((item, index) => {
159
- return (<MpxPickerVIewColumnItem key={index} item={item} index={index} itemHeight={itemHeight} itemWidth={itemRawW} textStyleFromParent={textStyleFromParent} textStyle={textStyle} hasVarDec={hasVarDec} varContext={varContextRef.current} textProps={textProps} visibleCount={visibleCount} onItemLayout={onItemLayout}/>);
161
+ return (<MpxPickerVIewColumnItem key={index} item={item} index={index} itemHeight={itemHeight} textStyleFromParent={textStyleFromParent} textStyle={textStyle} hasVarDec={hasVarDec} varContext={varContextRef.current} textProps={textProps} visibleCount={visibleCount} onItemLayout={onItemLayout}/>);
160
162
  });
161
163
  const renderScollView = () => {
162
164
  return (<PickerViewColumnAnimationContext.Provider value={offsetYShared}>
163
- <Reanimated.ScrollView ref={scrollViewRef} bounces={true} horizontal={false} nestedScrollEnabled={true} removeClippedSubviews={false} showsVerticalScrollIndicator={false} showsHorizontalScrollIndicator={false} scrollEventThrottle={16} {...layoutProps} style={[{ width: scrollViewWidth }]} decelerationRate="fast" snapToOffsets={snapToOffsets} onScroll={onScroll} onLayout={onScrollViewLayout} onTouchStart={onTouchStart} onTouchEnd={onTouchEnd} onTouchCancel={onTouchCancel} onMomentumScrollBegin={onMomentumScrollBegin} onMomentumScrollEnd={onMomentumScrollEnd} onContentSizeChange={onContentSizeChange} contentContainerStyle={contentContainerStyle}>
165
+ <Reanimated.ScrollView ref={scrollViewRef} bounces={true} horizontal={false} nestedScrollEnabled={true} removeClippedSubviews={false} showsVerticalScrollIndicator={false} showsHorizontalScrollIndicator={false} scrollEventThrottle={16} {...layoutProps} style={[{ width: '100%' }]} decelerationRate="fast" snapToOffsets={snapToOffsets} onScroll={onScroll} onScrollBeginDrag={onScrollBeginDrag} onScrollEndDrag={onScrollEndDrag} onMomentumScrollBegin={onMomentumScrollBegin} onMomentumScrollEnd={onMomentumScrollEnd} onContentSizeChange={onContentSizeChange} contentContainerStyle={contentContainerStyle}>
164
166
  {renderInnerchild()}
165
167
  </Reanimated.ScrollView>
166
168
  </PickerViewColumnAnimationContext.Provider>);
@@ -45,7 +45,7 @@ const _PickerView = forwardRef((props, ref) => {
45
45
  };
46
46
  const onInitialChange = (isInvalid, value) => {
47
47
  if (isInvalid || !snapActiveValueRef.current || hasDiff(snapActiveValueRef.current, value)) {
48
- console.log('[mpx-picker-view], onInitialChange-1 ===> value=', value);
48
+ console.log('[mpx-picker-view], onInitialChange ===> value=', value);
49
49
  const eventData = getCustomEvent('change', {}, { detail: { value, source: 'change' }, layoutRef });
50
50
  bindchange?.(eventData);
51
51
  snapActiveValueRef.current = value.slice();
@@ -2,10 +2,10 @@
2
2
  * ✔ nodes
3
3
  */
4
4
  import { View } from 'react-native';
5
- import { useRef, forwardRef, useState } from 'react';
5
+ import { useRef, forwardRef, useState, createElement } from 'react';
6
6
  import useInnerProps from '../getInnerListeners';
7
7
  import useNodesRef from '../useNodesRef'; // 引入辅助函数
8
- import { useTransformStyle, useLayout } from '../utils';
8
+ import { useTransformStyle, useLayout, extendObject } from '../utils';
9
9
  import { WebView } from 'react-native-webview';
10
10
  import { generateHTML } from './html';
11
11
  function jsonToHtmlStr(elements) {
@@ -44,20 +44,19 @@ const _RichText = forwardRef((props, ref) => {
44
44
  useNodesRef(props, ref, nodeRef, {
45
45
  layoutRef
46
46
  });
47
- const innerProps = useInnerProps(props, {
47
+ const innerProps = useInnerProps(props, extendObject({
48
48
  ref: nodeRef,
49
- style: { ...normalStyle, ...layoutStyle },
50
- ...layoutProps
51
- }, [], {
49
+ style: extendObject(normalStyle, layoutStyle)
50
+ }, layoutProps), [], {
52
51
  layoutRef
53
52
  });
54
53
  const html = typeof nodes === 'string' ? nodes : jsonToHtmlStr(nodes);
55
- return (<View {...innerProps}>
56
- <WebView source={{ html: generateHTML(html) }} onMessage={(event) => {
54
+ return createElement(View, innerProps, createElement(WebView, {
55
+ source: { html: generateHTML(html) },
56
+ onMessage: (event) => {
57
57
  setWebViewHeight(+event.nativeEvent.data);
58
- }}>
59
- </WebView>
60
- </View>);
58
+ }
59
+ }));
61
60
  });
62
61
  _RichText.displayName = 'mpx-rich-text';
63
62
  export default _RichText;
@@ -32,14 +32,14 @@
32
32
  * ✔ bindscroll
33
33
  */
34
34
  import { ScrollView } from 'react-native-gesture-handler';
35
- import { RefreshControl } from 'react-native';
36
- import { useRef, useState, useEffect, forwardRef, useContext, createElement } from 'react';
35
+ import { RefreshControl, Platform } from 'react-native';
36
+ import { useRef, useState, useEffect, forwardRef, useContext, createElement, useMemo } from 'react';
37
37
  import { useAnimatedRef } from 'react-native-reanimated';
38
38
  import { warn } from '@mpxjs/utils';
39
39
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
40
40
  import useNodesRef from './useNodesRef';
41
41
  import { splitProps, splitStyle, useTransformStyle, useLayout, wrapChildren, extendObject, flatGesture } from './utils';
42
- import { IntersectionObserverContext } from './context';
42
+ import { IntersectionObserverContext, ScrollViewContext } from './context';
43
43
  const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
44
44
  const { textProps, innerProps: props = {} } = splitProps(scrollViewProps);
45
45
  const { enhanced = false, bounces = true, style = {}, binddragstart, binddragging, binddragend, bindtouchstart, bindtouchmove, bindtouchend, 'scroll-x': scrollX = false, 'scroll-y': scrollY = false, 'enable-back-to-top': enableBackToTop = false, 'enable-trigger-intersection-observer': enableTriggerIntersectionObserver = false, 'paging-enabled': pagingEnabled = false, 'upper-threshold': upperThreshold = 50, 'lower-threshold': lowerThreshold = 50, 'scroll-with-animation': scrollWithAnimation, 'refresher-enabled': refresherEnabled, 'refresher-default-style': refresherDefaultStyle, 'refresher-background': refresherBackground, 'show-scrollbar': showScrollbar = true, 'scroll-into-view': scrollIntoView = '', 'scroll-top': scrollTop = 0, 'scroll-left': scrollLeft = 0, 'refresher-triggered': refresherTriggered, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'simultaneous-handlers': originSimultaneousHandlers, 'wait-for': waitFor, __selectRef } = props;
@@ -78,6 +78,11 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
78
78
  },
79
79
  gestureRef: scrollViewRef
80
80
  });
81
+ const contextValue = useMemo(() => {
82
+ return {
83
+ gestureRef: scrollViewRef
84
+ };
85
+ }, []);
81
86
  const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout });
82
87
  if (scrollX && scrollY) {
83
88
  warn('scroll-x and scroll-y cannot be set to true at the same time, Mpx will use the value of scroll-y as the criterion');
@@ -179,6 +184,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
179
184
  visibleLength
180
185
  });
181
186
  }
187
+ const observerTimers = {};
182
188
  function onScroll(e) {
183
189
  const { bindscroll } = props;
184
190
  const { x: scrollLeft, y: scrollTop } = e.nativeEvent.contentOffset;
@@ -198,7 +204,16 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
198
204
  updateScrollOptions(e, { scrollLeft, scrollTop });
199
205
  if (enableTriggerIntersectionObserver && intersectionObservers) {
200
206
  for (const key in intersectionObservers) {
201
- intersectionObservers[key].throttleMeasure();
207
+ if (Platform.OS === 'android') {
208
+ intersectionObservers[key].throttleMeasure();
209
+ }
210
+ else {
211
+ // TODO: 由于iOS在onScroll滚动的过程中view的计算measureInWindow计算的值不发生变化,所以暂时在ios上加一个延时计算
212
+ observerTimers[key] && clearTimeout(observerTimers[key]);
213
+ observerTimers[key] = setTimeout(() => {
214
+ intersectionObservers[key].throttleMeasure();
215
+ }, 300);
216
+ }
202
217
  }
203
218
  }
204
219
  }
@@ -342,12 +357,12 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
342
357
  onRefresh: onRefresh
343
358
  }, (refresherDefaultStyle && refresherDefaultStyle !== 'none' ? { colors: refreshColor[refresherDefaultStyle] } : null)))
344
359
  : undefined
345
- }), wrapChildren(props, {
360
+ }), createElement(ScrollViewContext.Provider, { value: contextValue }, wrapChildren(props, {
346
361
  hasVarDec,
347
362
  varContext: varContextRef.current,
348
363
  textStyle,
349
364
  textProps
350
- }));
365
+ })));
351
366
  });
352
367
  _ScrollView.displayName = 'MpxScrollView';
353
368
  export default _ScrollView;
@@ -1,10 +1,15 @@
1
- import { View } from 'react-native';
2
- import { forwardRef, useRef } from 'react';
1
+ import Animated, { useAnimatedStyle, interpolate } from 'react-native-reanimated';
2
+ import { forwardRef, useRef, useContext } from 'react';
3
3
  import useInnerProps from './getInnerListeners';
4
4
  import useNodesRef from './useNodesRef'; // 引入辅助函数
5
5
  import { useTransformStyle, splitStyle, splitProps, wrapChildren, useLayout } from './utils';
6
+ import { SwiperContext } from './context';
6
7
  const _SwiperItem = forwardRef((props, ref) => {
7
- const { 'enable-var': enableVar, 'external-var-context': externalVarContext, style } = props;
8
+ const { 'enable-var': enableVar, 'external-var-context': externalVarContext, style, customStyle, itemIndex } = props;
9
+ const contextValue = useContext(SwiperContext);
10
+ const offset = contextValue.offset || 0;
11
+ const step = contextValue.step || 0;
12
+ const scale = contextValue.scale || false;
8
13
  const { textProps } = splitProps(props);
9
14
  const nodeRef = useRef(null);
10
15
  const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext });
@@ -16,21 +21,33 @@ const _SwiperItem = forwardRef((props, ref) => {
16
21
  // 存储layout布局信息
17
22
  layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: nodeRef });
18
23
  const innerProps = useInnerProps(props, {
19
- style: { ...innerStyle, ...layoutStyle },
20
24
  ref: nodeRef,
21
25
  ...layoutProps
22
26
  }, [
23
27
  'children',
24
- 'enable-offset'
28
+ 'enable-offset',
29
+ 'style'
25
30
  ], { layoutRef });
26
- return (<View data-itemId={props['item-id']} {...innerProps}>
27
- {wrapChildren(props, {
31
+ const itemAnimatedStyle = useAnimatedStyle(() => {
32
+ if (!step.value)
33
+ return {};
34
+ const inputRange = [step.value, 0];
35
+ const outputRange = [0.7, 1];
36
+ return {
37
+ transform: [{
38
+ scale: interpolate(Math.abs(Math.abs(offset.value) - itemIndex * step.value), inputRange, outputRange)
39
+ }]
40
+ };
41
+ });
42
+ const mergeStyle = [innerStyle, layoutStyle, { width: '100%', height: '100%' }, scale ? itemAnimatedStyle : {}].concat(customStyle);
43
+ return (<Animated.View {...innerProps} style={mergeStyle} data-itemId={props['item-id']}>
44
+ {wrapChildren(props, {
28
45
  hasVarDec,
29
46
  varContext: varContextRef.current,
30
47
  textStyle,
31
48
  textProps
32
49
  })}
33
- </View>);
50
+ </Animated.View>);
34
51
  });
35
52
  _SwiperItem.displayName = 'MpxSwiperItem';
36
53
  export default _SwiperItem;