@mpxjs/webpack-plugin 2.9.66 → 2.9.69

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 (112) hide show
  1. package/lib/dependencies/RecordGlobalComponentsDependency.js +11 -12
  2. package/lib/dependencies/RecordRuntimeInfoDependency.js +1 -1
  3. package/lib/index.js +29 -8
  4. package/lib/json-compiler/index.js +2 -11
  5. package/lib/loader.js +24 -45
  6. package/lib/native-loader.js +49 -64
  7. package/lib/platform/json/wx/index.js +3 -10
  8. package/lib/platform/style/wx/index.js +15 -10
  9. package/lib/platform/template/wx/component-config/canvas.js +8 -0
  10. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  11. package/lib/react/index.js +4 -3
  12. package/lib/react/processJSON.js +5 -13
  13. package/lib/react/processMainScript.js +7 -3
  14. package/lib/react/processScript.js +3 -4
  15. package/lib/react/processStyles.js +14 -4
  16. package/lib/react/processTemplate.js +2 -2
  17. package/lib/resolver/AddModePlugin.js +20 -7
  18. package/lib/runtime/components/react/context.ts +2 -0
  19. package/lib/runtime/components/react/dist/context.js +1 -0
  20. package/lib/runtime/components/react/dist/getInnerListeners.js +3 -12
  21. package/lib/runtime/components/react/dist/mpx-button.jsx +44 -9
  22. package/lib/runtime/components/react/dist/mpx-canvas/Bus.js +60 -0
  23. package/lib/runtime/components/react/dist/mpx-canvas/CanvasGradient.js +15 -0
  24. package/lib/runtime/components/react/dist/mpx-canvas/CanvasRenderingContext2D.js +84 -0
  25. package/lib/runtime/components/react/dist/mpx-canvas/Image.js +87 -0
  26. package/lib/runtime/components/react/dist/mpx-canvas/ImageData.js +15 -0
  27. package/lib/runtime/components/react/dist/mpx-canvas/constructorsRegistry.js +28 -0
  28. package/lib/runtime/components/react/dist/mpx-canvas/html.js +343 -0
  29. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +214 -0
  30. package/lib/runtime/components/react/dist/mpx-canvas/utils.jsx +89 -0
  31. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +30 -17
  32. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +1 -1
  33. package/lib/runtime/components/react/dist/mpx-form.jsx +33 -24
  34. package/lib/runtime/components/react/dist/mpx-icon.jsx +1 -1
  35. package/lib/runtime/components/react/dist/mpx-image/index.jsx +1 -1
  36. package/lib/runtime/components/react/dist/mpx-input.jsx +44 -38
  37. package/lib/runtime/components/react/dist/mpx-label.jsx +10 -7
  38. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +10 -17
  39. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +378 -294
  40. package/lib/runtime/components/react/dist/mpx-navigator.jsx +1 -1
  41. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +143 -84
  42. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +69 -113
  43. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +30 -17
  44. package/lib/runtime/components/react/dist/mpx-radio.jsx +1 -1
  45. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +1 -1
  46. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +49 -29
  47. package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +1 -1
  48. package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +1 -1
  49. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +1 -1
  50. package/lib/runtime/components/react/dist/mpx-switch.jsx +8 -1
  51. package/lib/runtime/components/react/dist/mpx-text.jsx +1 -1
  52. package/lib/runtime/components/react/dist/mpx-textarea.jsx +1 -1
  53. package/lib/runtime/components/react/dist/mpx-view.jsx +46 -27
  54. package/lib/runtime/components/react/dist/mpx-web-view.jsx +20 -6
  55. package/lib/runtime/components/react/dist/pickerFaces.js +75 -0
  56. package/lib/runtime/components/react/dist/pickerOverlay.jsx +21 -0
  57. package/lib/runtime/components/react/dist/useAnimationHooks.js +96 -8
  58. package/lib/runtime/components/react/dist/utils.jsx +66 -6
  59. package/lib/runtime/components/react/getInnerListeners.ts +3 -16
  60. package/lib/runtime/components/react/mpx-button.tsx +42 -9
  61. package/lib/runtime/components/react/mpx-canvas/Bus.ts +70 -0
  62. package/lib/runtime/components/react/mpx-canvas/CanvasGradient.ts +18 -0
  63. package/lib/runtime/components/react/mpx-canvas/CanvasRenderingContext2D.ts +87 -0
  64. package/lib/runtime/components/react/mpx-canvas/Image.ts +102 -0
  65. package/lib/runtime/components/react/mpx-canvas/ImageData.ts +23 -0
  66. package/lib/runtime/components/react/mpx-canvas/constructorsRegistry.ts +38 -0
  67. package/lib/runtime/components/react/mpx-canvas/html.ts +343 -0
  68. package/lib/runtime/components/react/mpx-canvas/index.tsx +302 -0
  69. package/lib/runtime/components/react/mpx-canvas/utils.tsx +150 -0
  70. package/lib/runtime/components/react/mpx-checkbox-group.tsx +52 -29
  71. package/lib/runtime/components/react/mpx-checkbox.tsx +1 -1
  72. package/lib/runtime/components/react/mpx-form.tsx +42 -34
  73. package/lib/runtime/components/react/mpx-icon.tsx +1 -1
  74. package/lib/runtime/components/react/mpx-image/index.tsx +2 -3
  75. package/lib/runtime/components/react/mpx-input.tsx +68 -66
  76. package/lib/runtime/components/react/mpx-label.tsx +11 -8
  77. package/lib/runtime/components/react/mpx-movable-area.tsx +11 -19
  78. package/lib/runtime/components/react/mpx-movable-view.tsx +456 -334
  79. package/lib/runtime/components/react/mpx-navigator.tsx +1 -1
  80. package/lib/runtime/components/react/mpx-picker-view-column.tsx +232 -103
  81. package/lib/runtime/components/react/mpx-picker-view.tsx +126 -122
  82. package/lib/runtime/components/react/mpx-radio-group.tsx +55 -29
  83. package/lib/runtime/components/react/mpx-radio.tsx +1 -1
  84. package/lib/runtime/components/react/mpx-root-portal.tsx +1 -1
  85. package/lib/runtime/components/react/mpx-scroll-view.tsx +81 -36
  86. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +2 -2
  87. package/lib/runtime/components/react/mpx-swiper/index.tsx +2 -1
  88. package/lib/runtime/components/react/mpx-swiper-item.tsx +1 -1
  89. package/lib/runtime/components/react/mpx-switch.tsx +10 -2
  90. package/lib/runtime/components/react/mpx-text.tsx +1 -1
  91. package/lib/runtime/components/react/mpx-textarea.tsx +1 -1
  92. package/lib/runtime/components/react/mpx-view.tsx +58 -28
  93. package/lib/runtime/components/react/mpx-web-view.tsx +23 -6
  94. package/lib/runtime/components/react/pickerFaces.ts +104 -0
  95. package/lib/runtime/components/react/pickerOverlay.tsx +32 -0
  96. package/lib/runtime/components/react/types/common.ts +2 -0
  97. package/lib/runtime/components/react/types/global.d.ts +2 -0
  98. package/lib/runtime/components/react/useAnimationHooks.ts +97 -13
  99. package/lib/runtime/components/react/useNodesRef.ts +1 -0
  100. package/lib/runtime/components/react/utils.tsx +94 -8
  101. package/lib/runtime/optionProcessorReact.js +0 -15
  102. package/lib/runtime/swanHelper.wxs +1 -1
  103. package/lib/style-compiler/index.js +1 -1
  104. package/lib/style-compiler/plugins/scope-id.js +1 -0
  105. package/lib/template-compiler/compiler.js +47 -16
  106. package/lib/template-compiler/gen-node-react.js +2 -2
  107. package/lib/template-compiler/index.js +4 -4
  108. package/lib/utils/pre-process-json.js +113 -0
  109. package/lib/web/index.js +5 -4
  110. package/lib/web/processJSON.js +5 -13
  111. package/lib/web/processTemplate.js +2 -2
  112. package/package.json +5 -4
