@mpxjs/webpack-plugin 2.10.7-beta.8 → 2.10.7

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 (35) hide show
  1. package/LICENSE +433 -0
  2. package/lib/dependencies/RecordPageConfigsMapDependency.js +1 -1
  3. package/lib/index.js +5 -6
  4. package/lib/platform/template/wx/component-config/index.js +1 -5
  5. package/lib/platform/template/wx/index.js +2 -1
  6. package/lib/runtime/components/react/context.ts +3 -12
  7. package/lib/runtime/components/react/dist/context.js +1 -4
  8. package/lib/runtime/components/react/dist/getInnerListeners.js +1 -1
  9. package/lib/runtime/components/react/dist/mpx-button.jsx +2 -2
  10. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +2 -2
  11. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +6 -17
  12. package/lib/runtime/components/react/dist/mpx-swiper.jsx +27 -53
  13. package/lib/runtime/components/react/dist/mpx-web-view.jsx +14 -28
  14. package/lib/runtime/components/react/dist/useAnimationHooks.js +2 -87
  15. package/lib/runtime/components/react/getInnerListeners.ts +1 -1
  16. package/lib/runtime/components/react/mpx-button.tsx +2 -3
  17. package/lib/runtime/components/react/mpx-movable-view.tsx +2 -2
  18. package/lib/runtime/components/react/mpx-scroll-view.tsx +50 -68
  19. package/lib/runtime/components/react/mpx-swiper.tsx +25 -53
  20. package/lib/runtime/components/react/mpx-web-view.tsx +13 -33
  21. package/lib/runtime/components/react/types/global.d.ts +15 -0
  22. package/lib/runtime/components/react/useAnimationHooks.ts +2 -85
  23. package/lib/runtime/components/web/mpx-scroll-view.vue +4 -21
  24. package/lib/template-compiler/compiler.js +1 -1
  25. package/package.json +4 -4
  26. package/lib/platform/template/wx/component-config/sticky-header.js +0 -23
  27. package/lib/platform/template/wx/component-config/sticky-section.js +0 -23
  28. package/lib/runtime/components/react/AsyncContainer.tsx +0 -189
  29. package/lib/runtime/components/react/dist/AsyncContainer.jsx +0 -141
  30. package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +0 -115
  31. package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +0 -45
  32. package/lib/runtime/components/react/mpx-sticky-header.tsx +0 -179
  33. package/lib/runtime/components/react/mpx-sticky-section.tsx +0 -96
  34. package/lib/runtime/components/web/mpx-sticky-header.vue +0 -91
  35. package/lib/runtime/components/web/mpx-sticky-section.vue +0 -15
