@r0b0t3d/react-native-collapsible 1.5.3 → 1.6.0-alpha.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.
- package/lib/commonjs/components/CollapsibleContainer.js +19 -21
- package/lib/commonjs/components/CollapsibleContainer.js.map +1 -1
- package/lib/commonjs/components/CollapsibleView.js +38 -30
- package/lib/commonjs/components/CollapsibleView.js.map +1 -1
- package/lib/commonjs/components/header/AnimatedTopView.js +5 -7
- package/lib/commonjs/components/header/AnimatedTopView.js.map +1 -1
- package/lib/commonjs/components/header/CollapsibleHeaderConsumer.js +10 -13
- package/lib/commonjs/components/header/CollapsibleHeaderConsumer.js.map +1 -1
- package/lib/commonjs/components/header/CollapsibleHeaderContainer.js +22 -17
- package/lib/commonjs/components/header/CollapsibleHeaderContainer.js.map +1 -1
- package/lib/commonjs/components/header/CollapsibleHeaderContainerProvider.js +12 -15
- package/lib/commonjs/components/header/CollapsibleHeaderContainerProvider.js.map +1 -1
- package/lib/commonjs/components/header/StickyView.js +18 -25
- package/lib/commonjs/components/header/StickyView.js.map +1 -1
- package/lib/commonjs/components/scrollable/CollapsibleFlatList.js +27 -41
- package/lib/commonjs/components/scrollable/CollapsibleFlatList.js.map +1 -1
- package/lib/commonjs/components/scrollable/CollapsibleScrollView.js +12 -15
- package/lib/commonjs/components/scrollable/CollapsibleScrollView.js.map +1 -1
- package/lib/commonjs/components/scrollable/CollapsibleSectionList.js +22 -36
- package/lib/commonjs/components/scrollable/CollapsibleSectionList.js.map +1 -1
- package/lib/commonjs/components/scrollable/useAnimatedScroll.js +44 -24
- package/lib/commonjs/components/scrollable/useAnimatedScroll.js.map +1 -1
- package/lib/commonjs/hooks/useCollapsibleContext.js +1 -2
- package/lib/commonjs/hooks/useCollapsibleContext.js.map +1 -1
- package/lib/commonjs/hooks/useCollapsibleHeaderConsumerContext.js +1 -2
- package/lib/commonjs/hooks/useCollapsibleHeaderConsumerContext.js.map +1 -1
- package/lib/commonjs/hooks/useCollapsibleHeaderContext.js +1 -2
- package/lib/commonjs/hooks/useCollapsibleHeaderContext.js.map +1 -1
- package/lib/commonjs/hooks/useInternalCollapsibleContext.js +1 -2
- package/lib/commonjs/hooks/useInternalCollapsibleContext.js.map +1 -1
- package/lib/commonjs/hooks/useKeyboardShowEvent.js.map +1 -1
- package/lib/commonjs/index.js +3 -12
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/plugins/CollapsibleFlashList.js +14 -17
- package/lib/commonjs/plugins/CollapsibleFlashList.js.map +1 -1
- package/lib/commonjs/plugins/CollapsibleLegendList.js +15 -15
- package/lib/commonjs/plugins/CollapsibleLegendList.js.map +1 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/utils/debounce.js +2 -6
- package/lib/commonjs/utils/debounce.js.map +1 -1
- package/lib/commonjs/utils/useSharedValueRef.js +33 -3
- package/lib/commonjs/utils/useSharedValueRef.js.map +1 -1
- package/lib/commonjs/withCollapsibleContext.js +3 -4
- package/lib/commonjs/withCollapsibleContext.js.map +1 -1
- package/lib/module/components/CollapsibleContainer.js +18 -19
- package/lib/module/components/CollapsibleContainer.js.map +1 -1
- package/lib/module/components/CollapsibleView.js +38 -29
- package/lib/module/components/CollapsibleView.js.map +1 -1
- package/lib/module/components/header/AnimatedTopView.js +3 -4
- package/lib/module/components/header/AnimatedTopView.js.map +1 -1
- package/lib/module/components/header/CollapsibleHeaderConsumer.js +8 -10
- package/lib/module/components/header/CollapsibleHeaderConsumer.js.map +1 -1
- package/lib/module/components/header/CollapsibleHeaderContainer.js +21 -15
- package/lib/module/components/header/CollapsibleHeaderContainer.js.map +1 -1
- package/lib/module/components/header/CollapsibleHeaderContainerProvider.js +10 -12
- package/lib/module/components/header/CollapsibleHeaderContainerProvider.js.map +1 -1
- package/lib/module/components/header/StickyView.js +18 -23
- package/lib/module/components/header/StickyView.js.map +1 -1
- package/lib/module/components/scrollable/CollapsibleFlatList.js +27 -41
- package/lib/module/components/scrollable/CollapsibleFlatList.js.map +1 -1
- package/lib/module/components/scrollable/CollapsibleScrollView.js +10 -12
- package/lib/module/components/scrollable/CollapsibleScrollView.js.map +1 -1
- package/lib/module/components/scrollable/CollapsibleSectionList.js +22 -35
- package/lib/module/components/scrollable/CollapsibleSectionList.js.map +1 -1
- package/lib/module/components/scrollable/useAnimatedScroll.js +44 -23
- package/lib/module/components/scrollable/useAnimatedScroll.js.map +1 -1
- package/lib/module/hooks/useCollapsibleContext.js.map +1 -1
- package/lib/module/hooks/useCollapsibleHeaderConsumerContext.js.map +1 -1
- package/lib/module/hooks/useCollapsibleHeaderContext.js.map +1 -1
- package/lib/module/hooks/useInternalCollapsibleContext.js.map +1 -1
- package/lib/module/hooks/useKeyboardShowEvent.js.map +1 -1
- package/lib/module/index.js +0 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/plugins/CollapsibleFlashList.js +12 -14
- package/lib/module/plugins/CollapsibleFlashList.js.map +1 -1
- package/lib/module/plugins/CollapsibleLegendList.js +13 -12
- package/lib/module/plugins/CollapsibleLegendList.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils/debounce.js +2 -6
- package/lib/module/utils/debounce.js.map +1 -1
- package/lib/module/utils/useSharedValueRef.js +33 -3
- package/lib/module/utils/useSharedValueRef.js.map +1 -1
- package/lib/module/withCollapsibleContext.js +2 -2
- package/lib/module/withCollapsibleContext.js.map +1 -1
- package/lib/typescript/components/CollapsibleContainer.d.ts.map +1 -1
- package/lib/typescript/components/CollapsibleView.d.ts +4 -4
- package/lib/typescript/components/CollapsibleView.d.ts.map +1 -1
- package/lib/typescript/components/header/AnimatedTopView.d.ts +2 -2
- package/lib/typescript/components/header/AnimatedTopView.d.ts.map +1 -1
- package/lib/typescript/components/header/CollapsibleHeaderContainer.d.ts.map +1 -1
- package/lib/typescript/components/header/StickyView.d.ts.map +1 -1
- package/lib/typescript/components/scrollable/CollapsibleFlatList.d.ts.map +1 -1
- package/lib/typescript/components/scrollable/CollapsibleSectionList.d.ts.map +1 -1
- package/lib/typescript/components/scrollable/useAnimatedScroll.d.ts +2 -2
- package/lib/typescript/components/scrollable/useAnimatedScroll.d.ts.map +1 -1
- package/lib/typescript/hooks/useCollapsibleContext.d.ts +0 -1
- package/lib/typescript/hooks/useCollapsibleContext.d.ts.map +1 -1
- package/lib/typescript/hooks/useCollapsibleHeaderContext.d.ts +2 -3
- package/lib/typescript/hooks/useCollapsibleHeaderContext.d.ts.map +1 -1
- package/lib/typescript/hooks/useInternalCollapsibleContext.d.ts +0 -1
- package/lib/typescript/hooks/useInternalCollapsibleContext.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +0 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/plugins/CollapsibleFlashList.d.ts.map +1 -1
- package/lib/typescript/plugins/CollapsibleLegendList.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +12 -12
- package/lib/typescript/types.d.ts.map +1 -1
- package/lib/typescript/utils/debounce.d.ts.map +1 -1
- package/lib/typescript/utils/useSharedValueRef.d.ts +2 -2
- package/lib/typescript/utils/useSharedValueRef.d.ts.map +1 -1
- package/lib/typescript/withCollapsibleContext.d.ts.map +1 -1
- package/package.json +54 -18
- package/src/components/CollapsibleContainer.tsx +12 -3
- package/src/components/CollapsibleView.tsx +31 -10
- package/src/components/header/AnimatedTopView.tsx +5 -2
- package/src/components/header/CollapsibleHeaderContainer.tsx +18 -13
- package/src/components/header/StickyView.tsx +8 -15
- package/src/components/scrollable/CollapsibleFlatList.tsx +27 -46
- package/src/components/scrollable/CollapsibleSectionList.tsx +21 -41
- package/src/components/scrollable/useAnimatedScroll.ts +36 -22
- package/src/hooks/useCollapsibleHeaderContext.ts +2 -2
- package/src/index.tsx +0 -2
- package/src/plugins/CollapsibleFlashList.tsx +9 -9
- package/src/plugins/CollapsibleLegendList.tsx +8 -2
- package/src/types.ts +12 -12
- package/src/utils/useSharedValueRef.ts +37 -6
- package/src/withCollapsibleContext.tsx +7 -4
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
import { useCallback, useEffect } from 'react';
|
|
1
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
3
2
|
import { Dimensions, SectionListScrollParams } from 'react-native';
|
|
4
3
|
import {
|
|
5
4
|
runOnJS,
|
|
6
5
|
useAnimatedScrollHandler,
|
|
7
6
|
useSharedValue,
|
|
8
7
|
} from 'react-native-reanimated';
|
|
9
|
-
import type { ScrollToIndexParams } from '../../types';
|
|
8
|
+
import type { CollapsibleHandles, ScrollToIndexParams } from '../../types';
|
|
10
9
|
import useCollapsibleContext from '../../hooks/useCollapsibleContext';
|
|
11
10
|
import useInternalCollapsibleContext from '../../hooks/useInternalCollapsibleContext';
|
|
12
11
|
|
|
@@ -30,37 +29,52 @@ export default function useAnimatedScroll({
|
|
|
30
29
|
const { setCollapsibleHandlers, fixedHeaderHeight } =
|
|
31
30
|
useInternalCollapsibleContext();
|
|
32
31
|
|
|
32
|
+
// Keep a ref to the latest handlers so we can publish stable function
|
|
33
|
+
// references to setCollapsibleHandlers() that always delegate to the most
|
|
34
|
+
// recent closures. This avoids re-running the publish effect on every
|
|
35
|
+
// scrollable re-render.
|
|
36
|
+
const handlersRef = useRef<{
|
|
37
|
+
scrollTo: (y: number, animated?: boolean) => void;
|
|
38
|
+
scrollToIndex: (p: ScrollToIndexParams) => void;
|
|
39
|
+
scrollToLocation: (p: SectionListScrollParams) => void;
|
|
40
|
+
}>({ scrollTo, scrollToIndex, scrollToLocation });
|
|
41
|
+
handlersRef.current = { scrollTo, scrollToIndex, scrollToLocation };
|
|
42
|
+
|
|
33
43
|
useEffect(() => {
|
|
34
44
|
if (scrollY.value > 0) {
|
|
35
|
-
requestAnimationFrame(() =>
|
|
45
|
+
requestAnimationFrame(() =>
|
|
46
|
+
handlersRef.current.scrollTo(scrollY.value, false)
|
|
47
|
+
);
|
|
36
48
|
}
|
|
49
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
37
50
|
}, []);
|
|
38
51
|
|
|
39
52
|
const collapse = useCallback(
|
|
40
53
|
(animated = true) => {
|
|
41
|
-
scrollTo(fixedHeaderHeight.value, animated);
|
|
54
|
+
handlersRef.current.scrollTo(fixedHeaderHeight.value, animated);
|
|
42
55
|
},
|
|
43
|
-
[
|
|
56
|
+
[fixedHeaderHeight]
|
|
44
57
|
);
|
|
45
58
|
|
|
46
|
-
const expand = useCallback(() => scrollTo(0), [
|
|
59
|
+
const expand = useCallback(() => handlersRef.current.scrollTo(0), []);
|
|
60
|
+
|
|
61
|
+
// Stable trampoline for use inside worklets: runOnJS captures the function
|
|
62
|
+
// reference at worklet-build time, so we must pass a stable function that
|
|
63
|
+
// dereferences handlersRef.current at JS-thread call time.
|
|
64
|
+
const scrollToOnJS = useCallback((y: number) => {
|
|
65
|
+
handlersRef.current.scrollTo(y);
|
|
66
|
+
}, []);
|
|
47
67
|
|
|
48
68
|
useEffect(() => {
|
|
49
|
-
|
|
69
|
+
const handlers: CollapsibleHandles = {
|
|
50
70
|
collapse,
|
|
51
71
|
expand,
|
|
52
|
-
scrollTo,
|
|
53
|
-
scrollToIndex,
|
|
54
|
-
scrollToLocation,
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
collapse,
|
|
59
|
-
expand,
|
|
60
|
-
scrollTo,
|
|
61
|
-
scrollToIndex,
|
|
62
|
-
scrollToLocation,
|
|
63
|
-
]);
|
|
72
|
+
scrollTo: (y, a) => handlersRef.current.scrollTo(y, a),
|
|
73
|
+
scrollToIndex: (p) => handlersRef.current.scrollToIndex(p),
|
|
74
|
+
scrollToLocation: (p) => handlersRef.current.scrollToLocation(p),
|
|
75
|
+
};
|
|
76
|
+
setCollapsibleHandlers(handlers);
|
|
77
|
+
}, [setCollapsibleHandlers, collapse, expand]);
|
|
64
78
|
|
|
65
79
|
const scrollHandler = useAnimatedScrollHandler(
|
|
66
80
|
{
|
|
@@ -81,12 +95,12 @@ export default function useAnimatedScroll({
|
|
|
81
95
|
if (scrollDirection.value === 'up') {
|
|
82
96
|
yValue = maxY;
|
|
83
97
|
}
|
|
84
|
-
runOnJS(
|
|
98
|
+
runOnJS(scrollToOnJS)(yValue);
|
|
85
99
|
}
|
|
86
100
|
}
|
|
87
101
|
},
|
|
88
102
|
},
|
|
89
|
-
[
|
|
103
|
+
[headerSnappable, fixedHeaderHeight, scrollY, scrollToOnJS]
|
|
90
104
|
);
|
|
91
105
|
|
|
92
106
|
return {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createContext, useContext } from 'react';
|
|
2
2
|
import { LayoutRectangle } from 'react-native';
|
|
3
|
-
import
|
|
3
|
+
import { SharedValue } from 'react-native-reanimated';
|
|
4
4
|
|
|
5
5
|
export type CollapsibleContextHeaderType = {
|
|
6
6
|
handleStickyViewLayout: (key: string, layout?: LayoutRectangle) => void;
|
|
7
|
-
animatedY:
|
|
7
|
+
animatedY: SharedValue<number>;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
export const CollapsibleHeaderContext =
|
package/src/index.tsx
CHANGED
|
@@ -9,5 +9,3 @@ export { default as CollapsibleHeaderContainer } from './components/header/Colla
|
|
|
9
9
|
export { default as StickyView } from './components/header/StickyView';
|
|
10
10
|
export { default as CollapsibleView } from './components/CollapsibleView';
|
|
11
11
|
export * from './components/CollapsibleView';
|
|
12
|
-
|
|
13
|
-
export { default as CollapsibleFlashList } from './plugins/CollapsibleFlashList';
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/exhaustive-deps */
|
|
2
2
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { View, StyleSheet } from 'react-native';
|
|
4
|
-
import
|
|
5
|
-
runOnJS,
|
|
6
|
-
useAnimatedReaction,
|
|
7
|
-
} from 'react-native-reanimated';
|
|
4
|
+
import { runOnJS, useAnimatedReaction } from 'react-native-reanimated';
|
|
8
5
|
import useAnimatedScroll from '../components/scrollable/useAnimatedScroll';
|
|
9
6
|
import useInternalCollapsibleContext from '../hooks/useInternalCollapsibleContext';
|
|
10
7
|
import type { CollapsibleProps } from '../types';
|
|
11
8
|
import AnimatedTopView from '../components/header/AnimatedTopView';
|
|
12
9
|
import useCollapsibleContext from '../hooks/useCollapsibleContext';
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
const AnimatedFlashList = Animated.createAnimatedComponent(FlashList);
|
|
10
|
+
import { AnimatedFlashList, FlashListProps } from '@shopify/flash-list';
|
|
11
|
+
import type { ScrollToIndexParams } from '../types';
|
|
16
12
|
|
|
17
13
|
type Props<Data> = FlashListProps<Data> & CollapsibleProps;
|
|
18
14
|
|
|
@@ -39,7 +35,7 @@ export default function CollapsibleFlashList<Data>({
|
|
|
39
35
|
});
|
|
40
36
|
}, []);
|
|
41
37
|
|
|
42
|
-
const scrollToIndex = useCallback((params) => {
|
|
38
|
+
const scrollToIndex = useCallback((params: ScrollToIndexParams) => {
|
|
43
39
|
scrollViewRef.current?.scrollToIndex?.(params);
|
|
44
40
|
}, []);
|
|
45
41
|
|
|
@@ -73,11 +69,15 @@ export default function CollapsibleFlashList<Data>({
|
|
|
73
69
|
|
|
74
70
|
const handleScrollToIndexFailed = useCallback(() => {}, []);
|
|
75
71
|
|
|
72
|
+
const ListHeaderComponent = props.ListHeaderComponent;
|
|
76
73
|
function renderListHeader() {
|
|
77
74
|
return (
|
|
78
75
|
<View>
|
|
79
76
|
<AnimatedTopView height={headerHeight} />
|
|
80
|
-
{
|
|
77
|
+
{ListHeaderComponent &&
|
|
78
|
+
(typeof ListHeaderComponent === 'function'
|
|
79
|
+
? React.createElement(ListHeaderComponent)
|
|
80
|
+
: ListHeaderComponent)}
|
|
81
81
|
</View>
|
|
82
82
|
);
|
|
83
83
|
}
|
|
@@ -13,6 +13,7 @@ import type { CollapsibleProps } from '../types';
|
|
|
13
13
|
import AnimatedTopView from '../components/header/AnimatedTopView';
|
|
14
14
|
import useCollapsibleContext from '../hooks/useCollapsibleContext';
|
|
15
15
|
import { AnimatedLegendList } from '@legendapp/list/reanimated';
|
|
16
|
+
import type { ScrollToIndexParams } from '../types';
|
|
16
17
|
|
|
17
18
|
type Props<Data> = FlatListProps<Data> & CollapsibleProps;
|
|
18
19
|
|
|
@@ -38,7 +39,7 @@ export default function CollapsibleLegendList<Data>({
|
|
|
38
39
|
});
|
|
39
40
|
}, []);
|
|
40
41
|
|
|
41
|
-
const scrollToIndex = useCallback((params) => {
|
|
42
|
+
const scrollToIndex = useCallback((params: ScrollToIndexParams) => {
|
|
42
43
|
scrollViewRef.current?.scrollToIndex?.(params);
|
|
43
44
|
}, []);
|
|
44
45
|
|
|
@@ -72,11 +73,15 @@ export default function CollapsibleLegendList<Data>({
|
|
|
72
73
|
|
|
73
74
|
const handleScrollToIndexFailed = useCallback(() => {}, []);
|
|
74
75
|
|
|
76
|
+
const ListHeaderComponent = props.ListHeaderComponent;
|
|
75
77
|
function renderListHeader() {
|
|
76
78
|
return (
|
|
77
79
|
<View>
|
|
78
80
|
<AnimatedTopView height={headerHeight} />
|
|
79
|
-
{
|
|
81
|
+
{ListHeaderComponent &&
|
|
82
|
+
(typeof ListHeaderComponent === 'function'
|
|
83
|
+
? React.createElement(ListHeaderComponent)
|
|
84
|
+
: ListHeaderComponent)}
|
|
80
85
|
</View>
|
|
81
86
|
);
|
|
82
87
|
}
|
|
@@ -101,6 +106,7 @@ export default function CollapsibleLegendList<Data>({
|
|
|
101
106
|
ListHeaderComponent={renderListHeader()}
|
|
102
107
|
//@ts-ignore
|
|
103
108
|
simultaneousHandlers={[]}
|
|
109
|
+
// @ts-ignore
|
|
104
110
|
animatedProps={animatedProps}
|
|
105
111
|
/>
|
|
106
112
|
</View>
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
import type { LayoutRectangle, SectionListScrollParams } from 'react-native';
|
|
3
|
-
import type
|
|
3
|
+
import type { SharedValue } from 'react-native-reanimated';
|
|
4
4
|
|
|
5
5
|
export type ScrollToIndexParams = {
|
|
6
6
|
animated?: boolean | null;
|
|
@@ -27,9 +27,9 @@ export type CollapsibleHandles = {
|
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
export type CollapsibleContextType = CollapsibleHandles & {
|
|
30
|
-
scrollY:
|
|
31
|
-
headerHeight:
|
|
32
|
-
headerCollapsed:
|
|
30
|
+
scrollY: SharedValue<number>;
|
|
31
|
+
headerHeight: SharedValue<number>;
|
|
32
|
+
headerCollapsed: SharedValue<boolean>;
|
|
33
33
|
/**
|
|
34
34
|
* Scroll to specific view
|
|
35
35
|
* @param ref View that you want to scroll to
|
|
@@ -49,13 +49,13 @@ export type LayoutParams = {
|
|
|
49
49
|
export type CollapsibleContextInternalType = {
|
|
50
50
|
scrollViewRef: React.RefObject<any>;
|
|
51
51
|
containerRef: React.RefObject<any>;
|
|
52
|
-
containerHeight:
|
|
53
|
-
contentMinHeight:
|
|
54
|
-
headerViewPositions:
|
|
52
|
+
containerHeight: SharedValue<number>;
|
|
53
|
+
contentMinHeight: SharedValue<number>;
|
|
54
|
+
headerViewPositions: SharedValue<
|
|
55
55
|
Record<string, { top: number; stickyHeight: number }>
|
|
56
56
|
>;
|
|
57
|
-
fixedHeaderHeight:
|
|
58
|
-
headerHeight:
|
|
57
|
+
fixedHeaderHeight: SharedValue<number>;
|
|
58
|
+
headerHeight: SharedValue<number>;
|
|
59
59
|
handleHeaderContainerLayout: (
|
|
60
60
|
key: string,
|
|
61
61
|
layout?: LayoutRectangle,
|
|
@@ -69,7 +69,7 @@ export type CollapsibleProps = {
|
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
export type PullToRefreshContextType = {
|
|
72
|
-
refreshValue:
|
|
73
|
-
internalRefreshing:
|
|
74
|
-
internalHeight:
|
|
72
|
+
refreshValue: SharedValue<number>;
|
|
73
|
+
internalRefreshing: SharedValue<boolean>;
|
|
74
|
+
internalHeight: SharedValue<number>;
|
|
75
75
|
};
|
|
@@ -1,18 +1,49 @@
|
|
|
1
1
|
import { useCallback, useRef } from 'react';
|
|
2
|
-
import
|
|
2
|
+
import { SharedValue, useSharedValue } from 'react-native-reanimated';
|
|
3
|
+
|
|
4
|
+
function shallowEqualKeys(
|
|
5
|
+
a: Record<string, unknown>,
|
|
6
|
+
b: Record<string, unknown>
|
|
7
|
+
): boolean {
|
|
8
|
+
for (const k in a) {
|
|
9
|
+
if (a[k] !== b[k]) return false;
|
|
10
|
+
}
|
|
11
|
+
for (const k in b) {
|
|
12
|
+
if (!(k in a)) return false;
|
|
13
|
+
}
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
3
16
|
|
|
4
17
|
export default function useSharedValueRef<T>(
|
|
5
18
|
defaultValue: T
|
|
6
|
-
): [
|
|
19
|
+
): [SharedValue<T>, (value: T) => void] {
|
|
7
20
|
const sharedValue = useSharedValue<T>(defaultValue);
|
|
8
21
|
const savedValue = useRef<T>(defaultValue);
|
|
9
22
|
|
|
10
23
|
const appendValue = useCallback(
|
|
11
24
|
(value: T) => {
|
|
12
|
-
savedValue.current
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
25
|
+
const current = savedValue.current as Record<string, unknown>;
|
|
26
|
+
const next = value as Record<string, unknown>;
|
|
27
|
+
// Quick path: same reference means no change.
|
|
28
|
+
if (current === next) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// Build the merged map: take current, overlay next, then drop any
|
|
32
|
+
// resulting `undefined` slots so long-lived consumers don't
|
|
33
|
+
// accumulate stale keys across mount/unmount cycles.
|
|
34
|
+
const merged: Record<string, unknown> = { ...current, ...next };
|
|
35
|
+
for (const k in merged) {
|
|
36
|
+
if (merged[k] === undefined) {
|
|
37
|
+
delete merged[k];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Skip the shared-value write if the merged map is shallow-equal to
|
|
41
|
+
// the previous one. This protects readers (useDerivedValue
|
|
42
|
+
// Object.values(...).reduce) from re-running on no-op updates.
|
|
43
|
+
if (shallowEqualKeys(merged, current)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
savedValue.current = merged as T;
|
|
16
47
|
sharedValue.value = savedValue.current;
|
|
17
48
|
},
|
|
18
49
|
[sharedValue]
|
|
@@ -8,7 +8,7 @@ import type { LayoutRectangle, View } from 'react-native';
|
|
|
8
8
|
|
|
9
9
|
export default function withCollapsibleContext<T>(Component: FC<T>) {
|
|
10
10
|
return (props: T) => {
|
|
11
|
-
const collapsibleHandlers = useRef<CollapsibleHandles>();
|
|
11
|
+
const collapsibleHandlers = useRef<CollapsibleHandles>(null);
|
|
12
12
|
const headerHeight = useSharedValue(0);
|
|
13
13
|
const scrollY = useSharedValue(0);
|
|
14
14
|
const fixedHeaderHeight = useSharedValue(0);
|
|
@@ -20,9 +20,12 @@ export default function withCollapsibleContext<T>(Component: FC<T>) {
|
|
|
20
20
|
>({});
|
|
21
21
|
const headerViewPositions = useSharedValue({});
|
|
22
22
|
|
|
23
|
-
const setCollapsibleHandlers = useCallback(
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
const setCollapsibleHandlers = useCallback(
|
|
24
|
+
(handlers: CollapsibleHandles) => {
|
|
25
|
+
collapsibleHandlers.current = handlers;
|
|
26
|
+
},
|
|
27
|
+
[]
|
|
28
|
+
);
|
|
26
29
|
|
|
27
30
|
const headerCollapsed = useDerivedValue(() => {
|
|
28
31
|
const maxY = fixedHeaderHeight.value;
|