@@ -31,5 +31,5 @@ const _Navigator = forwardRef((props, ref) => {
31
31
  {children}
32
32
  </MpxView>);
33
33
  });
34
- _Navigator.displayName = 'mpx-navigator';
34
+ _Navigator.displayName = 'MpxNavigator';
35
35
  export default _Navigator;
@@ -1,108 +1,167 @@
1
- import { View, Animated, SafeAreaView } from 'react-native';
2
- import React, { forwardRef, useRef, useState, useEffect } from 'react';
3
- import { useTransformStyle, splitStyle, splitProps, wrapChildren, useLayout } from './utils';
4
- import useNodesRef from './useNodesRef'; // 引入辅助函数
5
- const defaultItemHeight = 36;
6
- // 每个Column 都有个外层的高度, 内部的元素高度
7
- // 默认的高度
1
+ import { Animated, SafeAreaView } from 'react-native';
2
+ import React, { forwardRef, useRef, useState, useMemo, useCallback, useEffect } from 'react';
3
+ import { useTransformStyle, splitStyle, splitProps, wrapChildren, useLayout, usePrevious } from './utils';
4
+ import useNodesRef from './useNodesRef';
5
+ import { createFaces } from './pickerFaces';
6
+ import PickerOverlay from './pickerOverlay';
7
+ // 默认的单个选项高度
8
+ const DefaultPickerItemH = 36;
9
+ // 默认一屏可见选项个数
10
+ const visibleCount = 5;
8
11
  const _PickerViewColumn = forwardRef((props, ref) => {
9
- const { children, selectedIndex, onColumnLayoutChange, onSelectChange, getInnerLayout, style, wrapperStyle, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props;
10
- // PickerViewColumn
12
+ const { columnData, columnIndex, initialIndex, onSelectChange, onColumnItemRawHChange, getInnerLayout, style, wrapperStyle, pickerOverlayStyle, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props;
11
13
  const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext });
12
14
  const { textStyle } = splitStyle(normalStyle);
13
15
  const { textProps } = splitProps(props);
14
- // const { innerStyle } = splitStyle(normalStyle)
15
- // scrollView的ref
16
16
  const scrollViewRef = useRef(null);
17
17
  useNodesRef(props, ref, scrollViewRef, {});
18
- // 每个元素的高度
19
- let [itemH, setItemH] = useState(0);
18
+ const { height: pickerH, itemHeight = DefaultPickerItemH } = wrapperStyle;
19
+ const [itemRawH, setItemRawH] = useState(0); // 单个选项真实渲染高度
20
+ const maxIndex = useMemo(() => columnData.length - 1, [columnData]);
21
+ const touching = useRef(false);
22
+ const scrolling = useRef(false);
23
+ const activeIndex = useRef(initialIndex);
24
+ const prevIndex = usePrevious(initialIndex);
25
+ const prevMaxIndex = usePrevious(maxIndex);
26
+ const initialOffset = useMemo(() => ({
27
+ x: 0,
28
+ y: itemRawH * initialIndex
29
+ }), [itemRawH]);
30
+ const snapToOffsets = useMemo(() => columnData.map((_, i) => i * itemRawH), [columnData, itemRawH]);
31
+ const contentContainerStyle = useMemo(() => {
32
+ return [
33
+ {
34
+ paddingVertical: Math.round(pickerH - itemRawH) / 2
35
+ }
36
+ ];
37
+ }, [pickerH, itemRawH]);
20
38
  useEffect(() => {
21
- if (selectedIndex && itemH) {
22
- const offsetY = selectedIndex * itemH;
23
- scrollViewRef.current?.scrollTo({ x: 0, y: offsetY, animated: true });
39
+ if (!scrollViewRef.current ||
40
+ !itemRawH ||
41
+ touching.current ||
42
+ scrolling.current ||
43
+ prevIndex == null ||
44
+ initialIndex === prevIndex ||
45
+ initialIndex === activeIndex.current ||
46
+ maxIndex !== prevMaxIndex) {
47
+ return;
24
48
  }
25
- }, [selectedIndex, itemH]);
49
+ activeIndex.current = initialIndex;
50
+ scrollViewRef.current.scrollTo({
51
+ x: 0,
52
+ y: itemRawH * initialIndex,
53
+ animated: false
54
+ });
55
+ }, [itemRawH, initialIndex]);
26
56
  const onScrollViewLayout = () => {
27
57
  getInnerLayout && getInnerLayout(layoutRef);
28
58
  };
29
- const {
30
- // 存储layout布局信息
31
- layoutRef, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout: onScrollViewLayout });
59
+ const { layoutRef, layoutProps } = useLayout({
60
+ props,
61
+ hasSelfPercent,
62
+ setWidth,
63
+ setHeight,
64
+ nodeRef: scrollViewRef,
65
+ onLayout: onScrollViewLayout
66
+ });
67
+ const onContentSizeChange = (w, h) => {
68
+ scrollViewRef.current?.scrollTo({
69
+ x: 0,
70
+ y: itemRawH * initialIndex,
71
+ animated: false
72
+ });
73
+ };
32
74
  const onItemLayout = (e) => {
33
- const layout = e.nativeEvent.layout;
34
- if (layout.height && itemH !== layout.height) {
35
- itemH = layout.height;
36
- setItemH(layout.height);
37
- onColumnLayoutChange && onColumnLayoutChange({ height: layout.height * 5 });
75
+ const { height: rawH } = e.nativeEvent.layout;
76
+ if (rawH && itemRawH !== rawH) {
77
+ setItemRawH(rawH);
78
+ onColumnItemRawHChange(rawH);
38
79
  }
39
80
  };
40
- const onMomentumScrollEnd = (e) => {
41
- if (scrollViewRef && itemH) {
42
- const { y: scrollY } = e.nativeEvent.contentOffset;
43
- const selIndex = Math.floor(scrollY / itemH);
44
- onSelectChange(selIndex);
45
- }
81
+ const onTouchStart = () => {
82
+ touching.current = true;
46
83
  };
47
- const renderInnerchild = () => {
48
- // Fragment 节点
49
- let realElement = [];
50
- const getRealChilds = () => {
51
- if (Array.isArray(children)) {
52
- realElement = children;
53
- }
54
- else {
55
- const tempChild = children;
56
- if (tempChild.props.children && tempChild.props.children) {
57
- realElement = tempChild.props.children;
58
- }
59
- else {
60
- realElement = [children];
61
- }
62
- }
63
- return realElement;
64
- };
65
- const realChilds = getRealChilds();
66
- const arrChild = realChilds.map((item, index) => {
67
- const InnerProps = index === 0 ? { onLayout: onItemLayout } : {};
68
- const strKey = 'picker' + props.prefix + '-column' + index;
69
- const arrHeight = (wrapperStyle.itemHeight + '').match(/\d+/g) || [];
70
- const iHeight = (arrHeight[0] || defaultItemHeight);
71
- return <View key={strKey} {...InnerProps} style={[{ height: iHeight, width: '100%' }]}>
72
- {wrapChildren({
73
- children: item
74
- }, {
75
- hasVarDec,
76
- varContext: varContextRef.current,
77
- textStyle,
78
- textProps
79
- })}
80
- </View>;
81
- });
82
- const totalHeight = itemH * 5;
83
- if (wrapperStyle.height && totalHeight !== wrapperStyle.height) {
84
- const fix = Math.ceil((totalHeight - wrapperStyle.height) / 2);
85
- arrChild.unshift(<View key="picker-column-0" style={[{ height: itemH - fix }]}></View>);
86
- arrChild.unshift(<View key="picker-column-1" style={[{ height: itemH }]}></View>);
87
- arrChild.push(<View key="picker-column-2" style={[{ height: itemH }]}></View>);
88
- arrChild.push(<View key="picker-column-3" style={[{ height: itemH - fix }]}></View>);
84
+ const onTouchEnd = () => {
85
+ touching.current = false;
86
+ };
87
+ const onTouchCancel = () => {
88
+ touching.current = false;
89
+ };
90
+ const onMomentumScrollBegin = () => {
91
+ scrolling.current = true;
92
+ };
93
+ const onMomentumScrollEnd = (e) => {
94
+ scrolling.current = false;
95
+ if (!itemRawH) {
96
+ return;
89
97
  }
90
- else {
91
- arrChild.unshift(<View key="picker-column-0" style={[{ height: itemH }]}></View>);
92
- arrChild.unshift(<View key="picker-column-1" style={[{ height: itemH }]}></View>);
93
- arrChild.push(<View key="picker-column-2" style={[{ height: itemH }]}></View>);
94
- arrChild.push(<View key="picker-column-3" style={[{ height: itemH }]}></View>);
98
+ const { y: scrollY } = e.nativeEvent.contentOffset;
99
+ let calcIndex = Math.round(scrollY / itemRawH);
100
+ activeIndex.current = calcIndex;
101
+ if (calcIndex !== initialIndex) {
102
+ calcIndex = Math.max(0, Math.min(calcIndex, maxIndex)) || 0;
103
+ onSelectChange(calcIndex);
95
104
  }
96
- return arrChild;
97
105
  };
106
+ const offsetY = useRef(new Animated.Value(0)).current;
107
+ const onScroll = useMemo(() => Animated.event([{ nativeEvent: { contentOffset: { y: offsetY } } }], {
108
+ useNativeDriver: true
109
+ }), [offsetY]);
110
+ const faces = useMemo(() => createFaces(itemRawH, visibleCount), [itemRawH]);
111
+ const getTransform = useCallback((index) => {
112
+ const inputRange = faces.map((f) => itemRawH * (index + f.index));
113
+ return {
114
+ opacity: offsetY.interpolate({
115
+ inputRange: inputRange,
116
+ outputRange: faces.map((x) => x.opacity),
117
+ extrapolate: 'clamp'
118
+ }),
119
+ rotateX: offsetY.interpolate({
120
+ inputRange: inputRange,
121
+ outputRange: faces.map((x) => `${x.deg}deg`),
122
+ extrapolate: 'extend'
123
+ }),
124
+ translateY: offsetY.interpolate({
125
+ inputRange: inputRange,
126
+ outputRange: faces.map((x) => x.offsetY),
127
+ extrapolate: 'extend'
128
+ })
129
+ };
130
+ }, [offsetY, faces, itemRawH]);
131
+ const renderInnerchild = () => columnData.map((item, index) => {
132
+ const InnerProps = index === 0 ? { onLayout: onItemLayout } : {};
133
+ const strKey = `picker-column-${columnIndex}-${index}`;
134
+ const { opacity, rotateX, translateY } = getTransform(index);
135
+ return (<Animated.View key={strKey} {...InnerProps} style={[
136
+ {
137
+ height: itemHeight || DefaultPickerItemH,
138
+ width: '100%',
139
+ opacity,
140
+ transform: [
141
+ { translateY },
142
+ { rotateX },
143
+ { perspective: 1000 } // 适配 Android
144
+ ]
145
+ }
146
+ ]}>
147
+ {wrapChildren({ children: item }, {
148
+ hasVarDec,
149
+ varContext: varContextRef.current,
150
+ textStyle,
151
+ textProps
152
+ })}
153
+ </Animated.View>);
154
+ });
98
155
  const renderScollView = () => {
99
- return (<Animated.ScrollView horizontal={false} ref={scrollViewRef} bounces={false} scrollsToTop={false} removeClippedSubviews={true} showsHorizontalScrollIndicator={false} showsVerticalScrollIndicator={false} pagingEnabled={false} snapToInterval={itemH} automaticallyAdjustContentInsets={false} {...layoutProps} onMomentumScrollEnd={onMomentumScrollEnd}>
156
+ return (<Animated.ScrollView ref={scrollViewRef} bounces={true} horizontal={false} pagingEnabled={false} nestedScrollEnabled={true} removeClippedSubviews={true} showsVerticalScrollIndicator={false} showsHorizontalScrollIndicator={false} {...layoutProps} scrollEventThrottle={16} contentContainerStyle={contentContainerStyle} contentOffset={initialOffset} snapToOffsets={snapToOffsets} onContentSizeChange={onContentSizeChange} onScroll={onScroll} onTouchStart={onTouchStart} onTouchEnd={onTouchEnd} onTouchCancel={onTouchCancel} onMomentumScrollBegin={onMomentumScrollBegin} onMomentumScrollEnd={onMomentumScrollEnd}>
100
157
  {renderInnerchild()}
101
- </Animated.ScrollView>);
158
+ </Animated.ScrollView>);
102
159
  };
160
+ const renderOverlay = () => (<PickerOverlay itemHeight={itemHeight} overlayItemStyle={pickerOverlayStyle}/>);
103
161
  return (<SafeAreaView style={[{ display: 'flex', flex: 1 }]}>
104
- {renderScollView()}
105
- </SafeAreaView>);
162
+ {renderScollView()}
163
+ {renderOverlay()}
164
+ </SafeAreaView>);
106
165
  });
107
- _PickerViewColumn.displayName = 'mpx-picker-view-column';
166
+ _PickerViewColumn.displayName = 'MpxPickerViewColumn';
108
167
  export default _PickerViewColumn;
@@ -1,9 +1,8 @@
1
1
  import { View } from 'react-native';
2
- import { LinearGradient } from 'react-native-linear-gradient';
3
2
  import React, { forwardRef, useState, useRef } from 'react';
4
3
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
5
- import useNodesRef from './useNodesRef'; // 引入辅助函数
6
- import { parseInlineStyle, useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren } from './utils';
4
+ import useNodesRef from './useNodesRef';
5
+ import { useLayout, splitProps, splitStyle, wrapChildren, parseInlineStyle, useTransformStyle, useDebounceCallback, useStableCallback, extendObject } from './utils';
7
6
  const styles = {
8
7
  wrapper: {
9
8
  display: 'flex',
@@ -12,16 +11,6 @@ const styles = {
12
11
  justifyContent: 'space-around',
13
12
  overflow: 'hidden',
14
13
  alignItems: 'center'
15
- },
16
- maskTop: {
17
- position: 'absolute',
18
- width: 1000,
19
- zIndex: 100
20
- },
21
- maskBottom: {
22
- position: 'absolute',
23
- width: 1000,
24
- zIndex: 100
25
14
  }
26
15
  };
27
16
  const _PickerView = forwardRef((props, ref) => {
@@ -29,67 +18,62 @@ const _PickerView = forwardRef((props, ref) => {
29
18
  // indicatorStyle 需要转换为rn的style
30
19
  // 微信设置到pick-view上上设置的normalStyle如border等需要转换成RN的style然后进行透传
31
20
  const indicatorStyle = parseInlineStyle(props['indicator-style']);
32
- const { height: indicatorH, width: indicatorW } = indicatorStyle;
21
+ const { height: indicatorH, ...pickerOverlayStyle } = indicatorStyle;
22
+ const [pickMaxH, setPickMaxH] = useState(0);
33
23
  const nodeRef = useRef(null);
34
- useNodesRef(props, ref, nodeRef, {});
35
- // picker-view 设置的color等textStyle,在小程序上的表现是可以继承到最内层的text样式, 但是RN内部column是slot无法设置, 需要业务自己在column内的元素上设置
24
+ const cloneRef = useRef(null);
25
+ const activeValueRef = useRef(value);
26
+ activeValueRef.current = value.slice();
36
27
  const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext });
37
- const { textStyle } = splitStyle(normalStyle);
38
- const { textProps } = splitProps(props);
28
+ useNodesRef(props, ref, nodeRef, {});
39
29
  const {
40
30
  // 存储layout布局信息
41
31
  layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: nodeRef });
42
- const isSetW = indicatorW !== undefined ? 1 : 0;
43
- const cloneRef = useRef(null);
44
- const maskPos = {};
45
- let [pickH, setPickH] = useState(0);
46
- const itemH = pickH / 5;
47
- if (normalStyle?.height && pickH && pickH !== normalStyle?.height) {
48
- maskPos.height = itemH * 2 + Math.ceil((normalStyle.height - pickH) / 2);
49
- }
50
- else {
51
- maskPos.height = itemH * 2;
52
- }
53
- const onColumnLayoutChange = (layoutConfig) => {
54
- pickH = layoutConfig.height;
55
- setPickH(layoutConfig.height);
32
+ const { textProps } = splitProps(props);
33
+ const { textStyle } = splitStyle(normalStyle);
34
+ const onColumnItemRawHChange = (height) => {
35
+ if (height > pickMaxH) {
36
+ setPickMaxH(height);
37
+ }
56
38
  };
57
- const onSelectChange = (columnIndex, selIndex) => {
58
- const changeValue = value.slice();
59
- changeValue[columnIndex] = selIndex;
60
- const eventData = getCustomEvent('change', {}, { detail: { value: changeValue, source: 'change' }, layoutRef });
61
- bindchange && bindchange(eventData);
39
+ const bindchangeDebounce = useDebounceCallback(useStableCallback(bindchange), 300);
40
+ const onSelectChange = (columnIndex, selectedIndex) => {
41
+ bindchangeDebounce.clear();
42
+ const activeValue = activeValueRef.current;
43
+ activeValue[columnIndex] = selectedIndex;
44
+ const eventData = getCustomEvent('change', {}, { detail: { value: activeValue, source: 'change' }, layoutRef });
45
+ bindchangeDebounce(eventData);
62
46
  };
63
- const innerProps = useInnerProps(props, {
47
+ const onInitialChange = (value) => {
48
+ const eventData = getCustomEvent('change', {}, { detail: { value, source: 'change' }, layoutRef });
49
+ bindchange?.(eventData); // immediate
50
+ };
51
+ const innerProps = useInnerProps(props, extendObject({
64
52
  ref: nodeRef,
65
- style: {
66
- ...normalStyle,
67
- ...layoutStyle,
53
+ style: extendObject(normalStyle, layoutStyle, {
68
54
  position: 'relative',
69
55
  overflow: 'hidden'
70
- },
71
- ...layoutProps
72
- }, [
73
- 'enable-offset'
74
- ], { layoutRef });
75
- const cloneChild = (child, index) => {
76
- // const extraProps = index === 0 ? { getInnerLayout: getInnerLayout, innerProps } : {}
56
+ }),
57
+ layoutProps
58
+ }), ['enable-offset'], { layoutRef });
59
+ const renderColumn = (child, index, columnData, initialIndex) => {
77
60
  const extraProps = {};
78
- const childProps = {
79
- ...child?.props,
61
+ const childProps = child?.props || {};
62
+ const wrappedProps = extendObject(childProps, {
63
+ columnData,
80
64
  ref: cloneRef,
81
- prefix: index,
82
- key: 'pick-view' + index,
65
+ columnIndex: index,
66
+ key: `pick-view-${index}`,
83
67
  wrapperStyle: {
84
68
  height: normalStyle?.height || 0,
85
69
  itemHeight: indicatorH || 0
86
70
  },
87
- onColumnLayoutChange,
71
+ onColumnItemRawHChange,
88
72
  onSelectChange: onSelectChange.bind(null, index),
89
- selectedIndex: value?.[index] || 0,
90
- ...extraProps
91
- };
92
- const realElement = React.cloneElement(child, childProps);
73
+ initialIndex,
74
+ pickerOverlayStyle
75
+ }, extraProps);
76
+ const realElement = React.cloneElement(child, wrappedProps);
93
77
  return wrapChildren({
94
78
  children: realElement
95
79
  }, {
@@ -99,65 +83,37 @@ const _PickerView = forwardRef((props, ref) => {
99
83
  textProps
100
84
  });
101
85
  };
102
- const renderTopMask = () => {
103
- const linearProps = {
104
- colors: ['rgba(255,255,255,0.8)', 'rgba(255,255,255,0.2)'],
105
- style: [
106
- styles.maskTop,
107
- {
108
- height: maskPos.height,
109
- top: 0,
110
- pointerEvents: 'none'
111
- }
112
- ]
113
- };
114
- return (<LinearGradient {...linearProps}/>);
115
- };
116
- const renderBottomMask = () => {
117
- const linearProps = {
118
- colors: ['rgba(255,255,255,0.2)', 'rgba(255,255,255,0.8)'],
119
- style: [
120
- styles.maskBottom,
121
- {
122
- height: maskPos.height,
123
- bottom: 0,
124
- pointerEvents: 'none'
125
- }
126
- ]
127
- };
128
- return <LinearGradient {...linearProps}></LinearGradient>;
86
+ const validateChildInitialIndex = (index, data) => {
87
+ return Math.max(0, Math.min(value[index] || 0, data.length - 1));
129
88
  };
130
- const renderLine = () => {
131
- return <View style={[{
132
- position: 'absolute',
133
- top: '50%',
134
- transform: [{ translateY: -(itemH / 2) }],
135
- height: itemH,
136
- borderTopWidth: 1,
137
- borderBottomWidth: 1,
138
- borderColor: '#f0f0f0',
139
- width: '100%',
140
- zIndex: 101
141
- }]}></View>;
142
- };
143
- const renderSubChild = () => {
144
- if (Array.isArray(children)) {
145
- return children.map((item, index) => {
146
- return cloneChild(item, index);
147
- });
148
- }
149
- else {
150
- return cloneChild(children, 0);
89
+ const flatColumnChildren = (data) => {
90
+ const columnData = React.Children.toArray(data?.props?.children);
91
+ if (columnData.length === 1 && React.isValidElement(columnData[0]) && columnData[0].type === React.Fragment) {
92
+ // 只有一个 Fragment 嵌套情况
93
+ return React.Children.toArray(columnData[0].props.children);
151
94
  }
95
+ return columnData;
96
+ };
97
+ const renderPickerColumns = () => {
98
+ const columns = React.Children.toArray(children);
99
+ const renderColumns = [];
100
+ const validValue = [];
101
+ let isInvalid = false;
102
+ columns.forEach((item, index) => {
103
+ const columnData = flatColumnChildren(item);
104
+ const validIndex = validateChildInitialIndex(index, columnData);
105
+ if (validIndex !== value[index]) {
106
+ isInvalid = true;
107
+ }
108
+ validValue.push(validIndex);
109
+ renderColumns.push(renderColumn(item, index, columnData, validIndex));
110
+ });
111
+ isInvalid && onInitialChange(validValue);
112
+ return renderColumns;
152
113
  };
153
114
  return (<View {...innerProps}>
154
- {renderTopMask()}
155
- <View style={[styles.wrapper]}>
156
- {renderSubChild()}
157
- </View>
158
- {renderBottomMask()}
159
- {!isSetW && renderLine()}
160
- </View>);
115
+ <View style={[styles.wrapper]}>{renderPickerColumns()}</View>
116
+ </View>);
161
117
  });
162
- _PickerView.displayName = 'mpx-picker-view';
118
+ _PickerView.displayName = 'MpxPickerView';
163
119
  export default _PickerView;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * ✔ bindchange
3
3
  */
4
- import { useRef, forwardRef, useContext } from 'react';
4
+ import { useRef, forwardRef, useContext, useMemo, useEffect } from 'react';
5
5
  import { View } from 'react-native';
6
6
  import { warn } from '@mpxjs/utils';
7
7
  import { FormContext, RadioGroupContext } from './context';
@@ -9,7 +9,9 @@ import useInnerProps, { getCustomEvent } from './getInnerListeners';
9
9
  import useNodesRef from './useNodesRef';
10
10
  import { useLayout, useTransformStyle, wrapChildren } from './utils';
11
11
  const radioGroup = forwardRef((props, ref) => {
12
- const { style = {}, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, bindchange } = props;
12
+ const { style = {}, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
13
+ const propsRef = useRef({});
14
+ propsRef.current = props;
13
15
  const formContext = useContext(FormContext);
14
16
  let formValuesMap;
15
17
  if (formContext) {
@@ -28,16 +30,13 @@ const radioGroup = forwardRef((props, ref) => {
28
30
  const nodeRef = useRef(null);
29
31
  useNodesRef(props, ref, nodeRef, { defaultStyle });
30
32
  const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
31
- const getSelectionValue = () => {
33
+ const getValue = () => {
32
34
  for (const key in groupValue) {
33
35
  if (groupValue[key].checked) {
34
36
  return key;
35
37
  }
36
38
  }
37
39
  };
38
- const getValue = () => {
39
- return getSelectionValue();
40
- };
41
40
  const resetValue = () => {
42
41
  Object.keys(groupValue).forEach((key) => {
43
42
  groupValue[key].checked = false;
@@ -52,15 +51,29 @@ const radioGroup = forwardRef((props, ref) => {
52
51
  formValuesMap.set(props.name, { getValue, resetValue });
53
52
  }
54
53
  }
55
- const notifyChange = (evt) => {
56
- bindchange &&
57
- bindchange(getCustomEvent('tap', evt, {
58
- layoutRef,
59
- detail: {
60
- value: getSelectionValue()
61
- }
62
- }, props));
63
- };
54
+ useEffect(() => {
55
+ return () => {
56
+ if (formValuesMap && props.name) {
57
+ formValuesMap.delete(props.name);
58
+ }
59
+ };
60
+ }, []);
61
+ const contextValue = useMemo(() => {
62
+ const notifyChange = (evt) => {
63
+ const { bindchange } = propsRef.current;
64
+ bindchange &&
65
+ bindchange(getCustomEvent('tap', evt, {
66
+ layoutRef,
67
+ detail: {
68
+ value: getValue()
69
+ }
70
+ }, propsRef.current));
71
+ };
72
+ return {
73
+ groupValue,
74
+ notifyChange
75
+ };
76
+ }, []);
64
77
  const innerProps = useInnerProps(props, {
65
78
  ref: nodeRef,
66
79
  style: { ...normalStyle, ...layoutStyle },
@@ -69,7 +82,7 @@ const radioGroup = forwardRef((props, ref) => {
69
82
  layoutRef
70
83
  });
71
84
  return (<View {...innerProps}>
72
- <RadioGroupContext.Provider value={{ groupValue, notifyChange }}>
85
+ <RadioGroupContext.Provider value={contextValue}>
73
86
  {wrapChildren(props, {
74
87
  hasVarDec,
75
88
  varContext: varContextRef.current
@@ -77,5 +90,5 @@ const radioGroup = forwardRef((props, ref) => {
77
90
  </RadioGroupContext.Provider>
78
91
  </View>);
79
92
  });
80
- radioGroup.displayName = 'mpx-radio-group';
93
+ radioGroup.displayName = 'MpxRadioGroup';
81
94
  export default radioGroup;
@@ -151,5 +151,5 @@ const Radio = forwardRef((radioProps, ref) => {
151
151
  })}
152
152
  </View>);
153
153
  });
154
- Radio.displayName = 'mpx-radio';
154
+ Radio.displayName = 'MpxRadio';
155
155
  export default Radio;
@@ -11,5 +11,5 @@ const _RootPortal = (props) => {
11
11
  </Portal>
12
12
  : <>{children}</>;
13
13
  };
14
- _RootPortal.displayName = 'mpx-root-portal';
14
+ _RootPortal.displayName = 'MpxRootPortal';
15
15
  export default _RootPortal;