@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.
Files changed (74) hide show
  1. package/lib/config.js +3 -1
  2. package/lib/index.js +17 -1
  3. package/lib/platform/style/wx/index.js +18 -18
  4. package/lib/platform/template/wx/component-config/movable-view.js +8 -1
  5. package/lib/platform/template/wx/component-config/scroll-view.js +1 -1
  6. package/lib/platform/template/wx/index.js +3 -1
  7. package/lib/react/processScript.js +6 -4
  8. package/lib/resolver/AddEnvPlugin.js +1 -0
  9. package/lib/resolver/AddModePlugin.js +1 -0
  10. package/lib/runtime/components/react/context.ts +25 -0
  11. package/lib/runtime/components/react/dist/context.js +4 -0
  12. package/lib/runtime/components/react/dist/getInnerListeners.js +5 -6
  13. package/lib/runtime/components/react/dist/locale-provider.jsx +15 -0
  14. package/lib/runtime/components/react/dist/mpx-button.jsx +16 -44
  15. package/lib/runtime/components/react/dist/mpx-image.jsx +13 -9
  16. package/lib/runtime/components/react/dist/mpx-input.jsx +1 -1
  17. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +1 -1
  18. package/lib/runtime/components/react/dist/mpx-picker/time.jsx +2 -1
  19. package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +2 -2
  20. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +72 -57
  21. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +1 -1
  22. package/lib/runtime/components/react/dist/mpx-portal/portal-consumer.jsx +23 -0
  23. package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +93 -0
  24. package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +40 -0
  25. package/lib/runtime/components/react/dist/mpx-portal.jsx +13 -0
  26. package/lib/runtime/components/react/dist/mpx-provider.jsx +31 -0
  27. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +10 -11
  28. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +1 -1
  29. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +18 -9
  30. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +31 -8
  31. package/lib/runtime/components/react/dist/mpx-swiper.jsx +437 -372
  32. package/lib/runtime/components/react/dist/mpx-view.jsx +18 -53
  33. package/lib/runtime/components/react/dist/mpx-web-view.jsx +163 -49
  34. package/lib/runtime/components/react/dist/pickerFaces.js +3 -8
  35. package/lib/runtime/components/react/dist/useAnimationHooks.js +31 -14
  36. package/lib/runtime/components/react/dist/utils.jsx +120 -4
  37. package/lib/runtime/components/react/getInnerListeners.ts +5 -7
  38. package/lib/runtime/components/react/locale-provider.tsx +83 -0
  39. package/lib/runtime/components/react/mpx-button.tsx +20 -57
  40. package/lib/runtime/components/react/mpx-image.tsx +41 -25
  41. package/lib/runtime/components/react/mpx-input.tsx +1 -1
  42. package/lib/runtime/components/react/mpx-movable-view.tsx +1 -1
  43. package/lib/runtime/components/react/mpx-picker/time.tsx +2 -1
  44. package/lib/runtime/components/react/mpx-picker-view-column-item.tsx +88 -0
  45. package/lib/runtime/components/react/mpx-picker-view-column.tsx +196 -163
  46. package/lib/runtime/components/react/mpx-picker-view.tsx +35 -37
  47. package/lib/runtime/components/react/mpx-portal/portal-consumer.tsx +32 -0
  48. package/lib/runtime/components/react/mpx-portal/portal-host.tsx +127 -0
  49. package/lib/runtime/components/react/mpx-portal/portal-manager.tsx +64 -0
  50. package/lib/runtime/components/react/mpx-portal.tsx +30 -0
  51. package/lib/runtime/components/react/mpx-provider.tsx +51 -0
  52. package/lib/runtime/components/react/mpx-rich-text/index.tsx +12 -18
  53. package/lib/runtime/components/react/mpx-root-portal.tsx +1 -1
  54. package/lib/runtime/components/react/mpx-scroll-view.tsx +29 -18
  55. package/lib/runtime/components/react/mpx-swiper-item.tsx +45 -11
  56. package/lib/runtime/components/react/mpx-swiper.tsx +743 -0
  57. package/lib/runtime/components/react/mpx-view.tsx +22 -65
  58. package/lib/runtime/components/react/mpx-web-view.tsx +199 -47
  59. package/lib/runtime/components/react/pickerFaces.ts +10 -7
  60. package/lib/runtime/components/react/pickerVIewContext.ts +18 -0
  61. package/lib/runtime/components/react/pickerViewMask.tsx +30 -0
  62. package/lib/runtime/components/react/{pickerOverlay.tsx → pickerViewOverlay.tsx} +5 -3
  63. package/lib/runtime/components/react/types/global.d.ts +10 -1
  64. package/lib/runtime/components/react/useAnimationHooks.ts +35 -15
  65. package/lib/runtime/components/react/utils.tsx +139 -5
  66. package/lib/style-compiler/index.js +3 -4
  67. package/lib/style-compiler/strip-conditional-loader.js +118 -0
  68. package/lib/template-compiler/compiler.js +10 -15
  69. package/lib/utils/pre-process-json.js +5 -9
  70. package/lib/wxss/loader.js +15 -2
  71. package/package.json +1 -1
  72. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +0 -527
  73. package/lib/runtime/components/react/mpx-swiper/index.tsx +0 -80
  74. 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 { Platform, SafeAreaView, StyleSheet } from 'react-native';
