@mpxjs/webpack-plugin 2.9.69-beta.0 → 2.9.69-beta.10
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.
- package/lib/config.js +3 -1
- package/lib/index.js +17 -1
- package/lib/platform/style/wx/index.js +18 -18
- package/lib/platform/template/wx/component-config/movable-view.js +8 -1
- package/lib/platform/template/wx/component-config/scroll-view.js +1 -1
- package/lib/platform/template/wx/index.js +3 -1
- package/lib/react/processScript.js +6 -4
- package/lib/resolver/AddEnvPlugin.js +1 -0
- package/lib/resolver/AddModePlugin.js +1 -0
- package/lib/runtime/components/react/context.ts +25 -0
- package/lib/runtime/components/react/dist/context.js +4 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +5 -6
- package/lib/runtime/components/react/dist/locale-provider.jsx +15 -0
- package/lib/runtime/components/react/dist/mpx-button.jsx +16 -44
- package/lib/runtime/components/react/dist/mpx-image.jsx +13 -9
- package/lib/runtime/components/react/dist/mpx-input.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +72 -57
- package/lib/runtime/components/react/dist/mpx-picker-view.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-portal/portal-consumer.jsx +23 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +93 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +40 -0
- package/lib/runtime/components/react/dist/mpx-portal.jsx +13 -0
- package/lib/runtime/components/react/dist/mpx-provider.jsx +31 -0
- package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +10 -11
- package/lib/runtime/components/react/dist/mpx-root-portal.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +18 -9
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +31 -8
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +437 -372
- package/lib/runtime/components/react/dist/mpx-view.jsx +18 -53
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +163 -49
- package/lib/runtime/components/react/dist/pickerFaces.js +3 -8
- package/lib/runtime/components/react/dist/useAnimationHooks.js +31 -14
- package/lib/runtime/components/react/dist/utils.jsx +120 -4
- package/lib/runtime/components/react/getInnerListeners.ts +5 -7
- package/lib/runtime/components/react/locale-provider.tsx +83 -0
- package/lib/runtime/components/react/mpx-button.tsx +20 -57
- package/lib/runtime/components/react/mpx-image.tsx +41 -25
- package/lib/runtime/components/react/mpx-input.tsx +1 -1
- package/lib/runtime/components/react/mpx-movable-view.tsx +1 -1
- package/lib/runtime/components/react/mpx-picker/time.tsx +2 -1
- package/lib/runtime/components/react/mpx-picker-view-column-item.tsx +88 -0
- package/lib/runtime/components/react/mpx-picker-view-column.tsx +196 -163
- package/lib/runtime/components/react/mpx-picker-view.tsx +35 -37
- package/lib/runtime/components/react/mpx-portal/portal-consumer.tsx +32 -0
- package/lib/runtime/components/react/mpx-portal/portal-host.tsx +127 -0
- package/lib/runtime/components/react/mpx-portal/portal-manager.tsx +64 -0
- package/lib/runtime/components/react/mpx-portal.tsx +30 -0
- package/lib/runtime/components/react/mpx-provider.tsx +51 -0
- package/lib/runtime/components/react/mpx-rich-text/index.tsx +12 -18
- package/lib/runtime/components/react/mpx-root-portal.tsx +1 -1
- package/lib/runtime/components/react/mpx-scroll-view.tsx +29 -18
- package/lib/runtime/components/react/mpx-swiper-item.tsx +45 -11
- package/lib/runtime/components/react/mpx-swiper.tsx +743 -0
- package/lib/runtime/components/react/mpx-view.tsx +22 -65
- package/lib/runtime/components/react/mpx-web-view.tsx +199 -47
- package/lib/runtime/components/react/pickerFaces.ts +10 -7
- package/lib/runtime/components/react/pickerVIewContext.ts +18 -0
- package/lib/runtime/components/react/pickerViewMask.tsx +30 -0
- package/lib/runtime/components/react/{pickerOverlay.tsx → pickerViewOverlay.tsx} +5 -3
- package/lib/runtime/components/react/types/global.d.ts +10 -1
- package/lib/runtime/components/react/useAnimationHooks.ts +35 -15
- package/lib/runtime/components/react/utils.tsx +139 -5
- package/lib/style-compiler/index.js +3 -4
- package/lib/style-compiler/strip-conditional-loader.js +118 -0
- package/lib/template-compiler/compiler.js +10 -15
- package/lib/utils/pre-process-json.js +5 -9
- package/lib/wxss/loader.js +15 -2
- package/package.json +1 -1
- package/lib/runtime/components/react/mpx-swiper/carouse.tsx +0 -527
- package/lib/runtime/components/react/mpx-swiper/index.tsx +0 -80
- package/lib/runtime/components/react/mpx-swiper/type.ts +0 -87
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import React, { forwardRef, useRef, useState, useMemo, useEffect, useCallback } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { SafeAreaView, StyleSheet } from 'react-native';
|
|
3
3
|
import Reanimated, { useAnimatedRef, useScrollViewOffset } from 'react-native-reanimated';
|
|
4
|
-
import {
|
|
5
|
-
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious } from './utils';
|
|
4
|
+
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, isIOS, useDebounceCallback, useStableCallback } from './utils';
|
|
6
5
|
import useNodesRef from './useNodesRef';
|
|
7
6
|
import PickerOverlay from './pickerViewOverlay';
|
|
8
7
|
import PickerMask from './pickerViewMask';
|
|
@@ -21,14 +20,12 @@ 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);
|
|
28
|
+
const timerScrollTo = useRef(null);
|
|
32
29
|
const activeIndex = useRef(initialIndex);
|
|
33
30
|
const prevIndex = usePrevious(initialIndex);
|
|
34
31
|
const prevMaxIndex = usePrevious(maxIndex);
|
|
@@ -39,13 +36,9 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
39
36
|
setHeight,
|
|
40
37
|
nodeRef: scrollViewRef
|
|
41
38
|
});
|
|
42
|
-
// console.log('[mpx-picker-view-column], render ---> columnIndex=', columnIndex, 'initialIndex=', initialIndex, 'columnData=', columnData.length)
|
|
43
|
-
|
|
44
|
-
// x: 0,
|
|
45
|
-
// y: itemRawH * initialIndex
|
|
46
|
-
// }), [itemRawH])
|
|
39
|
+
// console.log('[mpx-picker-view-column], render ---> columnIndex=', columnIndex, 'initialIndex=', initialIndex, 'columnData=', columnData.length, 'pickerH=', pickerH, 'itemRawH=', itemRawH, 'itemHeight=', itemHeight)
|
|
40
|
+
const paddingHeight = useMemo(() => Math.round((pickerH - itemHeight) / 2), [pickerH, itemHeight]);
|
|
47
41
|
const snapToOffsets = useMemo(() => columnData.map((_, i) => i * itemRawH), [columnData, itemRawH]);
|
|
48
|
-
const paddingHeight = useMemo(() => Math.round((pickerH - itemRawH) / 2), [pickerH, itemRawH]);
|
|
49
42
|
const contentContainerStyle = useMemo(() => {
|
|
50
43
|
return [{ paddingVertical: paddingHeight }];
|
|
51
44
|
}, [paddingHeight]);
|
|
@@ -53,6 +46,37 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
53
46
|
const calc = Math.round(y / itemRawH);
|
|
54
47
|
return Math.max(0, Math.min(calc, maxIndex));
|
|
55
48
|
}, [itemRawH, maxIndex]);
|
|
49
|
+
const getYofIndex = useCallback((index) => {
|
|
50
|
+
return index * itemRawH;
|
|
51
|
+
}, [itemRawH]);
|
|
52
|
+
const stableResetScrollPosition = useStableCallback((y) => {
|
|
53
|
+
// console.log('[mpx-picker-view-column], reset --->', 'columnIndex=', columnIndex, 'y=', y, touching.current, scrolling.current, itemRawH, 'snapToOffsets=', snapToOffsets)
|
|
54
|
+
if (touching.current || scrolling.current) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// needReset.current = true
|
|
58
|
+
if (y % itemRawH !== 0) {
|
|
59
|
+
scrolling.current = true;
|
|
60
|
+
const targetIndex = getIndex(y);
|
|
61
|
+
const targetY = getYofIndex(targetIndex);
|
|
62
|
+
scrollViewRef.current?.scrollTo({ x: 0, y: targetY, animated: false });
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
onMomentumScrollEnd({ nativeEvent: { contentOffset: { y } } });
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
const debounceResetScrollPosition = useDebounceCallback(stableResetScrollPosition, 10);
|
|
69
|
+
const clearTimerScrollTo = () => {
|
|
70
|
+
if (timerScrollTo.current) {
|
|
71
|
+
clearTimeout(timerScrollTo.current);
|
|
72
|
+
timerScrollTo.current = null;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
return () => {
|
|
77
|
+
clearTimerScrollTo();
|
|
78
|
+
};
|
|
79
|
+
}, []);
|
|
56
80
|
useEffect(() => {
|
|
57
81
|
if (!scrollViewRef.current ||
|
|
58
82
|
!itemRawH ||
|
|
@@ -64,80 +88,70 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
64
88
|
maxIndex !== prevMaxIndex) {
|
|
65
89
|
return;
|
|
66
90
|
}
|
|
67
|
-
|
|
68
|
-
setTimeout(() => {
|
|
91
|
+
clearTimerScrollTo();
|
|
92
|
+
timerScrollTo.current = setTimeout(() => {
|
|
69
93
|
scrollViewRef.current?.scrollTo({
|
|
70
94
|
x: 0,
|
|
71
|
-
y:
|
|
95
|
+
y: getYofIndex(initialIndex),
|
|
72
96
|
animated: false
|
|
73
97
|
});
|
|
74
|
-
}, 0);
|
|
98
|
+
}, isAndroid ? 200 : 0);
|
|
75
99
|
activeIndex.current = initialIndex;
|
|
76
100
|
}, [itemRawH, initialIndex]);
|
|
77
101
|
const onContentSizeChange = (_w, h) => {
|
|
78
|
-
const y =
|
|
79
|
-
// console.log('[mpx-picker-view-column], onContentSizeChange --->', 'columnIndex=', columnIndex, '_w=', _w, 'h=', h, 'y=', y)
|
|
102
|
+
const y = getYofIndex(initialIndex);
|
|
80
103
|
if (y <= h) {
|
|
81
|
-
|
|
104
|
+
clearTimerScrollTo();
|
|
105
|
+
timerScrollTo.current = setTimeout(() => {
|
|
82
106
|
scrollViewRef.current?.scrollTo({ x: 0, y, animated: false });
|
|
83
107
|
}, 0);
|
|
84
108
|
}
|
|
85
109
|
};
|
|
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
110
|
const onItemLayout = (e) => {
|
|
105
111
|
const { height: rawH } = e.nativeEvent.layout;
|
|
106
|
-
|
|
107
|
-
|
|
112
|
+
const roundedH = Math.round(rawH);
|
|
113
|
+
if (roundedH && roundedH !== itemRawH) {
|
|
114
|
+
setItemRawH(roundedH);
|
|
108
115
|
}
|
|
109
116
|
};
|
|
110
|
-
const
|
|
117
|
+
const onScrollBeginDrag = () => {
|
|
118
|
+
isIOS && debounceResetScrollPosition.clear();
|
|
111
119
|
touching.current = true;
|
|
112
120
|
prevScrollingInfo.current = {
|
|
113
121
|
index: activeIndex.current,
|
|
114
|
-
y: activeIndex.current
|
|
122
|
+
y: getYofIndex(activeIndex.current)
|
|
115
123
|
};
|
|
116
124
|
};
|
|
117
|
-
const
|
|
118
|
-
touching.current = false;
|
|
119
|
-
};
|
|
120
|
-
const onTouchCancel = () => {
|
|
125
|
+
const onScrollEndDrag = (e) => {
|
|
121
126
|
touching.current = false;
|
|
127
|
+
const { y } = e.nativeEvent.contentOffset;
|
|
128
|
+
if (isIOS) {
|
|
129
|
+
if (y >= 0 && y <= snapToOffsets[maxIndex]) {
|
|
130
|
+
debounceResetScrollPosition(y);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
122
133
|
};
|
|
123
134
|
const onMomentumScrollBegin = () => {
|
|
135
|
+
isIOS && debounceResetScrollPosition.clear();
|
|
124
136
|
scrolling.current = true;
|
|
125
137
|
};
|
|
126
138
|
const onMomentumScrollEnd = (e) => {
|
|
127
139
|
scrolling.current = false;
|
|
128
|
-
if (!itemRawH) {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
140
|
const { y: scrollY } = e.nativeEvent.contentOffset;
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
141
|
+
// console.log('[mpx-picker-view-column], onMomentumScrollEnd --->', 'columnIndex=', columnIndex, scrollY, itemRawH)
|
|
142
|
+
if (isIOS && scrollY % itemRawH !== 0) {
|
|
143
|
+
return debounceResetScrollPosition(scrollY);
|
|
144
|
+
}
|
|
145
|
+
const calcIndex = getIndex(scrollY);
|
|
146
|
+
if (calcIndex !== activeIndex.current) {
|
|
147
|
+
activeIndex.current = calcIndex;
|
|
136
148
|
onSelectChange(calcIndex);
|
|
137
149
|
}
|
|
138
150
|
};
|
|
139
151
|
const onScroll = (e) => {
|
|
140
|
-
|
|
152
|
+
// 全局注册的振动触感 hook
|
|
153
|
+
const pickerVibrate = global.__mpx?.config?.rnConfig?.pickerVibrate;
|
|
154
|
+
if (typeof pickerVibrate !== 'function') {
|
|
141
155
|
return;
|
|
142
156
|
}
|
|
143
157
|
const { y } = e.nativeEvent.contentOffset;
|
|
@@ -148,19 +162,20 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
148
162
|
if (currentId !== prevIndex) {
|
|
149
163
|
prevScrollingInfo.current = {
|
|
150
164
|
index: currentId,
|
|
151
|
-
y: currentId
|
|
165
|
+
y: getYofIndex(currentId)
|
|
152
166
|
};
|
|
153
|
-
vibrateShort({ type: 'selection' })
|
|
167
|
+
// vibrateShort({ type: 'selection' })
|
|
168
|
+
pickerVibrate();
|
|
154
169
|
}
|
|
155
170
|
}
|
|
156
171
|
}
|
|
157
172
|
};
|
|
158
173
|
const renderInnerchild = () => columnData.map((item, index) => {
|
|
159
|
-
return (<MpxPickerVIewColumnItem key={index} item={item} index={index} itemHeight={itemHeight}
|
|
174
|
+
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
175
|
});
|
|
161
176
|
const renderScollView = () => {
|
|
162
177
|
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:
|
|
178
|
+
<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
179
|
{renderInnerchild()}
|
|
165
180
|
</Reanimated.ScrollView>
|
|
166
181
|
</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
|
|
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();
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { getFocusedNavigation } from '@mpxjs/utils';
|
|
3
|
+
const PortalConsumer = ({ manager, children }) => {
|
|
4
|
+
const keyRef = useRef(null);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
const navigation = getFocusedNavigation();
|
|
7
|
+
const curPageId = navigation?.pageId;
|
|
8
|
+
manager.update(keyRef.current, children, curPageId);
|
|
9
|
+
}, [children]);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!manager) {
|
|
12
|
+
throw new Error('Looks like you forgot to wrap your root component with `Provider` component from `@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-portal`.\n\n');
|
|
13
|
+
}
|
|
14
|
+
const navigation = getFocusedNavigation();
|
|
15
|
+
const curPageId = navigation?.pageId;
|
|
16
|
+
keyRef.current = manager.mount(children, undefined, curPageId);
|
|
17
|
+
return () => {
|
|
18
|
+
manager.unmount(keyRef.current);
|
|
19
|
+
};
|
|
20
|
+
}, []);
|
|
21
|
+
return null;
|
|
22
|
+
};
|
|
23
|
+
export default PortalConsumer;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { View, DeviceEventEmitter, NativeEventEmitter, StyleSheet } from 'react-native';
|
|
3
|
+
import PortalManager from './portal-manager';
|
|
4
|
+
import { getFocusedNavigation } from '@mpxjs/utils';
|
|
5
|
+
import { PortalContext } from '../context';
|
|
6
|
+
// events
|
|
7
|
+
const addType = 'MPX_RN_ADD_PORTAL';
|
|
8
|
+
const removeType = 'MPX_RN_REMOVE_PORTAL';
|
|
9
|
+
const updateType = 'MPX_RN_UPDATE_PORTAL';
|
|
10
|
+
// fix react native web does not support DeviceEventEmitter
|
|
11
|
+
const TopViewEventEmitter = DeviceEventEmitter || new NativeEventEmitter();
|
|
12
|
+
const styles = StyleSheet.create({
|
|
13
|
+
container: {
|
|
14
|
+
flex: 1
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
class PortalGuard {
|
|
18
|
+
nextKey = 10000;
|
|
19
|
+
add = (e) => {
|
|
20
|
+
const key = this.nextKey++;
|
|
21
|
+
TopViewEventEmitter.emit(addType, e, key);
|
|
22
|
+
return key;
|
|
23
|
+
};
|
|
24
|
+
remove = (key) => {
|
|
25
|
+
TopViewEventEmitter.emit(removeType, key);
|
|
26
|
+
};
|
|
27
|
+
update = (key, e) => {
|
|
28
|
+
TopViewEventEmitter.emit(updateType, key, e);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* portal
|
|
33
|
+
*/
|
|
34
|
+
export const portal = new PortalGuard();
|
|
35
|
+
const PortalHost = ({ children }) => {
|
|
36
|
+
const _nextKey = useRef(0);
|
|
37
|
+
const _queue = useRef([]);
|
|
38
|
+
const _addType = useRef(null);
|
|
39
|
+
const _removeType = useRef(null);
|
|
40
|
+
const _updateType = useRef(null);
|
|
41
|
+
const manager = useRef(null);
|
|
42
|
+
let currentPageId;
|
|
43
|
+
const _mount = (children, _key, curPageId) => {
|
|
44
|
+
const navigation = getFocusedNavigation();
|
|
45
|
+
const pageId = navigation?.pageId;
|
|
46
|
+
if (pageId !== (curPageId ?? currentPageId)) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const key = _key || _nextKey.current++;
|
|
50
|
+
if (manager.current) {
|
|
51
|
+
manager.current.mount(key, children);
|
|
52
|
+
}
|
|
53
|
+
return key;
|
|
54
|
+
};
|
|
55
|
+
const _unmount = (key) => {
|
|
56
|
+
if (manager.current) {
|
|
57
|
+
manager.current.unmount(key);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const _update = (key, children, curPageId) => {
|
|
61
|
+
const navigation = getFocusedNavigation();
|
|
62
|
+
const pageId = navigation?.pageId;
|
|
63
|
+
if (pageId !== (curPageId ?? currentPageId)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (manager.current) {
|
|
67
|
+
manager.current.update(key, children);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
const navigation = getFocusedNavigation();
|
|
72
|
+
currentPageId = navigation?.pageId;
|
|
73
|
+
_addType.current = TopViewEventEmitter.addListener(addType, _mount);
|
|
74
|
+
_removeType.current = TopViewEventEmitter.addListener(removeType, _unmount);
|
|
75
|
+
_updateType.current = TopViewEventEmitter.addListener(updateType, _update);
|
|
76
|
+
return () => {
|
|
77
|
+
_addType.current?.remove();
|
|
78
|
+
_removeType.current?.remove();
|
|
79
|
+
_updateType.current?.remove();
|
|
80
|
+
};
|
|
81
|
+
}, []);
|
|
82
|
+
return (<PortalContext.Provider value={{
|
|
83
|
+
mount: _mount,
|
|
84
|
+
update: _update,
|
|
85
|
+
unmount: _unmount
|
|
86
|
+
}}>
|
|
87
|
+
<View style={styles.container} collapsable={false}>
|
|
88
|
+
{children}
|
|
89
|
+
</View>
|
|
90
|
+
<PortalManager ref={manager}/>
|
|
91
|
+
</PortalContext.Provider>);
|
|
92
|
+
};
|
|
93
|
+
export default PortalHost;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useState, useCallback, forwardRef, useImperativeHandle } from 'react';
|
|
2
|
+
import { View, StyleSheet } from 'react-native';
|
|
3
|
+
const _PortalManager = forwardRef((props, ref) => {
|
|
4
|
+
const [state, setState] = useState({
|
|
5
|
+
portals: []
|
|
6
|
+
});
|
|
7
|
+
const mount = useCallback((key, children) => {
|
|
8
|
+
setState((prevState) => ({
|
|
9
|
+
portals: [...prevState.portals, { key, children }]
|
|
10
|
+
}));
|
|
11
|
+
}, [state]);
|
|
12
|
+
const update = useCallback((key, children) => {
|
|
13
|
+
setState((prevState) => ({
|
|
14
|
+
portals: prevState.portals.map((item) => {
|
|
15
|
+
if (item.key === key) {
|
|
16
|
+
return { ...item, children };
|
|
17
|
+
}
|
|
18
|
+
return item;
|
|
19
|
+
})
|
|
20
|
+
}));
|
|
21
|
+
}, [state]);
|
|
22
|
+
const unmount = useCallback((key) => {
|
|
23
|
+
setState((prevState) => ({
|
|
24
|
+
portals: prevState.portals.filter((item) => item.key !== key)
|
|
25
|
+
}));
|
|
26
|
+
}, []);
|
|
27
|
+
useImperativeHandle(ref, () => ({
|
|
28
|
+
mount,
|
|
29
|
+
update,
|
|
30
|
+
unmount,
|
|
31
|
+
portals: state.portals
|
|
32
|
+
}));
|
|
33
|
+
return (<>
|
|
34
|
+
{state.portals.map(({ key, children }, i) => (<View key={key} collapsable={false} // Need collapsable=false here to clip the elevations
|
|
35
|
+
pointerEvents="box-none" style={[StyleSheet.absoluteFill, { zIndex: 1000 + i }]}>
|
|
36
|
+
{children}
|
|
37
|
+
</View>))}
|
|
38
|
+
</>);
|
|
39
|
+
});
|
|
40
|
+
export default _PortalManager;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PortalContext } from './context';
|
|
2
|
+
import PortalConsumer from './mpx-portal/portal-consumer';
|
|
3
|
+
import PortalHost, { portal } from './mpx-portal/portal-host';
|
|
4
|
+
const Portal = ({ children }) => {
|
|
5
|
+
return (<PortalContext.Consumer>
|
|
6
|
+
{(manager) => (<PortalConsumer manager={manager}>{children}</PortalConsumer>)}
|
|
7
|
+
</PortalContext.Consumer>);
|
|
8
|
+
};
|
|
9
|
+
Portal.Host = PortalHost;
|
|
10
|
+
Portal.add = portal.add;
|
|
11
|
+
Portal.remove = portal.remove;
|
|
12
|
+
Portal.update = portal.update;
|
|
13
|
+
export default Portal;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createContext, useMemo } from 'react';
|
|
2
|
+
import LocaleProvider from './locale-provider';
|
|
3
|
+
import Portal from './mpx-portal';
|
|
4
|
+
import { extendObject } from './utils';
|
|
5
|
+
const defaultTheme = {
|
|
6
|
+
color_text_base: '#000000',
|
|
7
|
+
color_text_base_inverse: '#ffffff',
|
|
8
|
+
color_text_secondary: '#a4a9b0',
|
|
9
|
+
color_text_placeholder: '#bbbbbb',
|
|
10
|
+
color_text_disabled: '#bbbbbb',
|
|
11
|
+
color_text_caption: '#888888',
|
|
12
|
+
color_text_paragraph: '#333333',
|
|
13
|
+
color_error: '#ff4d4f',
|
|
14
|
+
color_warning: '#faad14',
|
|
15
|
+
color_success: '#52c41a',
|
|
16
|
+
color_primary: '#1677ff'
|
|
17
|
+
};
|
|
18
|
+
export const ThemeContext = createContext(defaultTheme);
|
|
19
|
+
const ThemeProvider = (props) => {
|
|
20
|
+
const { value, children } = props;
|
|
21
|
+
const theme = useMemo(() => (extendObject({}, defaultTheme, value)), [value]);
|
|
22
|
+
return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>;
|
|
23
|
+
};
|
|
24
|
+
const Provider = ({ locale, theme, children }) => {
|
|
25
|
+
return (<LocaleProvider locale={locale}>
|
|
26
|
+
<ThemeProvider value={theme}>
|
|
27
|
+
<Portal.Host>{children}</Portal.Host>
|
|
28
|
+
</ThemeProvider>
|
|
29
|
+
</LocaleProvider>);
|
|
30
|
+
};
|
|
31
|
+
export default Provider;
|
|
@@ -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:
|
|
50
|
-
|
|
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 (
|
|
56
|
-
|
|
54
|
+
return createElement(View, innerProps, createElement(WebView, {
|
|
55
|
+
source: { html: generateHTML(html) },
|
|
56
|
+
onMessage: (event) => {
|
|
57
57
|
setWebViewHeight(+event.nativeEvent.data);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
</View>);
|
|
58
|
+
}
|
|
59
|
+
}));
|
|
61
60
|
});
|
|
62
61
|
_RichText.displayName = 'mpx-rich-text';
|
|
63
62
|
export default _RichText;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ✔ enable
|
|
3
3
|
*/
|
|
4
4
|
import { createElement, Fragment } from 'react';
|
|
5
|
-
import
|
|
5
|
+
import Portal from './mpx-portal';
|
|
6
6
|
import { warn } from '@mpxjs/utils';
|
|
7
7
|
const _RootPortal = (props) => {
|
|
8
8
|
const { children, enable = true } = props;
|
|
@@ -33,13 +33,13 @@
|
|
|
33
33
|
*/
|
|
34
34
|
import { ScrollView } from 'react-native-gesture-handler';
|
|
35
35
|
import { RefreshControl } from 'react-native';
|
|
36
|
-
import { useRef, useState, useEffect, forwardRef, useContext, createElement } from 'react';
|
|
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');
|
|
@@ -196,11 +201,6 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
196
201
|
layoutRef
|
|
197
202
|
}, props));
|
|
198
203
|
updateScrollOptions(e, { scrollLeft, scrollTop });
|
|
199
|
-
if (enableTriggerIntersectionObserver && intersectionObservers) {
|
|
200
|
-
for (const key in intersectionObservers) {
|
|
201
|
-
intersectionObservers[key].throttleMeasure();
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
204
|
}
|
|
205
205
|
function onScrollEnd(e) {
|
|
206
206
|
const { bindscrollend } = props;
|
|
@@ -219,6 +219,14 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
219
219
|
updateScrollOptions(e, { scrollLeft, scrollTop });
|
|
220
220
|
onStartReached(e);
|
|
221
221
|
onEndReached(e);
|
|
222
|
+
updateIntersection();
|
|
223
|
+
}
|
|
224
|
+
function updateIntersection() {
|
|
225
|
+
if (enableTriggerIntersectionObserver && intersectionObservers) {
|
|
226
|
+
for (const key in intersectionObservers) {
|
|
227
|
+
intersectionObservers[key].throttleMeasure();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
222
230
|
}
|
|
223
231
|
function scrollToOffset(x = 0, y = 0) {
|
|
224
232
|
if (scrollViewRef.current) {
|
|
@@ -277,6 +285,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
277
285
|
function onScrollDrag(e) {
|
|
278
286
|
const { x: scrollLeft, y: scrollTop } = e.nativeEvent.contentOffset;
|
|
279
287
|
updateScrollOptions(e, { scrollLeft, scrollTop });
|
|
288
|
+
updateIntersection();
|
|
280
289
|
}
|
|
281
290
|
const scrollAdditionalProps = extendObject({
|
|
282
291
|
style: extendObject({}, innerStyle, layoutStyle),
|
|
@@ -342,12 +351,12 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
342
351
|
onRefresh: onRefresh
|
|
343
352
|
}, (refresherDefaultStyle && refresherDefaultStyle !== 'none' ? { colors: refreshColor[refresherDefaultStyle] } : null)))
|
|
344
353
|
: undefined
|
|
345
|
-
}), wrapChildren(props, {
|
|
354
|
+
}), createElement(ScrollViewContext.Provider, { value: contextValue }, wrapChildren(props, {
|
|
346
355
|
hasVarDec,
|
|
347
356
|
varContext: varContextRef.current,
|
|
348
357
|
textStyle,
|
|
349
358
|
textProps
|
|
350
|
-
}));
|
|
359
|
+
})));
|
|
351
360
|
});
|
|
352
361
|
_ScrollView.displayName = 'MpxScrollView';
|
|
353
362
|
export default _ScrollView;
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import {
|
|
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;
|
|
13
|
+
const dir = contextValue.dir || 'x';
|
|
8
14
|
const { textProps } = splitProps(props);
|
|
9
15
|
const nodeRef = useRef(null);
|
|
10
16
|
const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext });
|
|
@@ -16,21 +22,38 @@ const _SwiperItem = forwardRef((props, ref) => {
|
|
|
16
22
|
// 存储layout布局信息
|
|
17
23
|
layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: nodeRef });
|
|
18
24
|
const innerProps = useInnerProps(props, {
|
|
19
|
-
style: { ...innerStyle, ...layoutStyle },
|
|
20
25
|
ref: nodeRef,
|
|
21
26
|
...layoutProps
|
|
22
27
|
}, [
|
|
23
28
|
'children',
|
|
24
|
-
'enable-offset'
|
|
29
|
+
'enable-offset',
|
|
30
|
+
'style'
|
|
25
31
|
], { layoutRef });
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
const itemAnimatedStyle = useAnimatedStyle(() => {
|
|
33
|
+
if (!step.value)
|
|
34
|
+
return {};
|
|
35
|
+
const inputRange = [step.value, 0];
|
|
36
|
+
const outputRange = [0.7, 1];
|
|
37
|
+
// 实现元素的宽度跟随step从0到真实宽度,且不能触发重新渲染整个组件,通过AnimatedStyle的方式实现
|
|
38
|
+
const outerLayoutStyle = dir === 'x' ? { width: step.value, height: '100%' } : { width: '100%', height: step.value };
|
|
39
|
+
const transformStyle = [];
|
|
40
|
+
if (scale) {
|
|
41
|
+
transformStyle.push({
|
|
42
|
+
scale: interpolate(Math.abs(Math.abs(offset.value) - itemIndex * step.value), inputRange, outputRange)
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return Object.assign(outerLayoutStyle, {
|
|
46
|
+
transform: transformStyle
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
return (<Animated.View {...innerProps} style={[innerStyle, layoutStyle, itemAnimatedStyle, customStyle]} data-itemId={props['item-id']}>
|
|
50
|
+
{wrapChildren(props, {
|
|
28
51
|
hasVarDec,
|
|
29
52
|
varContext: varContextRef.current,
|
|
30
53
|
textStyle,
|
|
31
54
|
textProps
|
|
32
55
|
})}
|
|
33
|
-
</View>);
|
|
56
|
+
</Animated.View>);
|
|
34
57
|
});
|
|
35
58
|
_SwiperItem.displayName = 'MpxSwiperItem';
|
|
36
59
|
export default _SwiperItem;
|