@@ -1,189 +0,0 @@
1
- import { ComponentType, ReactNode, Component, Fragment, Suspense } from 'react'
2
- import { View, Text, Image, StyleSheet, TouchableOpacity } from 'react-native'
3
- import FastImage from '@d11/react-native-fast-image'
4
-
5
- const styles = StyleSheet.create({
6
- container: {
7
- flex: 1,
8
- padding: 20,
9
- backgroundColor: '#fff'
10
- },
11
- loadingImage: {
12
- width: 100,
13
- height: 100,
14
- marginTop: 220,
15
- alignSelf: 'center'
16
- },
17
- buttonText: {
18
- color: '#fff',
19
- fontSize: 16,
20
- fontWeight: '500',
21
- textAlign: 'center'
22
- },
23
- errorImage: {
24
- marginTop: 80,
25
- width: 220,
26
- aspectRatio: 1,
27
- alignSelf: 'center'
28
- },
29
- errorText: {
30
- fontSize: 16,
31
- textAlign: 'center',
32
- color: '#333',
33
- marginBottom: 20
34
- },
35
- retryButton: {
36
- position: 'absolute',
37
- bottom: 54,
38
- left: 20,
39
- right: 20,
40
- backgroundColor: '#fff',
41
- paddingVertical: 15,
42
- borderRadius: 30,
43
- marginTop: 40,
44
- borderWidth: 1,
45
- borderColor: '#FF5F00'
46
- },
47
- retryButtonText: {
48
- color: '#FF5F00',
49
- fontSize: 16,
50
- fontWeight: '500',
51
- textAlign: 'center'
52
- }
53
- })
54
-
55
- type AsyncType = 'page' | 'component'
56
-
57
- interface PropsType<T extends AsyncType> {
58
- type: T
59
- props: object
60
- loading: ComponentType<unknown>
61
- fallback: ComponentType<unknown>
62
- children: (props: unknown) => ReactNode
63
- }
64
-
65
- interface StateType {
66
- hasError: boolean,
67
- key: number
68
- }
69
-
70
- interface ComponentError extends Error {
71
- request?: string
72
- type: 'timeout' | 'fail'
73
- }
74
-
75
- const DefaultLoading = () => {
76
- return (
77
- <View style={styles.container}>
78
- <FastImage
79
- style={styles.loadingImage}
80
- source={{ uri: 'https://dpubstatic.udache.com/static/dpubimg/439jiCVOtNOnEv9F2LaDs_loading.gif' }}
81
- resizeMode={FastImage.resizeMode.contain}></FastImage>
82
- </View>
83
- )
84
- }
85
-
86
- interface DefaultFallbackProps {
87
- onReload: () => void
88
- }
89
-
90
- const DefaultFallback = ({ onReload }: DefaultFallbackProps) => {
91
- return (
92
- <View style={styles.container}>
93
- <Image
94
- source={{ uri: 'https://dpubstatic.udache.com/static/dpubimg/Vak5mZvezPpKV5ZJI6P9b_drn-fallbak.png' }}
95
- style={styles.errorImage}
96
- resizeMode="contain"
97
- />
98
- <Text style={styles.errorText}>网络出了点问题,请查看网络环境</Text>
99
- <TouchableOpacity
100
- style={styles.retryButton}
101
- onPress={onReload}
102
- activeOpacity={0.7}
103
- >
104
- <Text style={styles.retryButtonText}>点击重试</Text>
105
- </TouchableOpacity>
106
- </View>
107
- )
108
- }
109
-
110
- export default class AsyncContainer extends Component<PropsType<AsyncType>, StateType> {
111
- private suspenseFallback: ReactNode
112
- private errorFallback: ReactNode
113
-
114
- constructor (props: PropsType<AsyncType>) {
115
- super(props)
116
- this.state = {
117
- hasError: false,
118
- key: 0
119
- }
120
- this.suspenseFallback = this.getSuspenseFallback()
121
- this.errorFallback = this.getErrorFallback()
122
- }
123
-
124
- // render 阶段收集到的错误
125
- static getDerivedStateFromError (error: ComponentError): StateType | undefined {
126
- if (error.name === 'ChunkLoadError') {
127
- return {
128
- hasError: true,
129
- key: 0
130
- }
131
- } else {
132
- // 被外层捕获
133
- throw error
134
- }
135
- }
136
-
137
- componentDidCatch (error: ComponentError): void {
138
- if (error.name === 'ChunkLoadError' && this.props.type === 'component') {
139
- const request = error.request || ''
140
- const subpackage = request.split('/').filter((i: string) => !!i)[0]
141
- global.onLazyLoadError({
142
- type: 'subpackage',
143
- subpackage: [subpackage],
144
- errMsg: `loadSubpackage: ${error.type}`
145
- })
146
- }
147
- }
148
-
149
- reloadPage () {
150
- this.setState((prevState) => {
151
- return {
152
- hasError: false,
153
- key: prevState.key + 1
154
- }
155
- })
156
- }
157
-
158
- getSuspenseFallback () {
159
- if (this.props.type === 'page') {
160
- const Fallback = this.props.loading || DefaultLoading
161
- return <Fallback />
162
- } else {
163
- const Fallback = this.props.loading
164
- return <Fallback {...this.props.props}></Fallback>
165
- }
166
- }
167
-
168
- getErrorFallback () {
169
- if (this.props.type === 'page') {
170
- const Fallback = this.props.fallback as ComponentType<DefaultFallbackProps> || DefaultFallback
171
- return <Fallback onReload={this.reloadPage.bind(this)}></Fallback>
172
- } else {
173
- const Fallback = this.props.loading
174
- return <Fallback {...this.props.props}></Fallback>
175
- }
176
- }
177
-
178
- render () {
179
- if (this.state.hasError) {
180
- return this.errorFallback
181
- } else {
182
- return (
183
- <Suspense fallback={this.suspenseFallback} key={this.state.key}>
184
- {this.props.children(this.props.props)}
185
- </Suspense>
186
- )
187
- }
188
- }
189
- }
@@ -1,141 +0,0 @@
1
- import { Component, Suspense } from 'react';
2
- import { View, Text, Image, StyleSheet, TouchableOpacity } from 'react-native';
3
- import FastImage from '@d11/react-native-fast-image';
4
- const styles = StyleSheet.create({
5
- container: {
6
- flex: 1,
7
- padding: 20,
8
- backgroundColor: '#fff'
9
- },
10
- loadingImage: {
11
- width: 100,
12
- height: 100,
13
- marginTop: 220,
14
- alignSelf: 'center'
15
- },
16
- buttonText: {
17
- color: '#fff',
18
- fontSize: 16,
19
- fontWeight: '500',
20
- textAlign: 'center'
21
- },
22
- errorImage: {
23
- marginTop: 80,
24
- width: 220,
25
- aspectRatio: 1,
26
- alignSelf: 'center'
27
- },
28
- errorText: {
29
- fontSize: 16,
30
- textAlign: 'center',
31
- color: '#333',
32
- marginBottom: 20
33
- },
34
- retryButton: {
35
- position: 'absolute',
36
- bottom: 54,
37
- left: 20,
38
- right: 20,
39
- backgroundColor: '#fff',
40
- paddingVertical: 15,
41
- borderRadius: 30,
42
- marginTop: 40,
43
- borderWidth: 1,
44
- borderColor: '#FF5F00'
45
- },
46
- retryButtonText: {
47
- color: '#FF5F00',
48
- fontSize: 16,
49
- fontWeight: '500',
50
- textAlign: 'center'
51
- }
52
- });
53
- const DefaultLoading = () => {
54
- return (<View style={styles.container}>
55
- <FastImage style={styles.loadingImage} source={{ uri: 'https://dpubstatic.udache.com/static/dpubimg/439jiCVOtNOnEv9F2LaDs_loading.gif' }} resizeMode={FastImage.resizeMode.contain}></FastImage>
56
- </View>);
57
- };
58
- const DefaultFallback = ({ onReload }) => {
59
- return (<View style={styles.container}>
60
- <Image source={{ uri: 'https://dpubstatic.udache.com/static/dpubimg/Vak5mZvezPpKV5ZJI6P9b_drn-fallbak.png' }} style={styles.errorImage} resizeMode="contain"/>
61
- <Text style={styles.errorText}>网络出了点问题,请查看网络环境</Text>
62
- <TouchableOpacity style={styles.retryButton} onPress={onReload} activeOpacity={0.7}>
63
- <Text style={styles.retryButtonText}>点击重试</Text>
64
- </TouchableOpacity>
65
- </View>);
66
- };
67
- export default class AsyncContainer extends Component {
68
- suspenseFallback;
69
- errorFallback;
70
- constructor(props) {
71
- super(props);
72
- this.state = {
73
- hasError: false,
74
- key: 0
75
- };
76
- this.suspenseFallback = this.getSuspenseFallback();
77
- this.errorFallback = this.getErrorFallback();
78
- }
79
- // render 阶段收集到的错误
80
- static getDerivedStateFromError(error) {
81
- if (error.name === 'ChunkLoadError') {
82
- return {
83
- hasError: true,
84
- key: 0
85
- };
86
- }
87
- else {
88
- // 被外层捕获
89
- throw error;
90
- }
91
- }
92
- componentDidCatch(error) {
93
- if (error.name === 'ChunkLoadError' && this.props.type === 'component') {
94
- const request = error.request || '';
95
- const subpackage = request.split('/').filter((i) => !!i)[0];
96
- global.onLazyLoadError({
97
- type: 'subpackage',
98
- subpackage: [subpackage],
99
- errMsg: `loadSubpackage: ${error.type}`
100
- });
101
- }
102
- }
103
- reloadPage() {
104
- this.setState((prevState) => {
105
- return {
106
- hasError: false,
107
- key: prevState.key + 1
108
- };
109
- });
110
- }
111
- getSuspenseFallback() {
112
- if (this.props.type === 'page') {
113
- const Fallback = this.props.loading || DefaultLoading;
114
- return <Fallback />;
115
- }
116
- else {
117
- const Fallback = this.props.loading;
118
- return <Fallback {...this.props.props}></Fallback>;
119
- }
120
- }
121
- getErrorFallback() {
122
- if (this.props.type === 'page') {
123
- const Fallback = this.props.fallback || DefaultFallback;
124
- return <Fallback onReload={this.reloadPage.bind(this)}></Fallback>;
125
- }
126
- else {
127
- const Fallback = this.props.loading;
128
- return <Fallback {...this.props.props}></Fallback>;
129
- }
130
- }
131
- render() {
132
- if (this.state.hasError) {
133
- return this.errorFallback;
134
- }
135
- else {
136
- return (<Suspense fallback={this.suspenseFallback} key={this.state.key}>
137
- {this.props.children(this.props.props)}
138
- </Suspense>);
139
- }
140
- }
141
- }
@@ -1,115 +0,0 @@
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
- }
113
- });
114
- _StickyHeader.displayName = 'MpxStickyHeader';
115
- export default _StickyHeader;
@@ -1,45 +0,0 @@
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;
@@ -1,179 +0,0 @@
1
- import { useEffect, useRef, useContext, forwardRef, useMemo, createElement, ReactNode, useId } from 'react'
2
- import { Animated, StyleSheet, View, NativeSyntheticEvent, ViewStyle, LayoutChangeEvent, useAnimatedValue } from 'react-native'
3
- import { ScrollViewContext, StickyContext } from './context'
4
- import useNodesRef, { HandlerRef } 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
-
9
- interface StickyHeaderProps {
10
- children?: ReactNode;
11
- style?: ViewStyle;
12
- padding?: [number, number, number, number];
13
- 'offset-top'?: number;
14
- 'enable-var'?: boolean;
15
- 'external-var-context'?: Record<string, any>;
16
- 'parent-font-size'?: number;
17
- 'parent-width'?: number;
18
- 'parent-height'?: number;
19
- bindstickontopchange?: (e: NativeSyntheticEvent<unknown>) => void;
20
- }
21
-
22
- const _StickyHeader = forwardRef<HandlerRef<View, StickyHeaderProps>, StickyHeaderProps>((stickyHeaderProps: StickyHeaderProps = {}, ref): JSX.Element => {
23
- const { textProps, innerProps: props = {} } = splitProps(stickyHeaderProps)
24
- const {
25
- style,
26
- bindstickontopchange,
27
- padding = [0, 0, 0, 0],
28
- 'offset-top': offsetTop = 0,
29
- 'enable-var': enableVar,
30
- 'external-var-context': externalVarContext,
31
- 'parent-font-size': parentFontSize,
32
- 'parent-width': parentWidth,
33
- 'parent-height': parentHeight
34
- } = props
35
-
36
- const scrollViewContext = useContext(ScrollViewContext)
37
- const stickyContext = useContext(StickyContext)
38
- const { scrollOffset } = scrollViewContext
39
- const { registerStickyHeader, unregisterStickyHeader } = stickyContext
40
- const headerRef = useRef<View>(null)
41
- const isStickOnTopRef = useRef(false)
42
- const id = useId()
43
-
44
- const {
45
- normalStyle,
46
- hasVarDec,
47
- varContextRef,
48
- hasSelfPercent,
49
- setWidth,
50
- setHeight
51
- } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
52
-
53
- const { layoutRef, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: headerRef, onLayout })
54
-
55
- const { textStyle, innerStyle = {} } = splitStyle(normalStyle)
56
-
57
- const headerTopAnimated = useAnimatedValue(0)
58
- // harmony animatedValue 不支持通过 _value 访问
59
- const headerTopRef = useRef(0)
60
-
61
- useEffect(() => {
62
- registerStickyHeader({ key: id, updatePosition })
63
- return () => {
64
- unregisterStickyHeader(id)
65
- }
66
- }, [])
67
-
68
- function updatePosition () {
69
- if (headerRef.current) {
70
- const scrollViewRef = scrollViewContext.gestureRef
71
- if (scrollViewRef && scrollViewRef.current) {
72
- headerRef.current.measureLayout(
73
- scrollViewRef.current,
74
- (left: number, top: number) => {
75
- Animated.timing(headerTopAnimated, {
76
- toValue: top,
77
- duration: 0,
78
- useNativeDriver: true
79
- }).start()
80
- headerTopRef.current = top
81
- }
82
- )
83
- } else {
84
- error('StickyHeader measureLayout error: scrollViewRef is not a valid native component reference')
85
- }
86
- }
87
- }
88
-
89
- function onLayout (e: LayoutChangeEvent) {
90
- updatePosition()
91
- }
92
-
93
- useNodesRef(props, ref, headerRef, {
94
- style: normalStyle
95
- })
96
-
97
- useEffect(() => {
98
- if (!bindstickontopchange) return
99
-
100
- const listener = scrollOffset.addListener((state: { value: number }) => {
101
- const currentScrollValue = state.value
102
- const newIsStickOnTop = currentScrollValue > headerTopRef.current
103
- if (newIsStickOnTop !== isStickOnTopRef.current) {
104
- isStickOnTopRef.current = newIsStickOnTop
105
- bindstickontopchange(
106
- getCustomEvent('stickontopchange', {}, {
107
- detail: {
108
- isStickOnTop: newIsStickOnTop
109
- },
110
- layoutRef
111
- }, props))
112
- }
113
- })
114
-
115
- return () => {
116
- scrollOffset.removeListener(listener)
117
- }
118
- }, [])
119
-
120
- const animatedStyle = useMemo(() => {
121
- const translateY = Animated.subtract(scrollOffset, headerTopAnimated).interpolate({
122
- inputRange: [0, 1],
123
- outputRange: [0, 1],
124
- extrapolateLeft: 'clamp',
125
- extrapolateRight: 'extend'
126
- })
127
-
128
- const finalTranslateY = offsetTop === 0
129
- ? translateY
130
- : Animated.add(
131
- translateY,
132
- Animated.subtract(scrollOffset, headerTopAnimated).interpolate({
133
- inputRange: [0, 1],
134
- outputRange: [0, offsetTop],
135
- extrapolate: 'clamp'
136
- })
137
- )
138
-
139
- return {
140
- transform: [{ translateY: finalTranslateY }]
141
- }
142
- }, [scrollOffset, headerTopAnimated, offsetTop])
143
-
144
- const innerProps = useInnerProps(extendObject({}, props, {
145
- ref: headerRef,
146
- style: extendObject({}, styles.content, innerStyle, animatedStyle, {
147
- paddingTop: padding[0] || 0,
148
- paddingRight: padding[1] || 0,
149
- paddingBottom: padding[2] || 0,
150
- paddingLeft: padding[3] || 0
151
- })
152
- }, layoutProps), [], { layoutRef })
153
-
154
- return (
155
- createElement(
156
- Animated.View,
157
- innerProps,
158
- wrapChildren(
159
- props,
160
- {
161
- hasVarDec,
162
- varContext: varContextRef.current,
163
- textStyle,
164
- textProps
165
- }
166
- )
167
- )
168
- )
169
- })
170
-
171
- const styles = StyleSheet.create({
172
- content: {
173
- width: '100%',
174
- zIndex: 10
175
- }
176
- })
177
-
178
- _StickyHeader.displayName = 'MpxStickyHeader'
179
- export default _StickyHeader