UNPKG

4.76 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = useScrollToTop;
7var _core = require("@react-navigation/core");
8var React = _interopRequireWildcard(require("react"));
9function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
10function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
11function getScrollableNode(ref) {
12 if (ref.current == null) {
13 return null;
14 }
15 if ('scrollToTop' in ref.current || 'scrollTo' in ref.current || 'scrollToOffset' in ref.current || 'scrollResponderScrollTo' in ref.current) {
16 // This is already a scrollable node.
17 return ref.current;
18 } else if ('getScrollResponder' in ref.current) {
19 // If the view is a wrapper like FlatList, SectionList etc.
20 // We need to use `getScrollResponder` to get access to the scroll responder
21 return ref.current.getScrollResponder();
22 } else if ('getNode' in ref.current) {
23 // When a `ScrollView` is wraped in `Animated.createAnimatedComponent`
24 // we need to use `getNode` to get the ref to the actual scrollview.
25 // Note that `getNode` is deprecated in newer versions of react-native
26 // this is why we check if we already have a scrollable node above.
27 return ref.current.getNode();
28 } else {
29 return ref.current;
30 }
31}
32function useScrollToTop(ref) {
33 const navigation = (0, _core.useNavigation)();
34 const route = (0, _core.useRoute)();
35 React.useEffect(() => {
36 let tabNavigations = [];
37 let currentNavigation = navigation;
38
39 // If the screen is nested inside multiple tab navigators, we should scroll to top for any of them
40 // So we need to find all the parent tab navigators and add the listeners there
41 while (currentNavigation) {
42 if (currentNavigation.getState().type === 'tab') {
43 tabNavigations.push(currentNavigation);
44 }
45 currentNavigation = currentNavigation.getParent();
46 }
47 if (tabNavigations.length === 0) {
48 return;
49 }
50 const unsubscribers = tabNavigations.map(tab => {
51 return tab.addListener(
52 // We don't wanna import tab types here to avoid extra deps
53 // in addition, there are multiple tab implementations
54 // @ts-expect-error
55 'tabPress', e => {
56 // We should scroll to top only when the screen is focused
57 const isFocused = navigation.isFocused();
58
59 // In a nested stack navigator, tab press resets the stack to first screen
60 // So we should scroll to top only when we are on first screen
61 const isFirst = tabNavigations.includes(navigation) || navigation.getState().routes[0].key === route.key;
62
63 // Run the operation in the next frame so we're sure all listeners have been run
64 // This is necessary to know if preventDefault() has been called
65 requestAnimationFrame(() => {
66 const scrollable = getScrollableNode(ref);
67 if (isFocused && isFirst && scrollable && !e.defaultPrevented) {
68 if ('scrollToTop' in scrollable) {
69 scrollable.scrollToTop();
70 } else if ('scrollTo' in scrollable) {
71 scrollable.scrollTo({
72 y: 0,
73 animated: true
74 });
75 } else if ('scrollToOffset' in scrollable) {
76 scrollable.scrollToOffset({
77 offset: 0,
78 animated: true
79 });
80 } else if ('scrollResponderScrollTo' in scrollable) {
81 scrollable.scrollResponderScrollTo({
82 y: 0,
83 animated: true
84 });
85 }
86 }
87 });
88 });
89 });
90 return () => {
91 unsubscribers.forEach(unsubscribe => unsubscribe());
92 };
93 }, [navigation, ref, route.key]);
94}
95//# sourceMappingURL=useScrollToTop.js.map
\No newline at end of file