@mpxjs/webpack-plugin 2.9.67 → 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 (48) hide show
  1. package/lib/index.js +13 -8
  2. package/lib/platform/template/wx/component-config/canvas.js +8 -0
  3. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  4. package/lib/react/processStyles.js +14 -4
  5. package/lib/resolver/AddModePlugin.js +8 -8
  6. package/lib/runtime/components/react/context.ts +2 -0
  7. package/lib/runtime/components/react/dist/context.js +1 -0
  8. package/lib/runtime/components/react/dist/getInnerListeners.js +3 -12
  9. package/lib/runtime/components/react/dist/mpx-button.jsx +43 -8
  10. package/lib/runtime/components/react/dist/mpx-canvas/Bus.js +60 -0
  11. package/lib/runtime/components/react/dist/mpx-canvas/CanvasGradient.js +15 -0
  12. package/lib/runtime/components/react/dist/mpx-canvas/CanvasRenderingContext2D.js +84 -0
  13. package/lib/runtime/components/react/dist/mpx-canvas/Image.js +87 -0
  14. package/lib/runtime/components/react/dist/mpx-canvas/ImageData.js +15 -0
  15. package/lib/runtime/components/react/dist/mpx-canvas/constructorsRegistry.js +28 -0
  16. package/lib/runtime/components/react/dist/mpx-canvas/html.js +343 -0
  17. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +214 -0
  18. package/lib/runtime/components/react/dist/mpx-canvas/utils.jsx +89 -0
  19. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +143 -84
  20. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +69 -113
  21. package/lib/runtime/components/react/dist/mpx-view.jsx +45 -26
  22. package/lib/runtime/components/react/dist/mpx-web-view.jsx +19 -5
  23. package/lib/runtime/components/react/dist/pickerFaces.js +75 -0
  24. package/lib/runtime/components/react/dist/pickerOverlay.jsx +21 -0
  25. package/lib/runtime/components/react/dist/utils.jsx +54 -3
  26. package/lib/runtime/components/react/getInnerListeners.ts +3 -17
  27. package/lib/runtime/components/react/mpx-button.tsx +41 -8
  28. package/lib/runtime/components/react/mpx-canvas/Bus.ts +70 -0
  29. package/lib/runtime/components/react/mpx-canvas/CanvasGradient.ts +18 -0
  30. package/lib/runtime/components/react/mpx-canvas/CanvasRenderingContext2D.ts +87 -0
  31. package/lib/runtime/components/react/mpx-canvas/Image.ts +102 -0
  32. package/lib/runtime/components/react/mpx-canvas/ImageData.ts +23 -0
  33. package/lib/runtime/components/react/mpx-canvas/constructorsRegistry.ts +38 -0
  34. package/lib/runtime/components/react/mpx-canvas/html.ts +343 -0
  35. package/lib/runtime/components/react/mpx-canvas/index.tsx +302 -0
  36. package/lib/runtime/components/react/mpx-canvas/utils.tsx +150 -0
  37. package/lib/runtime/components/react/mpx-picker-view-column.tsx +232 -103
  38. package/lib/runtime/components/react/mpx-picker-view.tsx +126 -122
  39. package/lib/runtime/components/react/mpx-view.tsx +57 -27
  40. package/lib/runtime/components/react/mpx-web-view.tsx +22 -5
  41. package/lib/runtime/components/react/pickerFaces.ts +104 -0
  42. package/lib/runtime/components/react/pickerOverlay.tsx +32 -0
  43. package/lib/runtime/components/react/types/common.ts +2 -0
  44. package/lib/runtime/components/react/types/global.d.ts +2 -0
  45. package/lib/runtime/components/react/utils.tsx +78 -7
  46. package/lib/template-compiler/compiler.js +3 -2
  47. package/lib/template-compiler/gen-node-react.js +2 -2
  48. package/package.json +5 -4
@@ -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;
@@ -10,7 +10,7 @@ import useInnerProps from './getInnerListeners';
10
10
  import Animated from 'react-native-reanimated';
