@shoutem/ui 8.3.0-rc.2 → 9.0.0-rc.0
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.
|
@@ -1,80 +1,60 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useContext, useEffect, useRef } from 'react';
|
|
2
2
|
import { Animated } from 'react-native';
|
|
3
|
-
import
|
|
3
|
+
import { useFocusEffect } from '@react-navigation/native';
|
|
4
4
|
import _ from 'lodash';
|
|
5
5
|
import PropTypes from 'prop-types';
|
|
6
|
-
import { ScrollDriver } from '@shoutem/animation';
|
|
6
|
+
import { AnimationDriverContext, ScrollDriver } from '@shoutem/animation';
|
|
7
7
|
import { connectStyle } from '@shoutem/theme';
|
|
8
|
-
import {
|
|
9
|
-
ScrollDriverContext,
|
|
10
|
-
ScrollDriverProvider,
|
|
11
|
-
} from './ScrollDriverProvider.js';
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
static DriverContext = ScrollDriverContext;
|
|
17
|
-
|
|
18
|
-
constructor(props, context) {
|
|
19
|
-
super(props, context);
|
|
20
|
-
|
|
21
|
-
autoBindReact(this);
|
|
22
|
-
|
|
23
|
-
this.animationDriver =
|
|
24
|
-
props.driver ||
|
|
9
|
+
const ScrollView = ({ driver, onScroll, primary, style, ...otherProps }) => {
|
|
10
|
+
const animationDriver = useRef(
|
|
11
|
+
driver ||
|
|
25
12
|
new ScrollDriver(
|
|
26
13
|
{ useNativeDriver: true, nativeScrollEventThrottle: 20 },
|
|
27
|
-
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
14
|
+
onScroll,
|
|
15
|
+
),
|
|
16
|
+
);
|
|
17
|
+
const animationDriverContext = useContext(AnimationDriverContext);
|
|
18
|
+
|
|
19
|
+
// When transition to and back from the screen containing the scrollview,
|
|
20
|
+
// we want to switch to appropriate animation driver. We use the following hook
|
|
21
|
+
// to derive the new driver and cascading styles before the actual navigation transition is done
|
|
22
|
+
// to avoid rerendering when the actual nav transition completes
|
|
23
|
+
useFocusEffect(() => {
|
|
24
|
+
const {
|
|
25
|
+
animationDriver: prevAnimationDriver,
|
|
26
|
+
setAnimationDriver,
|
|
27
|
+
} = animationDriverContext;
|
|
28
|
+
|
|
29
|
+
if (setAnimationDriver) {
|
|
30
|
+
setAnimationDriver(animationDriver.current, primary);
|
|
37
31
|
}
|
|
38
|
-
}
|
|
39
32
|
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
return () => {
|
|
34
|
+
if (prevAnimationDriver) {
|
|
35
|
+
setAnimationDriver(prevAnimationDriver);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
});
|
|
42
39
|
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (driver && animationDriver.current !== driver) {
|
|
42
|
+
animationDriver.current = driver;
|
|
45
43
|
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
value={{
|
|
61
|
-
driverProvider,
|
|
62
|
-
animationDriver: this.animationDriver,
|
|
63
|
-
}}
|
|
64
|
-
>
|
|
65
|
-
<Animated.ScrollView
|
|
66
|
-
ref={this.setWrappedInstance}
|
|
67
|
-
contentContainerStyle={contentContainerStyle}
|
|
68
|
-
{...scrollViewProps}
|
|
69
|
-
{..._.omit(otherProps, 'onScroll')}
|
|
70
|
-
style={otherStyle}
|
|
71
|
-
/>
|
|
72
|
-
</ScrollDriverContext.Provider>
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
ScrollView.contextType = ScrollDriverContext;
|
|
44
|
+
}, [driver]);
|
|
45
|
+
|
|
46
|
+
const { scrollViewProps } = animationDriver?.current;
|
|
47
|
+
const { contentContainerStyle, ...otherStyle } = style;
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Animated.ScrollView
|
|
51
|
+
contentContainerStyle={contentContainerStyle}
|
|
52
|
+
{...scrollViewProps}
|
|
53
|
+
{..._.omit(otherProps, 'onScroll')}
|
|
54
|
+
style={otherStyle}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
78
58
|
|
|
79
59
|
ScrollView.propTypes = {
|
|
80
60
|
...Animated.ScrollView.propTypes,
|
|
@@ -87,27 +67,4 @@ ScrollView.defaultProps = {
|
|
|
87
67
|
|
|
88
68
|
const StyledScrollView = connectStyle('shoutem.ui.ScrollView')(ScrollView);
|
|
89
69
|
|
|
90
|
-
function getRNScrollViewComponent(context) {
|
|
91
|
-
// wrappedInstance.wrappedInstance._component:
|
|
92
|
-
// 1st wrappedInstance -> StyledScrollView
|
|
93
|
-
// 2nd wrappedInstance -> ScrollView (Shoutem UI)
|
|
94
|
-
// _component -> Animated.ScrollView
|
|
95
|
-
// more info about _component: https://stackoverflow.com/questions/42051368/scrollto-is-undefined-on-animated-scrollview
|
|
96
|
-
return _.get(context, 'wrappedInstance.wrappedInstance._component');
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
StyledScrollView.prototype.scrollTo = function scrollTo(coordinates) {
|
|
100
|
-
const scrollView = getRNScrollViewComponent(this);
|
|
101
|
-
if (scrollView) {
|
|
102
|
-
scrollView.scrollTo(coordinates);
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
StyledScrollView.prototype.scrollToEnd = function scrollToEnd(animation) {
|
|
107
|
-
const scrollView = getRNScrollViewComponent(this);
|
|
108
|
-
if (scrollView) {
|
|
109
|
-
scrollView.scrollToEnd(animation);
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
|
|
113
70
|
export { StyledScrollView as ScrollView };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shoutem/ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0-rc.0",
|
|
4
4
|
"description": "Styleable set of components for React Native applications",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"lint": "eslint .",
|
|
@@ -51,7 +51,8 @@
|
|
|
51
51
|
"react": ">=19.0.0",
|
|
52
52
|
"react-native": ">=0.78.0",
|
|
53
53
|
"react-native-gesture-handler": "*",
|
|
54
|
-
"react-native-safe-area-context": "*"
|
|
54
|
+
"react-native-safe-area-context": "*",
|
|
55
|
+
"@react-navigation/native": "*"
|
|
55
56
|
},
|
|
56
57
|
"devDependencies": {
|
|
57
58
|
"@babel/core": "^7.25.2",
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import React, { Children, createContext, PureComponent } from 'react';
|
|
2
|
-
import _ from 'lodash';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
|
-
import { DriverShape, ScrollDriver } from '@shoutem/animation';
|
|
5
|
-
|
|
6
|
-
export const ScrollDriverContext = createContext({});
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Use this component if you want to share animation driver between unreachable siblings.
|
|
10
|
-
* Just wrap their parent component with it. We use it to share an instance of ScrollDriver
|
|
11
|
-
* between Screen and NavigationBar automatically. ScrollView from @shoutem/ui uses it to
|
|
12
|
-
* register its driver.
|
|
13
|
-
*/
|
|
14
|
-
export class ScrollDriverProvider extends PureComponent {
|
|
15
|
-
constructor(props, context) {
|
|
16
|
-
super(props, context);
|
|
17
|
-
|
|
18
|
-
this.setupAnimationDriver(props, context);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
setupAnimationDriver(props, context) {
|
|
22
|
-
const { onAnimationDriverChange } = this.props;
|
|
23
|
-
|
|
24
|
-
if (props.driver) {
|
|
25
|
-
this.animationDriver = props.driver;
|
|
26
|
-
} else if (context.driverProvider) {
|
|
27
|
-
this.animationDriver = context.animationDriver;
|
|
28
|
-
} else if (!this.animationDriver) {
|
|
29
|
-
this.animationDriver = new ScrollDriver(
|
|
30
|
-
{ useNativeDriver: true, nativeScrollEventThrottle: 20 },
|
|
31
|
-
props.onScroll,
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (onAnimationDriverChange) {
|
|
36
|
-
onAnimationDriverChange(this.animationDriver);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
setAnimationDriver(driver, primaryScrollView) {
|
|
41
|
-
if (driver || !this.animationDriver || primaryScrollView) {
|
|
42
|
-
const { onAnimationDriverChange } = this.props;
|
|
43
|
-
const { driverProvider } = this.context;
|
|
44
|
-
|
|
45
|
-
_.assign(this.animationDriver, driver);
|
|
46
|
-
if (onAnimationDriverChange) {
|
|
47
|
-
onAnimationDriverChange(driver);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (driverProvider) {
|
|
51
|
-
driverProvider.setAnimationDriver(driver, primaryScrollView);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
render() {
|
|
57
|
-
const { children } = this.props;
|
|
58
|
-
|
|
59
|
-
return (
|
|
60
|
-
<ScrollDriverContext.Provider
|
|
61
|
-
value={{
|
|
62
|
-
driverProvider: this,
|
|
63
|
-
animationDriver: this.animationDriver,
|
|
64
|
-
}}
|
|
65
|
-
>
|
|
66
|
-
{children && Children.only(children)}
|
|
67
|
-
</ScrollDriverContext.Provider>
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
ScrollDriverProvider.contextType = ScrollDriverContext;
|
|
73
|
-
|
|
74
|
-
// We disable this eslint rule because the props are being utilized indirectly
|
|
75
|
-
// through componentDidUpdate's usage of setupAnimationDriver
|
|
76
|
-
/* eslint-disable react/no-unused-prop-types */
|
|
77
|
-
ScrollDriverProvider.propTypes = {
|
|
78
|
-
children: PropTypes.node,
|
|
79
|
-
driver: DriverShape,
|
|
80
|
-
// Used to propagate animation driver changes to components that aren't
|
|
81
|
-
// children of ScrollDriver, recieves driver as argument.
|
|
82
|
-
// TODO: Rewrite for new context API.
|
|
83
|
-
onAnimationDriverChange: PropTypes.func,
|
|
84
|
-
onScroll: PropTypes.func,
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
ScrollDriverProvider.defaultProps = {
|
|
88
|
-
children: undefined,
|
|
89
|
-
driver: undefined,
|
|
90
|
-
onAnimationDriverChange: undefined,
|
|
91
|
-
onScroll: undefined,
|
|
92
|
-
};
|