@mpxjs/webpack-plugin 2.10.7 → 2.10.8
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/dependencies/RecordPageConfigsMapDependency.js +1 -1
- package/lib/dependencies/RequireExternalDependency.js +61 -0
- package/lib/file-loader.js +3 -2
- package/lib/index.js +55 -9
- package/lib/json-compiler/index.js +1 -0
- package/lib/parser.js +1 -1
- package/lib/platform/json/wx/index.js +43 -25
- package/lib/platform/style/wx/index.js +7 -0
- package/lib/platform/template/wx/component-config/fix-component-name.js +2 -2
- package/lib/platform/template/wx/component-config/index.js +5 -1
- package/lib/platform/template/wx/component-config/sticky-header.js +23 -0
- package/lib/platform/template/wx/component-config/sticky-section.js +23 -0
- package/lib/react/LoadAsyncChunkModule.js +74 -0
- package/lib/react/index.js +3 -1
- package/lib/react/processJSON.js +74 -13
- package/lib/react/processScript.js +6 -6
- package/lib/react/script-helper.js +100 -41
- package/lib/runtime/components/react/context.ts +12 -3
- package/lib/runtime/components/react/dist/context.js +4 -1
- package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +135 -0
- package/lib/runtime/components/react/dist/mpx-button.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +8 -6
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +31 -15
- package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +117 -0
- package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +45 -0
- package/lib/runtime/components/react/mpx-async-suspense.tsx +180 -0
- package/lib/runtime/components/react/mpx-button.tsx +3 -2
- package/lib/runtime/components/react/mpx-movable-view.tsx +8 -4
- package/lib/runtime/components/react/mpx-scroll-view.tsx +84 -59
- package/lib/runtime/components/react/mpx-sticky-header.tsx +181 -0
- package/lib/runtime/components/react/mpx-sticky-section.tsx +96 -0
- package/lib/runtime/components/web/mpx-scroll-view.vue +18 -4
- package/lib/runtime/components/web/mpx-sticky-header.vue +99 -0
- package/lib/runtime/components/web/mpx-sticky-section.vue +15 -0
- package/lib/runtime/optionProcessorReact.d.ts +18 -0
- package/lib/runtime/optionProcessorReact.js +30 -0
- package/lib/script-setup-compiler/index.js +27 -5
- package/lib/template-compiler/bind-this.js +2 -1
- package/lib/template-compiler/compiler.js +4 -3
- package/lib/utils/dom-tag-config.js +17 -3
- package/lib/utils/trans-async-sub-rules.js +19 -0
- package/lib/web/script-helper.js +1 -1
- package/package.json +4 -4
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
* ✔ bindscroll
|
|
33
33
|
*/
|
|
34
34
|
import { ScrollView, RefreshControl, Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
35
|
+
import { Animated as RNAnimated } from 'react-native';
|
|
35
36
|
import { isValidElement, Children, useRef, useState, useEffect, forwardRef, useContext, useMemo, createElement } from 'react';
|
|
36
37
|
import Animated, { useAnimatedRef, useSharedValue, withTiming, useAnimatedStyle, runOnJS } from 'react-native-reanimated';
|
|
37
38
|
import { warn, hasOwn } from '@mpxjs/utils';
|
|
@@ -40,9 +41,11 @@ import useNodesRef from './useNodesRef';
|
|
|
40
41
|
import { splitProps, splitStyle, useTransformStyle, useLayout, wrapChildren, extendObject, flatGesture, HIDDEN_STYLE } from './utils';
|
|
41
42
|
import { IntersectionObserverContext, ScrollViewContext } from './context';
|
|
42
43
|
import Portal from './mpx-portal';
|
|
44
|
+
const AnimatedScrollView = RNAnimated.createAnimatedComponent(ScrollView);
|
|
43
45
|
const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
44
46
|
const { textProps, innerProps: props = {} } = splitProps(scrollViewProps);
|
|
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 = false, 'refresher-enabled': refresherEnabled, 'refresher-default-style': refresherDefaultStyle, 'refresher-background': refresherBackground, 'refresher-threshold': refresherThreshold = 45, '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, 'scroll-event-throttle': scrollEventThrottle = 0, __selectRef } = props;
|
|
47
|
+
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 = false, 'refresher-enabled': refresherEnabled, 'refresher-default-style': refresherDefaultStyle, 'refresher-background': refresherBackground, 'refresher-threshold': refresherThreshold = 45, '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, 'enable-sticky': enableSticky, 'scroll-event-throttle': scrollEventThrottle = 0, 'scroll-into-view-offset': scrollIntoViewOffset = 0, __selectRef } = props;
|
|
48
|
+
const scrollOffset = useRef(new RNAnimated.Value(0)).current;
|
|
46
49
|
const simultaneousHandlers = flatGesture(originSimultaneousHandlers);
|
|
47
50
|
const waitForHandlers = flatGesture(waitFor);
|
|
48
51
|
const snapScrollTop = useRef(0);
|
|
@@ -66,7 +69,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
66
69
|
const hasCallScrollToLower = useRef(false);
|
|
67
70
|
const initialTimeout = useRef(null);
|
|
68
71
|
const intersectionObservers = useContext(IntersectionObserverContext);
|
|
69
|
-
const firstScrollIntoViewChange = useRef(
|
|
72
|
+
const firstScrollIntoViewChange = useRef(true);
|
|
70
73
|
const refreshColor = {
|
|
71
74
|
black: ['#000'],
|
|
72
75
|
white: ['#fff']
|
|
@@ -86,16 +89,18 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
86
89
|
pagingEnabled,
|
|
87
90
|
fastDeceleration: false,
|
|
88
91
|
decelerationDisabled: false,
|
|
89
|
-
scrollTo
|
|
92
|
+
scrollTo,
|
|
93
|
+
scrollIntoView: handleScrollIntoView
|
|
90
94
|
},
|
|
91
95
|
gestureRef: scrollViewRef
|
|
92
96
|
});
|
|
97
|
+
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout });
|
|
93
98
|
const contextValue = useMemo(() => {
|
|
94
99
|
return {
|
|
95
|
-
gestureRef: scrollViewRef
|
|
100
|
+
gestureRef: scrollViewRef,
|
|
101
|
+
scrollOffset
|
|
96
102
|
};
|
|
97
103
|
}, []);
|
|
98
|
-
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout });
|
|
99
104
|
const hasRefresherLayoutRef = useRef(false);
|
|
100
105
|
// layout 完成前先隐藏,避免安卓闪烁问题
|
|
101
106
|
const refresherLayoutStyle = useMemo(() => { return !hasRefresherLayoutRef.current ? HIDDEN_STYLE : {}; }, [hasRefresherLayoutRef.current]);
|
|
@@ -115,14 +120,16 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
115
120
|
}, [scrollTop, scrollLeft]);
|
|
116
121
|
useEffect(() => {
|
|
117
122
|
if (scrollIntoView && __selectRef) {
|
|
118
|
-
if (
|
|
119
|
-
setTimeout(
|
|
123
|
+
if (firstScrollIntoViewChange.current) {
|
|
124
|
+
setTimeout(() => {
|
|
125
|
+
handleScrollIntoView(scrollIntoView, { offset: scrollIntoViewOffset, animated: scrollWithAnimation });
|
|
126
|
+
});
|
|
120
127
|
}
|
|
121
128
|
else {
|
|
122
|
-
handleScrollIntoView();
|
|
129
|
+
handleScrollIntoView(scrollIntoView, { offset: scrollIntoViewOffset, animated: scrollWithAnimation });
|
|
123
130
|
}
|
|
124
131
|
}
|
|
125
|
-
firstScrollIntoViewChange.current =
|
|
132
|
+
firstScrollIntoViewChange.current = false;
|
|
126
133
|
}, [scrollIntoView]);
|
|
127
134
|
useEffect(() => {
|
|
128
135
|
if (refresherEnabled) {
|
|
@@ -142,13 +149,15 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
142
149
|
function scrollTo({ top = 0, left = 0, animated = false }) {
|
|
143
150
|
scrollToOffset(left, top, animated);
|
|
144
151
|
}
|
|
145
|
-
function handleScrollIntoView() {
|
|
146
|
-
const refs = __selectRef(`#${
|
|
152
|
+
function handleScrollIntoView(selector = '', { offset = 0, animated = true } = {}) {
|
|
153
|
+
const refs = __selectRef(`#${selector}`, 'node');
|
|
147
154
|
if (!refs)
|
|
148
155
|
return;
|
|
149
156
|
const { nodeRef } = refs.getNodeInstance();
|
|
150
157
|
nodeRef.current?.measureLayout(scrollViewRef.current, (left, top) => {
|
|
151
|
-
|
|
158
|
+
const adjustedLeft = scrollX ? left + offset : left;
|
|
159
|
+
const adjustedTop = scrollY ? top + offset : top;
|
|
160
|
+
scrollToOffset(adjustedLeft, adjustedTop, animated);
|
|
152
161
|
});
|
|
153
162
|
}
|
|
154
163
|
function selectLength(size) {
|
|
@@ -321,6 +330,12 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
321
330
|
updateScrollOptions(e, { scrollLeft, scrollTop });
|
|
322
331
|
updateIntersection();
|
|
323
332
|
}
|
|
333
|
+
const scrollHandler = RNAnimated.event([{ nativeEvent: { contentOffset: { y: scrollOffset } } }], {
|
|
334
|
+
useNativeDriver: true,
|
|
335
|
+
listener: (event) => {
|
|
336
|
+
onScroll(event);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
324
339
|
function onScrollDragStart(e) {
|
|
325
340
|
hasCallScrollToLower.current = false;
|
|
326
341
|
hasCallScrollToUpper.current = false;
|
|
@@ -481,7 +496,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
481
496
|
scrollEnabled: !enableScroll ? false : !!(scrollX || scrollY),
|
|
482
497
|
bounces: false,
|
|
483
498
|
ref: scrollViewRef,
|
|
484
|
-
onScroll: onScroll,
|
|
499
|
+
onScroll: enableSticky ? scrollHandler : onScroll,
|
|
485
500
|
onContentSizeChange: onContentSizeChange,
|
|
486
501
|
bindtouchstart: ((enhanced && binddragstart) || bindtouchstart) && onScrollTouchStart,
|
|
487
502
|
bindtouchmove: ((enhanced && binddragging) || bindtouchmove) && onScrollTouchMove,
|
|
@@ -523,13 +538,14 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
523
538
|
'bindscrolltolower',
|
|
524
539
|
'bindrefresherrefresh'
|
|
525
540
|
], { layoutRef });
|
|
526
|
-
const
|
|
541
|
+
const ScrollViewComponent = enableSticky ? AnimatedScrollView : ScrollView;
|
|
542
|
+
const withRefresherScrollView = createElement(GestureDetector, { gesture: panGesture }, createElement(ScrollViewComponent, innerProps, createElement(Animated.View, { style: [refresherAnimatedStyle, refresherLayoutStyle], onLayout: onRefresherLayout }, refresherContent), createElement(Animated.View, { style: contentAnimatedStyle }, createElement(ScrollViewContext.Provider, { value: contextValue }, wrapChildren(extendObject({}, props, { children: otherContent }), {
|
|
527
543
|
hasVarDec,
|
|
528
544
|
varContext: varContextRef.current,
|
|
529
545
|
textStyle,
|
|
530
546
|
textProps
|
|
531
547
|
})))));
|
|
532
|
-
const commonScrollView = createElement(
|
|
548
|
+
const commonScrollView = createElement(ScrollViewComponent, extendObject({}, innerProps, {
|
|
533
549
|
refreshControl: refresherEnabled
|
|
534
550
|
? createElement(RefreshControl, extendObject({
|
|
535
551
|
progressBackgroundColor: refresherBackground,
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { useEffect, useRef, useContext, forwardRef, useMemo, createElement, useId } from 'react';
|
|
2
|
+
import { Animated, StyleSheet, useAnimatedValue } from 'react-native';
|
|
3
|
+
import { ScrollViewContext, StickyContext } from './context';
|
|
4
|
+
import useNodesRef from './useNodesRef';
|
|
5
|
+
import { splitProps, splitStyle, useTransformStyle, wrapChildren, useLayout, extendObject } from './utils';
|
|
6
|
+
import { error } from '@mpxjs/utils';
|
|
7
|
+
import useInnerProps, { getCustomEvent } from './getInnerListeners';
|
|
8
|
+
const _StickyHeader = forwardRef((stickyHeaderProps = {}, ref) => {
|
|
9
|
+
const { textProps, innerProps: props = {} } = splitProps(stickyHeaderProps);
|
|
10
|
+
const { style, bindstickontopchange, padding = [0, 0, 0, 0], 'offset-top': offsetTop = 0, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
|
|
11
|
+
const scrollViewContext = useContext(ScrollViewContext);
|
|
12
|
+
const stickyContext = useContext(StickyContext);
|
|
13
|
+
const { scrollOffset } = scrollViewContext;
|
|
14
|
+
const { registerStickyHeader, unregisterStickyHeader } = stickyContext;
|
|
15
|
+
const headerRef = useRef(null);
|
|
16
|
+
const isStickOnTopRef = useRef(false);
|
|
17
|
+
const id = useId();
|
|
18
|
+
const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
|
|
19
|
+
const { layoutRef, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: headerRef, onLayout });
|
|
20
|
+
const { textStyle, innerStyle = {} } = splitStyle(normalStyle);
|
|
21
|
+
const headerTopAnimated = useAnimatedValue(0);
|
|
22
|
+
// harmony animatedValue 不支持通过 _value 访问
|
|
23
|
+
const headerTopRef = useRef(0);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
registerStickyHeader({ key: id, updatePosition });
|
|
26
|
+
return () => {
|
|
27
|
+
unregisterStickyHeader(id);
|
|
28
|
+
};
|
|
29
|
+
}, []);
|
|
30
|
+
function updatePosition() {
|
|
31
|
+
if (headerRef.current) {
|
|
32
|
+
const scrollViewRef = scrollViewContext.gestureRef;
|
|
33
|
+
if (scrollViewRef && scrollViewRef.current) {
|
|
34
|
+
headerRef.current.measureLayout(scrollViewRef.current, (left, top) => {
|
|
35
|
+
Animated.timing(headerTopAnimated, {
|
|
36
|
+
toValue: top,
|
|
37
|
+
duration: 0,
|
|
38
|
+
useNativeDriver: true
|
|
39
|
+
}).start();
|
|
40
|
+
headerTopRef.current = top;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
error('StickyHeader measureLayout error: scrollViewRef is not a valid native component reference');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function onLayout(e) {
|
|
49
|
+
updatePosition();
|
|
50
|
+
}
|
|
51
|
+
useNodesRef(props, ref, headerRef, {
|
|
52
|
+
style: normalStyle
|
|
53
|
+
});
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (!bindstickontopchange)
|
|
56
|
+
return;
|
|
57
|
+
const listener = scrollOffset.addListener((state) => {
|
|
58
|
+
const currentScrollValue = state.value;
|
|
59
|
+
const newIsStickOnTop = currentScrollValue > headerTopRef.current;
|
|
60
|
+
if (newIsStickOnTop !== isStickOnTopRef.current) {
|
|
61
|
+
isStickOnTopRef.current = newIsStickOnTop;
|
|
62
|
+
bindstickontopchange(getCustomEvent('stickontopchange', {}, {
|
|
63
|
+
detail: {
|
|
64
|
+
isStickOnTop: newIsStickOnTop
|
|
65
|
+
},
|
|
66
|
+
layoutRef
|
|
67
|
+
}, props));
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return () => {
|
|
71
|
+
scrollOffset.removeListener(listener);
|
|
72
|
+
};
|
|
73
|
+
}, []);
|
|
74
|
+
const animatedStyle = useMemo(() => {
|
|
75
|
+
const translateY = Animated.subtract(scrollOffset, headerTopAnimated).interpolate({
|
|
76
|
+
inputRange: [0, 1],
|
|
77
|
+
outputRange: [0, 1],
|
|
78
|
+
extrapolateLeft: 'clamp',
|
|
79
|
+
extrapolateRight: 'extend'
|
|
80
|
+
});
|
|
81
|
+
const finalTranslateY = offsetTop === 0
|
|
82
|
+
? translateY
|
|
83
|
+
: Animated.add(translateY, Animated.subtract(scrollOffset, headerTopAnimated).interpolate({
|
|
84
|
+
inputRange: [0, 1],
|
|
85
|
+
outputRange: [0, offsetTop],
|
|
86
|
+
extrapolate: 'clamp'
|
|
87
|
+
}));
|
|
88
|
+
return {
|
|
89
|
+
transform: [{ translateY: finalTranslateY }]
|
|
90
|
+
};
|
|
91
|
+
}, [scrollOffset, headerTopAnimated, offsetTop]);
|
|
92
|
+
const innerProps = useInnerProps(extendObject({}, props, {
|
|
93
|
+
ref: headerRef,
|
|
94
|
+
style: extendObject({}, styles.content, innerStyle, animatedStyle, {
|
|
95
|
+
paddingTop: padding[0] || 0,
|
|
96
|
+
paddingRight: padding[1] || 0,
|
|
97
|
+
paddingBottom: padding[2] || 0,
|
|
98
|
+
paddingLeft: padding[3] || 0
|
|
99
|
+
})
|
|
100
|
+
}, layoutProps), [], { layoutRef });
|
|
101
|
+
return (createElement(Animated.View, innerProps, wrapChildren(props, {
|
|
102
|
+
hasVarDec,
|
|
103
|
+
varContext: varContextRef.current,
|
|
104
|
+
textStyle,
|
|
105
|
+
textProps
|
|
106
|
+
})));
|
|
107
|
+
});
|
|
108
|
+
const styles = StyleSheet.create({
|
|
109
|
+
content: {
|
|
110
|
+
width: '100%',
|
|
111
|
+
zIndex: 10,
|
|
112
|
+
// harmony 需要手动设置 relative, zIndex 才生效
|
|
113
|
+
position: 'relative'
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
_StickyHeader.displayName = 'MpxStickyHeader';
|
|
117
|
+
export default _StickyHeader;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useRef, forwardRef, createElement, useCallback, useMemo } from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import useNodesRef from './useNodesRef';
|
|
4
|
+
import { splitProps, splitStyle, useTransformStyle, wrapChildren, useLayout, extendObject } from './utils';
|
|
5
|
+
import { StickyContext } from './context';
|
|
6
|
+
import useInnerProps from './getInnerListeners';
|
|
7
|
+
const _StickySection = forwardRef((stickySectionProps = {}, ref) => {
|
|
8
|
+
const { textProps, innerProps: props = {} } = splitProps(stickySectionProps);
|
|
9
|
+
const { style, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
|
|
10
|
+
const sectionRef = useRef(null);
|
|
11
|
+
const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
|
|
12
|
+
const { layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: sectionRef, onLayout });
|
|
13
|
+
const { textStyle, innerStyle = {} } = splitStyle(normalStyle);
|
|
14
|
+
const stickyHeaders = useRef(new Map());
|
|
15
|
+
const registerStickyHeader = useCallback((item) => {
|
|
16
|
+
stickyHeaders.current.set(item.id, item);
|
|
17
|
+
}, []);
|
|
18
|
+
const unregisterStickyHeader = useCallback((id) => {
|
|
19
|
+
stickyHeaders.current.delete(id);
|
|
20
|
+
}, []);
|
|
21
|
+
const contextValue = useMemo(() => ({
|
|
22
|
+
registerStickyHeader,
|
|
23
|
+
unregisterStickyHeader
|
|
24
|
+
}), []);
|
|
25
|
+
useNodesRef(props, ref, sectionRef, {
|
|
26
|
+
style: normalStyle
|
|
27
|
+
});
|
|
28
|
+
function onLayout() {
|
|
29
|
+
stickyHeaders.current.forEach(item => {
|
|
30
|
+
item.updatePosition();
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
const innerProps = useInnerProps(extendObject({}, props, {
|
|
34
|
+
style: extendObject(innerStyle, layoutStyle),
|
|
35
|
+
ref: sectionRef
|
|
36
|
+
}, layoutProps), [], { layoutRef });
|
|
37
|
+
return (createElement(View, innerProps, createElement(StickyContext.Provider, { value: contextValue }, wrapChildren(props, {
|
|
38
|
+
hasVarDec,
|
|
39
|
+
varContext: varContextRef.current,
|
|
40
|
+
textStyle,
|
|
41
|
+
textProps
|
|
42
|
+
}))));
|
|
43
|
+
});
|
|
44
|
+
_StickySection.displayName = 'MpxStickySection';
|
|
45
|
+
export default _StickySection;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { useState, ComponentType, useEffect, useCallback, useRef, ReactNode, createElement } from 'react'
|
|
2
|
+
import { View, Image, StyleSheet, Text, TouchableOpacity } from 'react-native'
|
|
3
|
+
import FastImage from '@d11/react-native-fast-image'
|
|
4
|
+
|
|
5
|
+
const asyncChunkMap = new Map()
|
|
6
|
+
|
|
7
|
+
const styles = StyleSheet.create({
|
|
8
|
+
container: {
|
|
9
|
+
flex: 1,
|
|
10
|
+
padding: 20,
|
|
11
|
+
backgroundColor: '#fff'
|
|
12
|
+
},
|
|
13
|
+
loadingImage: {
|
|
14
|
+
width: 100,
|
|
15
|
+
height: 100,
|
|
16
|
+
marginTop: 220,
|
|
17
|
+
alignSelf: 'center'
|
|
18
|
+
},
|
|
19
|
+
buttonText: {
|
|
20
|
+
color: '#fff',
|
|
21
|
+
fontSize: 16,
|
|
22
|
+
fontWeight: '500',
|
|
23
|
+
textAlign: 'center'
|
|
24
|
+
},
|
|
25
|
+
errorImage: {
|
|
26
|
+
marginTop: 80,
|
|
27
|
+
width: 220,
|
|
28
|
+
aspectRatio: 1,
|
|
29
|
+
alignSelf: 'center'
|
|
30
|
+
},
|
|
31
|
+
errorText: {
|
|
32
|
+
fontSize: 16,
|
|
33
|
+
textAlign: 'center',
|
|
34
|
+
color: '#333',
|
|
35
|
+
marginBottom: 20
|
|
36
|
+
},
|
|
37
|
+
retryButton: {
|
|
38
|
+
position: 'absolute',
|
|
39
|
+
bottom: 54,
|
|
40
|
+
left: 20,
|
|
41
|
+
right: 20,
|
|
42
|
+
backgroundColor: '#fff',
|
|
43
|
+
paddingVertical: 15,
|
|
44
|
+
borderRadius: 30,
|
|
45
|
+
marginTop: 40,
|
|
46
|
+
borderWidth: 1,
|
|
47
|
+
borderColor: '#FF5F00'
|
|
48
|
+
},
|
|
49
|
+
retryButtonText: {
|
|
50
|
+
color: '#FF5F00',
|
|
51
|
+
fontSize: 16,
|
|
52
|
+
fontWeight: '500',
|
|
53
|
+
textAlign: 'center'
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
interface DefaultFallbackProps {
|
|
58
|
+
onReload: () => void
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const DefaultFallback = ({ onReload }: DefaultFallbackProps) => {
|
|
62
|
+
return (
|
|
63
|
+
<View style={styles.container}>
|
|
64
|
+
<Image
|
|
65
|
+
source={{
|
|
66
|
+
uri: 'https://dpubstatic.udache.com/static/dpubimg/Vak5mZvezPpKV5ZJI6P9b_drn-fallbak.png'
|
|
67
|
+
}}
|
|
68
|
+
style={styles.errorImage}
|
|
69
|
+
resizeMode="contain"
|
|
70
|
+
/>
|
|
71
|
+
<Text style={styles.errorText}>网络出了点问题,请查看网络环境</Text>
|
|
72
|
+
<TouchableOpacity
|
|
73
|
+
style={styles.retryButton}
|
|
74
|
+
onPress={onReload}
|
|
75
|
+
activeOpacity={0.7}
|
|
76
|
+
>
|
|
77
|
+
<Text style={styles.retryButtonText}>点击重试</Text>
|
|
78
|
+
</TouchableOpacity>
|
|
79
|
+
</View>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const DefaultLoading = () => {
|
|
84
|
+
return (
|
|
85
|
+
<View style={styles.container}>
|
|
86
|
+
<FastImage
|
|
87
|
+
style={styles.loadingImage}
|
|
88
|
+
source={{
|
|
89
|
+
uri: 'https://dpubstatic.udache.com/static/dpubimg/439jiCVOtNOnEv9F2LaDs_loading.gif'
|
|
90
|
+
}}
|
|
91
|
+
resizeMode={FastImage.resizeMode.contain}
|
|
92
|
+
></FastImage>
|
|
93
|
+
</View>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
interface AsyncSuspenseProps {
|
|
98
|
+
type: 'component' | 'page'
|
|
99
|
+
chunkName: string
|
|
100
|
+
moduleId: string
|
|
101
|
+
innerProps: any,
|
|
102
|
+
loading?: ComponentType<unknown>
|
|
103
|
+
fallback?: ComponentType<unknown>
|
|
104
|
+
getChildren: () => Promise<ReactNode>
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
type ComponentStauts = 'pending' | 'error' | 'loaded'
|
|
108
|
+
|
|
109
|
+
const AsyncSuspense: React.FC<AsyncSuspenseProps> = ({
|
|
110
|
+
type,
|
|
111
|
+
innerProps,
|
|
112
|
+
chunkName,
|
|
113
|
+
moduleId,
|
|
114
|
+
loading,
|
|
115
|
+
fallback,
|
|
116
|
+
getChildren
|
|
117
|
+
}) => {
|
|
118
|
+
const [status, setStatus] = useState<ComponentStauts>('pending')
|
|
119
|
+
const chunkLoaded = asyncChunkMap.has(moduleId)
|
|
120
|
+
const loadChunkPromise = useRef<null | Promise<ReactNode>>(null)
|
|
121
|
+
|
|
122
|
+
const reloadPage = useCallback(() => {
|
|
123
|
+
setStatus('pending')
|
|
124
|
+
}, [])
|
|
125
|
+
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
let cancelled = false
|
|
128
|
+
if (!chunkLoaded && status === 'pending') {
|
|
129
|
+
if (loadChunkPromise.current) {
|
|
130
|
+
loadChunkPromise
|
|
131
|
+
.current.then((res: ReactNode) => {
|
|
132
|
+
if (cancelled) return
|
|
133
|
+
asyncChunkMap.set(moduleId, res)
|
|
134
|
+
setStatus('loaded')
|
|
135
|
+
})
|
|
136
|
+
.catch((e) => {
|
|
137
|
+
if (cancelled) return
|
|
138
|
+
if (type === 'component') {
|
|
139
|
+
global.onLazyLoadError({
|
|
140
|
+
type: 'subpackage',
|
|
141
|
+
subpackage: [chunkName],
|
|
142
|
+
errMsg: `loadSubpackage: ${e.type}`
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
loadChunkPromise.current = null
|
|
146
|
+
setStatus('error')
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return () => {
|
|
152
|
+
cancelled = true
|
|
153
|
+
}
|
|
154
|
+
}, [status])
|
|
155
|
+
|
|
156
|
+
if (chunkLoaded) {
|
|
157
|
+
const Comp = asyncChunkMap.get(moduleId)
|
|
158
|
+
return createElement(Comp, innerProps)
|
|
159
|
+
} else if (status === 'error') {
|
|
160
|
+
if (type === 'page') {
|
|
161
|
+
fallback = fallback || DefaultFallback
|
|
162
|
+
return createElement(fallback as ComponentType<DefaultFallbackProps>, { onReload: reloadPage })
|
|
163
|
+
} else {
|
|
164
|
+
return fallback ? createElement(fallback, innerProps) : null
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
if (!loadChunkPromise.current) {
|
|
168
|
+
loadChunkPromise.current = getChildren()
|
|
169
|
+
}
|
|
170
|
+
if (type === 'page') {
|
|
171
|
+
return createElement(loading || DefaultLoading)
|
|
172
|
+
} else {
|
|
173
|
+
return fallback ? createElement(fallback, innerProps) : null
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
AsyncSuspense.displayName = 'MpxAsyncSuspense'
|
|
179
|
+
|
|
180
|
+
export default AsyncSuspense
|
|
@@ -42,7 +42,8 @@ import {
|
|
|
42
42
|
TextStyle,
|
|
43
43
|
Animated,
|
|
44
44
|
Easing,
|
|
45
|
-
NativeSyntheticEvent
|
|
45
|
+
NativeSyntheticEvent,
|
|
46
|
+
useAnimatedValue
|
|
46
47
|
} from 'react-native'
|
|
47
48
|
import { warn } from '@mpxjs/utils'
|
|
48
49
|
import { GestureDetector, PanGesture } from 'react-native-gesture-handler'
|
|
@@ -157,7 +158,7 @@ const timer = (data: any, time = 3000) => new Promise((resolve) => {
|
|
|
157
158
|
})
|
|
158
159
|
|
|
159
160
|
const Loading = ({ alone = false }: { alone: boolean }): JSX.Element => {
|
|
160
|
-
const image =
|
|
161
|
+
const image = useAnimatedValue(0)
|
|
161
162
|
|
|
162
163
|
const rotate = image.interpolate({
|
|
163
164
|
inputRange: [0, 1],
|
|
@@ -70,6 +70,7 @@ interface MovableViewProps {
|
|
|
70
70
|
'parent-font-size'?: number
|
|
71
71
|
'parent-width'?: number
|
|
72
72
|
'parent-height'?: number
|
|
73
|
+
'disable-event-passthrough'?: boolean
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
const styles = StyleSheet.create({
|
|
@@ -103,6 +104,7 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
103
104
|
'parent-width': parentWidth,
|
|
104
105
|
'parent-height': parentHeight,
|
|
105
106
|
direction = 'none',
|
|
107
|
+
'disable-event-passthrough': disableEventPassthrough = false,
|
|
106
108
|
'simultaneous-handlers': originSimultaneousHandlers = [],
|
|
107
109
|
'wait-for': waitFor = [],
|
|
108
110
|
style = {},
|
|
@@ -557,10 +559,12 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
557
559
|
})
|
|
558
560
|
.withRef(movableGestureRef)
|
|
559
561
|
|
|
560
|
-
if (
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
562
|
+
if (!disableEventPassthrough) {
|
|
563
|
+
if (direction === 'horizontal') {
|
|
564
|
+
gesturePan.activeOffsetX([-5, 5]).failOffsetY([-5, 5])
|
|
565
|
+
} else if (direction === 'vertical') {
|
|
566
|
+
gesturePan.activeOffsetY([-5, 5]).failOffsetX([-5, 5])
|
|
567
|
+
}
|
|
564
568
|
}
|
|
565
569
|
|
|
566
570
|
if (simultaneousHandlers && simultaneousHandlers.length) {
|