11
11
  import useAnimationHooks from './useAnimationHooks';
12
12
  import useNodesRef from './useNodesRef';
13
- import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout } from './utils';
13
+ import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout, renderImage, pickStyle } from './utils';
14
14
  import LinearGradient from 'react-native-linear-gradient';
15
15
  const linearMap = new Map([
16
16
  ['top', 0],
@@ -201,7 +201,7 @@ function backgroundSize(imageProps, preImageInfo, imageSize, layoutInfo) {
201
201
  }
202
202
  else { // 数值类型 ImageStyle
203
203
  // 数值类型设置为 stretch
204
- imageProps.style.resizeMode = 'stretch';
204
+ imageProps.resizeMode = 'stretch';
205
205
  dimensions = {
206
206
  width: isPercent(width) ? width : +width,
207
207
  height: isPercent(height) ? height : +height
@@ -216,8 +216,9 @@ function backgroundSize(imageProps, preImageInfo, imageSize, layoutInfo) {
216
216
  }
217
217
  // background-image转换为source
218
218
  function backgroundImage(imageProps, preImageInfo) {
219
- if (preImageInfo.src) {
220
- imageProps.src = preImageInfo.src;
219
+ const src = preImageInfo.src;
220
+ if (src) {
221
+ imageProps.source = { uri: src };
221
222
  }
222
223
  }
223
224
  // 渐变的转换
@@ -241,8 +242,8 @@ function linearGradient(imageProps, preImageInfo, imageSize, layoutInfo) {
241
242
  const imageStyleToProps = (preImageInfo, imageSize, layoutInfo) => {
242
243
  // 初始化
243
244
  const imageProps = {
245
+ resizeMode: 'cover',
244
246
  style: {
245
- resizeMode: 'cover',
246
247
  position: 'absolute'
247
248
  // ...StyleSheet.absoluteFillObject
248
249
  },
@@ -430,7 +431,23 @@ function preParseImage(imageStyle) {
430
431
  function isDiagonalAngle(linearInfo) {
431
432
  return !!(linearInfo?.direction && diagonalAngleMap[linearInfo.direction]);
432
433
  }
433
- function wrapImage(imageStyle) {
434
+ function inheritStyle(innerStyle = {}) {
435
+ const { borderWidth, borderRadius } = innerStyle;
436
+ const borderStyles = ['borderRadius', 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius'];
437
+ return pickStyle(innerStyle, borderStyles, borderWidth && borderRadius
438
+ ? (key, val) => {
439
+ // 盒子内圆角borderWith与borderRadius的关系
440
+ // 当borderRadius 小于 当borderWith 内边框为直角
441
+ // 当borderRadius 大于等于 当borderWith 内边框为圆角
442
+ if (borderStyles.includes(key)) {
443
+ const borderVal = +val - borderWidth;
444
+ return borderVal > 0 ? borderVal : 0;
445
+ }
446
+ return val;
447
+ }
448
+ : undefined);
449
+ }
450
+ function wrapImage(imageStyle, innerStyle, enableFastImage) {
434
451
  // 预处理数据
435
452
  const preImageInfo = preParseImage(imageStyle);
436
453
  // 预解析
@@ -510,12 +527,12 @@ function wrapImage(imageStyle) {
510
527
  setShow(true);
511
528
  }
512
529
  };
513
- return <View key='backgroundImage' {...needLayout ? { onLayout } : null} style={{ ...StyleSheet.absoluteFillObject, overflow: 'hidden' }}>
530
+ return <View key='backgroundImage' {...needLayout ? { onLayout } : null} style={{ ...inheritStyle(innerStyle), ...StyleSheet.absoluteFillObject, overflow: 'hidden' }}>
514
531
  {show && type === 'linear' && <LinearGradient useAngle={true} {...imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current)}/>}
515
- {show && type === 'image' && <Image {...imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current)}/>}
532
+ {show && type === 'image' && (renderImage(imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current), enableFastImage))}
516
533
  </View>;
517
534
  }
518
- function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backgroundStyle, varContext, textProps }) {
535
+ function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backgroundStyle, varContext, textProps, innerStyle, enableFastImage }) {
519
536
  const children = wrapChildren(props, {
520
537
  hasVarDec,
521
538
  varContext,
@@ -523,13 +540,13 @@ function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backg
523
540
  textProps
524
541
  });
525
542
  return [
526
- enableBackground ? wrapImage(backgroundStyle) : null,
543
+ enableBackground ? wrapImage(backgroundStyle, innerStyle, enableFastImage) : null,
527
544
  children
528
545
  ];
529
546
  }
530
547
  const _View = forwardRef((viewProps, ref) => {
531
548
  const { textProps, innerProps: props = {} } = splitProps(viewProps);
532
- let { style = {}, 'hover-style': hoverStyle, 'hover-start-time': hoverStartTime = 50, 'hover-stay-time': hoverStayTime = 400, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'enable-background': enableBackground, 'enable-animation': enableAnimation, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, animation } = props;
549
+ let { style = {}, 'hover-style': hoverStyle, 'hover-start-time': hoverStartTime = 50, 'hover-stay-time': hoverStayTime = 400, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'enable-background': enableBackground, 'enable-fast-image': enableFastImage, 'enable-animation': enableAnimation, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, animation } = props;
533
550
  const [isHover, setIsHover] = useState(false);
534
551
  // 默认样式
535
552
  const defaultStyle = {
@@ -595,9 +612,20 @@ const _View = forwardRef((viewProps, ref) => {
595
612
  }
596
613
  const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
597
614
  const viewStyle = Object.assign({}, innerStyle, layoutStyle);
615
+ enableAnimation = enableAnimation || !!animation;
616
+ const enableAnimationRef = useRef(enableAnimation);
617
+ if (enableAnimationRef.current !== enableAnimation) {
618
+ throw new Error('[Mpx runtime error]: animation use should be stable in the component lifecycle, or you can set [enable-animation] with true.');
619
+ }
620
+ const finalStyle = enableAnimation
621
+ ? useAnimationHooks({
622
+ animation,
623
+ style: viewStyle
624
+ })
625
+ : viewStyle;
598
626
  const innerProps = useInnerProps(props, {
599
627
  ref: nodeRef,
600
- style: viewStyle,
628
+ style: finalStyle,
601
629
  ...layoutProps,
602
630
  ...(hoverStyle && {
603
631
  bindtouchstart: onTouchStart,
@@ -611,27 +639,18 @@ const _View = forwardRef((viewProps, ref) => {
611
639
  ], {
612
640
  layoutRef
613
641
  });
614
- enableAnimation = enableAnimation || !!animation;
615
- const enableAnimationRef = useRef(enableAnimation);
616
- if (enableAnimationRef.current !== enableAnimation) {
617
- throw new Error('[Mpx runtime error]: animation use should be stable in the component lifecycle, or you can set [enable-animation] with true.');
618
- }
619
- const finalStyle = enableAnimation
620
- ? useAnimationHooks({
621
- animation,
622
- style: viewStyle
623
- })
624
- : viewStyle;
625
642
  const childNode = wrapWithChildren(props, {
626
643
  hasVarDec,
627
644
  enableBackground: enableBackgroundRef.current,
628
645
  textStyle,
629
646
  backgroundStyle,
630
647
  varContext: varContextRef.current,
631
- textProps
648
+ textProps,
649
+ innerStyle,
650
+ enableFastImage
632
651
  });
633
- return animation?.actions?.length
634
- ? (<Animated.View {...innerProps} style={finalStyle}>
652
+ return enableAnimation
653
+ ? (<Animated.View {...innerProps}>
635
654
  {childNode}
636
655
  </Animated.View>)
637
656
  : (<View {...innerProps}>