2
+ import { SafeAreaView, StyleSheet } from 'react-native';
3
3
  import Reanimated, { useAnimatedRef, useScrollViewOffset } from 'react-native-reanimated';
4
- import { vibrateShort } from '@mpxjs/api-proxy';
5
- import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious } from './utils';
4
+ import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, 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
- // const initialOffset = useMemo(() => ({
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
- // console.log('[mpx-picker-view-column], useEffect ---> columnIndex=', columnIndex, 'initialIndex=', initialIndex, 'y=', itemRawH * initialIndex, `${scrollViewRef.current?.scrollTo}`)
68
- setTimeout(() => {
91
+ clearTimerScrollTo();
92
+ timerScrollTo.current = setTimeout(() => {
69
93
  scrollViewRef.current?.scrollTo({
70
94
  x: 0,
71
- y: itemRawH * initialIndex,
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 = itemRawH * initialIndex;
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
- setTimeout(() => {
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
- if (rawH && itemRawH !== rawH) {
107
- setItemRawH(rawH);
112
+ const roundedH = Math.round(rawH);
113
+ if (roundedH && roundedH !== itemRawH) {
114
+ setItemRawH(roundedH);
108
115
  }
109
116
  };
110
- const onTouchStart = () => {
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 * itemRawH
122
+ y: getYofIndex(activeIndex.current)
115
123
  };
116
124
  };
117
- const onTouchEnd = () => {
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
- let calcIndex = Math.round(scrollY / itemRawH);
133
- activeIndex.current = calcIndex;
134
- if (calcIndex !== initialIndex) {
135
- calcIndex = Math.max(0, Math.min(calcIndex, maxIndex)) || 0;
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
- if (Platform.OS === 'android') {
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 * itemRawH
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} itemWidth={itemRawW} textStyleFromParent={textStyleFromParent} textStyle={textStyle} hasVarDec={hasVarDec} varContext={varContextRef.current} textProps={textProps} visibleCount={visibleCount} onItemLayout={onItemLayout}/>);
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: scrollViewWidth }]} decelerationRate="fast" snapToOffsets={snapToOffsets} onScroll={onScroll} onLayout={onScrollViewLayout} onTouchStart={onTouchStart} onTouchEnd={onTouchEnd} onTouchCancel={onTouchCancel} onMomentumScrollBegin={onMomentumScrollBegin} onMomentumScrollEnd={onMomentumScrollEnd} onContentSizeChange={onContentSizeChange} contentContainerStyle={contentContainerStyle}>
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-1 ===> value=', value);
48
+ console.log('[mpx-picker-view], onInitialChange ===> value=', value);
49
49
  const eventData = getCustomEvent('change', {}, { detail: { value, source: 'change' }, layoutRef });
50
50
  bindchange?.(eventData);
51
51
  snapActiveValueRef.current = value.slice();
@@ -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: { ...normalStyle, ...layoutStyle },
50
- ...layoutProps
51
- }, [], {
49
+ style: extendObject(normalStyle, layoutStyle)
50
+ }, layoutProps), [], {
52
51
  layoutRef
53
52
  });
54
53
  const html = typeof nodes === 'string' ? nodes : jsonToHtmlStr(nodes);
55
- return (<View {...innerProps}>
56
- <WebView source={{ html: generateHTML(html) }} onMessage={(event) => {
54
+ return createElement(View, innerProps, createElement(WebView, {
55
+ source: { html: generateHTML(html) },
56
+ onMessage: (event) => {
57
57
  setWebViewHeight(+event.nativeEvent.data);
58
- }}>
59
- </WebView>
60
- </View>);
58
+ }
59
+ }));
61
60
  });
62
61
  _RichText.displayName = 'mpx-rich-text';
63
62
  export default _RichText;
@@ -2,7 +2,7 @@
2
2
  * ✔ enable
3
3
  */
4
4
  import { createElement, Fragment } from 'react';
5
- import { Portal } from '@ant-design/react-native';
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 { View } from 'react-native';
2
- import { forwardRef, useRef } from 'react';
1
+ import Animated, { useAnimatedStyle, interpolate } from 'react-native-reanimated';
2
+ import { forwardRef, useRef, useContext } from 'react';
3
3
  import useInnerProps from './getInnerListeners';
4
4
  import useNodesRef from './useNodesRef'; // 引入辅助函数
5
5
  import { useTransformStyle, splitStyle, splitProps, wrapChildren, useLayout } from './utils';
6
+ import { SwiperContext } from './context';
6
7
  const _SwiperItem = forwardRef((props, ref) => {
7
- const { 'enable-var': enableVar, 'external-var-context': externalVarContext, style } = props;
8
+ const { 'enable-var': enableVar, 'external-var-context': externalVarContext, style, customStyle, itemIndex } = props;
9
+ const contextValue = useContext(SwiperContext);
10
+ const offset = contextValue.offset || 0;
11
+ const step = contextValue.step || 0;
12
+ const scale = contextValue.scale || false;
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
- return (<View data-itemId={props['item-id']} {...innerProps}>
27
- {wrapChildren(props, {
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;