@r0b0t3d/react-native-collapsible 1.2.1 → 1.3.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 +5 -2
- package/lib/commonjs/components/CollapsibleContainer.js.map +1 -1
- package/lib/commonjs/components/header/AnimatedTopView.js +2 -1
- package/lib/commonjs/components/header/AnimatedTopView.js.map +1 -1
- package/lib/commonjs/components/header/CollapsibleHeaderConsumer.js +67 -0
- package/lib/commonjs/components/header/CollapsibleHeaderConsumer.js.map +1 -0
- package/lib/commonjs/components/header/CollapsibleHeaderContainer.js +15 -62
- package/lib/commonjs/components/header/CollapsibleHeaderContainer.js.map +1 -1
- package/lib/commonjs/components/header/CollapsibleHeaderProvider.js +62 -0
- package/lib/commonjs/components/header/CollapsibleHeaderProvider.js.map +1 -0
- package/lib/commonjs/components/scrollable/CollapsibleScrollView.js +0 -6
- package/lib/commonjs/components/scrollable/CollapsibleScrollView.js.map +1 -1
- package/lib/commonjs/hooks/useCollapsibleHeaderContext.js +26 -0
- package/lib/commonjs/hooks/useCollapsibleHeaderContext.js.map +1 -0
- package/lib/commonjs/withCollapsibleContext.js +6 -15
- package/lib/commonjs/withCollapsibleContext.js.map +1 -1
- package/lib/module/components/CollapsibleContainer.js +4 -2
- package/lib/module/components/CollapsibleContainer.js.map +1 -1
- package/lib/module/components/header/AnimatedTopView.js +2 -1
- package/lib/module/components/header/AnimatedTopView.js.map +1 -1
- package/lib/module/components/header/CollapsibleHeaderConsumer.js +47 -0
- package/lib/module/components/header/CollapsibleHeaderConsumer.js.map +1 -0
- package/lib/module/components/header/CollapsibleHeaderContainer.js +15 -54
- package/lib/module/components/header/CollapsibleHeaderContainer.js.map +1 -1
- package/lib/module/components/header/CollapsibleHeaderProvider.js +49 -0
- package/lib/module/components/header/CollapsibleHeaderProvider.js.map +1 -0
- package/lib/module/components/scrollable/CollapsibleScrollView.js +0 -6
- package/lib/module/components/scrollable/CollapsibleScrollView.js.map +1 -1
- package/lib/module/hooks/useCollapsibleHeaderContext.js +15 -0
- package/lib/module/hooks/useCollapsibleHeaderContext.js.map +1 -0
- package/lib/module/withCollapsibleContext.js +5 -15
- package/lib/module/withCollapsibleContext.js.map +1 -1
- package/lib/typescript/components/header/CollapsibleHeaderConsumer.d.ts +1 -0
- package/lib/typescript/components/header/CollapsibleHeaderContainer.d.ts +2 -2
- package/lib/typescript/components/header/CollapsibleHeaderProvider.d.ts +4 -0
- package/lib/typescript/hooks/useCollapsibleHeaderContext.d.ts +14 -0
- package/lib/typescript/types.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/CollapsibleContainer.tsx +3 -0
- package/src/components/header/AnimatedTopView.tsx +1 -0
- package/src/components/header/CollapsibleHeaderConsumer.tsx +61 -0
- package/src/components/header/CollapsibleHeaderContainer.tsx +13 -82
- package/src/components/header/CollapsibleHeaderProvider.tsx +70 -0
- package/src/components/scrollable/CollapsibleScrollView.tsx +0 -6
- package/src/hooks/useCollapsibleHeaderContext.ts +22 -0
- package/src/types.ts +1 -1
- package/src/withCollapsibleContext.tsx +15 -26
|
@@ -1,21 +1,7 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/exhaustive-deps */
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
LayoutChangeEvent,
|
|
6
|
-
Platform,
|
|
7
|
-
StyleProp,
|
|
8
|
-
StyleSheet,
|
|
9
|
-
View,
|
|
10
|
-
ViewStyle,
|
|
11
|
-
} from 'react-native';
|
|
12
|
-
import Animated, {
|
|
13
|
-
interpolate,
|
|
14
|
-
useAnimatedStyle,
|
|
15
|
-
useDerivedValue,
|
|
16
|
-
useSharedValue,
|
|
17
|
-
} from 'react-native-reanimated';
|
|
18
|
-
import useCollapsibleContext from '../../hooks/useCollapsibleContext';
|
|
2
|
+
import { ReactNode, useEffect, useMemo } from 'react';
|
|
3
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
4
|
+
import useCollapsibleHeaderContext from '../../hooks/useCollapsibleHeaderContext';
|
|
19
5
|
|
|
20
6
|
type Props = {
|
|
21
7
|
children: ReactNode;
|
|
@@ -24,76 +10,21 @@ type Props = {
|
|
|
24
10
|
|
|
25
11
|
let key = 0;
|
|
26
12
|
|
|
27
|
-
export default function CollapsibleHeaderContainer({
|
|
28
|
-
children,
|
|
29
|
-
containerStyle,
|
|
30
|
-
}: Props) {
|
|
13
|
+
export default function CollapsibleHeaderContainer({ children }: Props) {
|
|
31
14
|
const contentKey = useMemo(() => `collapsible-header-${key++}`, []);
|
|
32
|
-
const {
|
|
33
|
-
const { handleHeaderContainerLayout } = useInternalCollapsibleContext();
|
|
34
|
-
const headerHeight = useSharedValue(0);
|
|
15
|
+
const { mount, unmount, update } = useCollapsibleHeaderContext();
|
|
35
16
|
|
|
36
17
|
useEffect(() => {
|
|
37
|
-
|
|
38
|
-
}, []);
|
|
18
|
+
mount(contentKey, children);
|
|
39
19
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
nativeEvent: {
|
|
43
|
-
layout: { height },
|
|
44
|
-
},
|
|
45
|
-
}: LayoutChangeEvent) => {
|
|
46
|
-
headerHeight.value = height;
|
|
47
|
-
handleHeaderContainerLayout(contentKey, height);
|
|
48
|
-
},
|
|
49
|
-
[contentKey]
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
const headerTranslate = useDerivedValue(
|
|
53
|
-
() =>
|
|
54
|
-
interpolate(
|
|
55
|
-
scrollY.value,
|
|
56
|
-
// FIXME: can improve by geting maxY value of header and sticky views
|
|
57
|
-
[-250, 0, 100000],
|
|
58
|
-
[250, 0, -100000],
|
|
59
|
-
Animated.Extrapolate.CLAMP
|
|
60
|
-
),
|
|
61
|
-
[]
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
const headerStyle = useAnimatedStyle(() => {
|
|
65
|
-
return {
|
|
66
|
-
transform: [{ translateY: headerTranslate.value }],
|
|
67
|
-
minHeight: headerHeight.value,
|
|
20
|
+
return () => {
|
|
21
|
+
unmount(contentKey);
|
|
68
22
|
};
|
|
69
|
-
}, [
|
|
23
|
+
}, [contentKey]);
|
|
70
24
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
};
|
|
75
|
-
}, []);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
update(contentKey, children);
|
|
27
|
+
}, [children]);
|
|
76
28
|
|
|
77
|
-
return
|
|
78
|
-
<Animated.View
|
|
79
|
-
style={[headerStyle, internalStyle]}
|
|
80
|
-
pointerEvents="box-none"
|
|
81
|
-
>
|
|
82
|
-
<View
|
|
83
|
-
key={contentKey}
|
|
84
|
-
onLayout={handleHeaderLayout}
|
|
85
|
-
pointerEvents="box-none"
|
|
86
|
-
style={[styles.container, containerStyle]}
|
|
87
|
-
>
|
|
88
|
-
{children}
|
|
89
|
-
</View>
|
|
90
|
-
</Animated.View>
|
|
91
|
-
);
|
|
29
|
+
return null;
|
|
92
30
|
}
|
|
93
|
-
|
|
94
|
-
const styles = StyleSheet.create({
|
|
95
|
-
container: {
|
|
96
|
-
backgroundColor: 'white',
|
|
97
|
-
marginTop: Platform.OS === 'android' ? -1 : 0,
|
|
98
|
-
},
|
|
99
|
-
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/* eslint-disable no-shadow */
|
|
2
|
+
import React, {
|
|
3
|
+
ReactNode,
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from 'react';
|
|
10
|
+
import {
|
|
11
|
+
CollapsibleHeaderContext,
|
|
12
|
+
HeaderItem,
|
|
13
|
+
} from '../../hooks/useCollapsibleHeaderContext';
|
|
14
|
+
|
|
15
|
+
export default function CollapsibleHeaderProvider({
|
|
16
|
+
children,
|
|
17
|
+
}: {
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
}) {
|
|
20
|
+
const [headers, setHeaders] = useState<HeaderItem[]>([]);
|
|
21
|
+
const mounted = useRef(false);
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
mounted.current = true;
|
|
25
|
+
return () => {
|
|
26
|
+
mounted.current = false;
|
|
27
|
+
};
|
|
28
|
+
}, []);
|
|
29
|
+
|
|
30
|
+
const mount = useCallback((key: string, children: ReactNode) => {
|
|
31
|
+
setHeaders((prev) => [...prev, { key, children }]);
|
|
32
|
+
}, []);
|
|
33
|
+
|
|
34
|
+
const unmount = useCallback((key: string) => {
|
|
35
|
+
setHeaders((prev) => prev.filter((h) => h.key !== key));
|
|
36
|
+
}, []);
|
|
37
|
+
|
|
38
|
+
const update = useCallback((key: string, children: ReactNode) => {
|
|
39
|
+
if (!mounted.current) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
setHeaders((prev) =>
|
|
43
|
+
prev.map((item) => {
|
|
44
|
+
if (item.key === key) {
|
|
45
|
+
return {
|
|
46
|
+
...item,
|
|
47
|
+
children,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return item;
|
|
51
|
+
})
|
|
52
|
+
);
|
|
53
|
+
}, []);
|
|
54
|
+
|
|
55
|
+
const context = useMemo(
|
|
56
|
+
() => ({
|
|
57
|
+
headers,
|
|
58
|
+
mount,
|
|
59
|
+
unmount,
|
|
60
|
+
update,
|
|
61
|
+
}),
|
|
62
|
+
[headers, mount, unmount, update]
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<CollapsibleHeaderContext.Provider value={context}>
|
|
67
|
+
{children}
|
|
68
|
+
</CollapsibleHeaderContext.Provider>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createContext, ReactNode, useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
export type HeaderItem = { key: string; children: ReactNode };
|
|
4
|
+
|
|
5
|
+
type CollapsibleContextHeaderType = {
|
|
6
|
+
headers: HeaderItem[];
|
|
7
|
+
mount: (key: string, header: ReactNode) => void;
|
|
8
|
+
update: (key: string, header: ReactNode) => void;
|
|
9
|
+
unmount: (key: string) => void;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const CollapsibleHeaderContext =
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
createContext<CollapsibleContextHeaderType>({});
|
|
15
|
+
|
|
16
|
+
export default function useCollapsibleHeaderContext() {
|
|
17
|
+
const ctx = useContext(CollapsibleHeaderContext);
|
|
18
|
+
if (!ctx) {
|
|
19
|
+
throw new Error('Component should be wrapped CollapsibleHeaderProvider');
|
|
20
|
+
}
|
|
21
|
+
return ctx;
|
|
22
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -42,7 +42,7 @@ export type CollapsibleContextInternalType = {
|
|
|
42
42
|
viewKey: string,
|
|
43
43
|
viewRef?: React.RefObject<View>
|
|
44
44
|
) => void;
|
|
45
|
-
handleHeaderContainerLayout: (
|
|
45
|
+
handleHeaderContainerLayout: (height: number) => void;
|
|
46
46
|
setCollapsibleHandlers: (handlers: CollapsibleHandles) => void;
|
|
47
47
|
};
|
|
48
48
|
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import type { View } from 'react-native';
|
|
14
14
|
import { debounce } from './utils/debounce';
|
|
15
15
|
import PullToRefreshProvider from './components/pullToRefresh/PullToRefreshProvider';
|
|
16
|
+
import CollapsibleHeaderProvider from './components/header/CollapsibleHeaderProvider';
|
|
16
17
|
|
|
17
18
|
export default function withCollapsibleContext<T>(Component: FC<T>) {
|
|
18
19
|
return (props: T) => {
|
|
@@ -29,13 +30,10 @@ export default function withCollapsibleContext<T>(Component: FC<T>) {
|
|
|
29
30
|
const stickyHeaderHeight = useSharedValue(0);
|
|
30
31
|
const containerHeight = useSharedValue(0);
|
|
31
32
|
const firstStickyViewY = useSharedValue(1000000);
|
|
32
|
-
const headerContainersHeight = useRef<Record<string, number>>({});
|
|
33
33
|
const containerRef = useRef<View>(null);
|
|
34
34
|
const scrollViewRef = useRef<View>(null);
|
|
35
35
|
|
|
36
36
|
const setCollapsibleHandlers = useCallback((handlers) => {
|
|
37
|
-
console.log({ handlers });
|
|
38
|
-
|
|
39
37
|
collapsibleHandlers.current = handlers;
|
|
40
38
|
}, []);
|
|
41
39
|
|
|
@@ -128,26 +126,14 @@ export default function withCollapsibleContext<T>(Component: FC<T>) {
|
|
|
128
126
|
}, 200);
|
|
129
127
|
}, []);
|
|
130
128
|
|
|
131
|
-
const handleHeaderContainerLayout = useCallback(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
(acc, key) => headerContainersHeight.current[key] + acc,
|
|
140
|
-
0
|
|
141
|
-
);
|
|
142
|
-
headerHeight.value = withTiming(totalHeight, {
|
|
143
|
-
duration: fixedHeaderHeight.value === 0 ? 0 : 10,
|
|
144
|
-
});
|
|
145
|
-
fixedHeaderHeight.value = totalHeight;
|
|
146
|
-
// Try refresh sticky positions
|
|
147
|
-
debounceRefreshStickyPositions();
|
|
148
|
-
},
|
|
149
|
-
[]
|
|
150
|
-
);
|
|
129
|
+
const handleHeaderContainerLayout = useCallback((height: number) => {
|
|
130
|
+
headerHeight.value = withTiming(height, {
|
|
131
|
+
duration: fixedHeaderHeight.value === 0 ? 0 : 10,
|
|
132
|
+
});
|
|
133
|
+
fixedHeaderHeight.value = height;
|
|
134
|
+
// Try refresh sticky positions
|
|
135
|
+
debounceRefreshStickyPositions();
|
|
136
|
+
}, []);
|
|
151
137
|
|
|
152
138
|
const handleContainerHeight = useCallback((height: number) => {
|
|
153
139
|
containerHeight.value = height;
|
|
@@ -198,9 +184,12 @@ export default function withCollapsibleContext<T>(Component: FC<T>) {
|
|
|
198
184
|
return (
|
|
199
185
|
<CollapsibleContext.Provider value={context}>
|
|
200
186
|
<InternalCollapsibleContext.Provider value={internalContext}>
|
|
201
|
-
<
|
|
202
|
-
<
|
|
203
|
-
|
|
187
|
+
<CollapsibleHeaderProvider>
|
|
188
|
+
<PullToRefreshProvider>
|
|
189
|
+
{/** @ts-ignore */}
|
|
190
|
+
<Component {...props} />
|
|
191
|
+
</PullToRefreshProvider>
|
|
192
|
+
</CollapsibleHeaderProvider>
|
|
204
193
|
</InternalCollapsibleContext.Provider>
|
|
205
194
|
</CollapsibleContext.Provider>
|
|
206
195
|
);
|