@r0b0t3d/react-native-collapsible 1.3.5-beta.3 → 1.3.5-beta.5

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 (50) hide show
  1. package/lib/commonjs/components/CollapsibleContainer.js +3 -2
  2. package/lib/commonjs/components/CollapsibleContainer.js.map +1 -1
  3. package/lib/commonjs/components/header/CollapsibleHeaderConsumer.js +65 -0
  4. package/lib/commonjs/components/header/CollapsibleHeaderConsumer.js.map +1 -0
  5. package/lib/commonjs/components/header/CollapsibleHeaderContainer.js +24 -86
  6. package/lib/commonjs/components/header/CollapsibleHeaderContainer.js.map +1 -1
  7. package/lib/commonjs/components/header/CollapsibleHeaderContainerProvider.js +105 -0
  8. package/lib/commonjs/components/header/CollapsibleHeaderContainerProvider.js.map +1 -0
  9. package/lib/commonjs/components/header/StickyView.js +0 -6
  10. package/lib/commonjs/components/header/StickyView.js.map +1 -1
  11. package/lib/commonjs/hooks/useCollapsibleHeaderConsumerContext.js +21 -0
  12. package/lib/commonjs/hooks/useCollapsibleHeaderConsumerContext.js.map +1 -0
  13. package/lib/commonjs/withCollapsibleContext.js +0 -2
  14. package/lib/commonjs/withCollapsibleContext.js.map +1 -1
  15. package/lib/module/components/CollapsibleContainer.js +3 -2
  16. package/lib/module/components/CollapsibleContainer.js.map +1 -1
  17. package/lib/module/components/header/CollapsibleHeaderConsumer.js +57 -0
  18. package/lib/module/components/header/CollapsibleHeaderConsumer.js.map +1 -0
  19. package/lib/module/components/header/CollapsibleHeaderContainer.js +25 -87
  20. package/lib/module/components/header/CollapsibleHeaderContainer.js.map +1 -1
  21. package/lib/module/components/header/CollapsibleHeaderContainerProvider.js +96 -0
  22. package/lib/module/components/header/CollapsibleHeaderContainerProvider.js.map +1 -0
  23. package/lib/module/components/header/StickyView.js +0 -6
  24. package/lib/module/components/header/StickyView.js.map +1 -1
  25. package/lib/module/hooks/useCollapsibleHeaderConsumerContext.js +13 -0
  26. package/lib/module/hooks/useCollapsibleHeaderConsumerContext.js.map +1 -0
  27. package/lib/module/withCollapsibleContext.js +0 -2
  28. package/lib/module/withCollapsibleContext.js.map +1 -1
  29. package/lib/typescript/components/CollapsibleContainer.d.ts.map +1 -1
  30. package/lib/typescript/components/header/CollapsibleHeaderConsumer.d.ts +9 -0
  31. package/lib/typescript/components/header/CollapsibleHeaderConsumer.d.ts.map +1 -0
  32. package/lib/typescript/components/header/CollapsibleHeaderContainer.d.ts +2 -2
  33. package/lib/typescript/components/header/CollapsibleHeaderContainer.d.ts.map +1 -1
  34. package/lib/typescript/components/header/CollapsibleHeaderContainerProvider.d.ts +10 -0
  35. package/lib/typescript/components/header/CollapsibleHeaderContainerProvider.d.ts.map +1 -0
  36. package/lib/typescript/components/header/StickyView.d.ts.map +1 -1
  37. package/lib/typescript/hooks/useCollapsibleHeaderConsumerContext.d.ts +15 -0
  38. package/lib/typescript/hooks/useCollapsibleHeaderConsumerContext.d.ts.map +1 -0
  39. package/lib/typescript/types.d.ts +1 -2
  40. package/lib/typescript/types.d.ts.map +1 -1
  41. package/lib/typescript/withCollapsibleContext.d.ts.map +1 -1
  42. package/package.json +1 -1
  43. package/src/components/CollapsibleContainer.tsx +4 -3
  44. package/src/components/header/CollapsibleHeaderConsumer.tsx +78 -0
  45. package/src/components/header/CollapsibleHeaderContainer.tsx +27 -145
  46. package/src/components/header/CollapsibleHeaderContainerProvider.tsx +162 -0
  47. package/src/components/header/StickyView.tsx +0 -2
  48. package/src/hooks/useCollapsibleHeaderConsumerContext.ts +22 -0
  49. package/src/types.ts +1 -2
  50. package/src/withCollapsibleContext.tsx +0 -2
@@ -0,0 +1,78 @@
1
+ import React, {
2
+ ReactNode,
3
+ useCallback,
4
+ useEffect,
5
+ useMemo,
6
+ useRef,
7
+ useState,
8
+ } from 'react';
9
+ import { StyleSheet, View } from 'react-native';
10
+ import { CollapsibleHeaderConsumerContext } from '../../hooks/useCollapsibleHeaderConsumerContext';
11
+
12
+ export type HeaderItem = { key: string; children: ReactNode };
13
+
14
+ export default function CollapsibleHeaderConsumer({
15
+ children,
16
+ }: {
17
+ children: ReactNode;
18
+ }) {
19
+ const [headers, setHeaders] = useState<HeaderItem[]>([]);
20
+ const mounted = useRef(false);
21
+
22
+ useEffect(() => {
23
+ mounted.current = true;
24
+ return () => {
25
+ mounted.current = false;
26
+ };
27
+ }, []);
28
+
29
+ const mount = useCallback((key: string, children: ReactNode) => {
30
+ setHeaders((prev) => [...prev, { key, children }]);
31
+ }, []);
32
+
33
+ const unmount = useCallback((key: string) => {
34
+ setHeaders((prev) => prev.filter((h) => h.key !== key));
35
+ }, []);
36
+
37
+ const update = useCallback((key: string, children: ReactNode) => {
38
+ if (!mounted.current) {
39
+ return;
40
+ }
41
+ setHeaders((prev) =>
42
+ prev.map((item) => {
43
+ if (item.key === key) {
44
+ return {
45
+ ...item,
46
+ children,
47
+ };
48
+ }
49
+ return item;
50
+ })
51
+ );
52
+ }, []);
53
+
54
+ const context = useMemo(
55
+ () => ({
56
+ headers,
57
+ mount,
58
+ unmount,
59
+ update,
60
+ }),
61
+ [headers, mount, unmount, update]
62
+ );
63
+
64
+ return (
65
+ <CollapsibleHeaderConsumerContext.Provider value={context}>
66
+ {children}
67
+ <View style={styles.container} pointerEvents="box-none">
68
+ {headers.map((item) => item.children)}
69
+ </View>
70
+ </CollapsibleHeaderConsumerContext.Provider>
71
+ );
72
+ }
73
+
74
+ const styles = StyleSheet.create({
75
+ container: {
76
+ zIndex: 10,
77
+ },
78
+ });
@@ -1,27 +1,7 @@
1
- import React, { ReactNode, useCallback, useEffect, useMemo } from 'react';
2
- import {
3
- StyleProp,
4
- ViewStyle,
5
- LayoutChangeEvent,
6
- LayoutRectangle,
7
- StyleSheet,
8
- } from 'react-native';
9
- import useInternalCollapsibleContext from '../../hooks/useInternalCollapsibleContext';
10
- import useCollapsibleContext from '../../hooks/useCollapsibleContext';
11
- import Animated, {
12
- Extrapolate,
13
- interpolate,
14
- runOnJS,
15
- useAnimatedReaction,
16
- useAnimatedStyle,
17
- useDerivedValue,
18
- useSharedValue,
19
- } from 'react-native-reanimated';
20
- import {
21
- CollapsibleContextHeaderType,
22
- CollapsibleHeaderContext,
23
- } from '../../hooks/useCollapsibleHeaderContext';
24
- import useSharedValueRef from '../../utils/useSharedValueRef';
1
+ import React, { ReactNode, useEffect, useMemo } from 'react';
2
+ import { StyleProp, ViewStyle } from 'react-native';
3
+ import useCollapsibleHeaderConsumerContext from '../../hooks/useCollapsibleHeaderConsumerContext';
4
+ import CollapsibleHeaderContainerProvider from './CollapsibleHeaderContainerProvider';
25
5
 
26
6
  type Props = {
27
7
  children: ReactNode;
@@ -35,65 +15,7 @@ export default function CollapsibleHeaderContainer({
35
15
  containerStyle,
36
16
  }: Props) {
37
17
  const contentKey = useMemo(() => `collapsible-header-${key++}`, []);
38
- const { handleHeaderContainerLayout, headerViewPositions } =
39
- useInternalCollapsibleContext();
40
- const { scrollY } = useCollapsibleContext();
41
- const currentLayout = useSharedValue<LayoutRectangle | undefined>(undefined);
42
- const [stickyLayouts, setStickyLayouts] = useSharedValueRef<
43
- Record<string, LayoutRectangle | undefined>
44
- >({});
45
-
46
- useEffect(() => {
47
- return () => {
48
- handleHeaderContainerLayout(contentKey);
49
- };
50
- // eslint-disable-next-line react-hooks/exhaustive-deps
51
- }, [contentKey]);
52
-
53
- const stickyHeight = useDerivedValue(
54
- () =>
55
- Object.values(stickyLayouts.value).reduce(
56
- (acc, value) => acc + (value?.height ?? 0),
57
- 0
58
- ),
59
- []
60
- );
61
-
62
- useAnimatedReaction(
63
- () => {
64
- if (!currentLayout.value) {
65
- return -1;
66
- }
67
- return currentLayout.value.height - stickyHeight.value;
68
- },
69
- (result, previous) => {
70
- if (result !== -1 && result !== previous) {
71
- runOnJS(handleHeaderContainerLayout)(
72
- contentKey,
73
- currentLayout.value,
74
- stickyHeight.value
75
- );
76
- }
77
- }
78
- );
79
-
80
- const handleLayout = useCallback(
81
- ({ nativeEvent: { layout } }: LayoutChangeEvent) => {
82
- currentLayout.value = layout;
83
- },
84
- [currentLayout]
85
- );
86
-
87
- const handleStickyViewLayout = useCallback(
88
- (stickyKey: string, layout?: LayoutRectangle) => {
89
- console.log('handleStickyViewLayout', stickyKey, layout);
90
-
91
- setStickyLayouts({
92
- [stickyKey]: layout,
93
- });
94
- },
95
- [setStickyLayouts]
96
- );
18
+ const { mount, unmount, update } = useCollapsibleHeaderConsumerContext();
97
19
 
98
20
  const internalStyle = useMemo(() => {
99
21
  return {
@@ -101,71 +23,31 @@ export default function CollapsibleHeaderContainer({
101
23
  };
102
24
  }, []);
103
25
 
104
- const translateY = useDerivedValue(() => {
105
- const position = headerViewPositions.value[contentKey];
106
- if (!currentLayout.value || !position) {
107
- return scrollY.value;
108
- }
109
- const topPosition =
110
- currentLayout.value.height +
111
- currentLayout.value.y -
112
- position.top -
113
- position.stickyHeight;
114
-
115
- return interpolate(
116
- scrollY.value,
117
- [0, topPosition, 10000],
118
- [0, -topPosition, -topPosition],
119
- Extrapolate.CLAMP
26
+ const content = useMemo(() => {
27
+ return (
28
+ <CollapsibleHeaderContainerProvider
29
+ containerStyle={[containerStyle, internalStyle]}
30
+ contentKey={contentKey}
31
+ key={contentKey}
32
+ >
33
+ {children}
34
+ </CollapsibleHeaderContainerProvider>
120
35
  );
121
- });
36
+ }, [children, containerStyle, contentKey, internalStyle]);
122
37
 
123
- const animatedStyle = useAnimatedStyle(() => {
124
- return {
125
- transform: [
126
- {
127
- translateY: translateY.value,
128
- },
129
- ],
130
- };
131
- });
132
-
133
- const animatedY = useDerivedValue(() => {
134
- const position = headerViewPositions.value[contentKey];
135
- if (!currentLayout.value || !position) {
136
- return 0;
137
- }
138
- const value = scrollY.value - currentLayout.value.y + position.top;
139
- const maxV = currentLayout.value.height - stickyHeight.value;
38
+ useEffect(() => {
39
+ mount(contentKey, content);
140
40
 
141
- return Math.max(0, Math.min(value, maxV));
142
- });
41
+ return () => {
42
+ unmount(contentKey);
43
+ };
44
+ // eslint-disable-next-line react-hooks/exhaustive-deps
45
+ }, [contentKey]);
143
46
 
144
- const value: CollapsibleContextHeaderType = useMemo(
145
- () => ({
146
- handleStickyViewLayout,
147
- animatedY,
148
- }),
149
- [handleStickyViewLayout, animatedY]
150
- );
47
+ useEffect(() => {
48
+ update(contentKey, content);
49
+ // eslint-disable-next-line react-hooks/exhaustive-deps
50
+ }, [content]);
151
51
 
152
- return (
153
- <CollapsibleHeaderContext.Provider value={value}>
154
- <Animated.View
155
- key={contentKey}
156
- style={[styles.container, containerStyle, internalStyle, animatedStyle]}
157
- pointerEvents="box-none"
158
- onLayout={handleLayout}
159
- >
160
- {children}
161
- </Animated.View>
162
- </CollapsibleHeaderContext.Provider>
163
- );
52
+ return null;
164
53
  }
165
-
166
- const styles = StyleSheet.create({
167
- container: {
168
- overflow: 'hidden',
169
- backgroundColor: 'white',
170
- },
171
- });
@@ -0,0 +1,162 @@
1
+ import React, { ReactNode, useCallback, useEffect, useMemo } from 'react';
2
+ import {
3
+ StyleProp,
4
+ ViewStyle,
5
+ LayoutChangeEvent,
6
+ LayoutRectangle,
7
+ StyleSheet,
8
+ } from 'react-native';
9
+ import useInternalCollapsibleContext from '../../hooks/useInternalCollapsibleContext';
10
+ import useCollapsibleContext from '../../hooks/useCollapsibleContext';
11
+ import Animated, {
12
+ Extrapolate,
13
+ interpolate,
14
+ runOnJS,
15
+ useAnimatedReaction,
16
+ useAnimatedStyle,
17
+ useDerivedValue,
18
+ useSharedValue,
19
+ } from 'react-native-reanimated';
20
+ import {
21
+ CollapsibleContextHeaderType,
22
+ CollapsibleHeaderContext,
23
+ } from '../../hooks/useCollapsibleHeaderContext';
24
+ import useSharedValueRef from '../../utils/useSharedValueRef';
25
+
26
+ type Props = {
27
+ children: ReactNode;
28
+ containerStyle?: StyleProp<ViewStyle>;
29
+ contentKey: string;
30
+ };
31
+
32
+ export default function CollapsibleHeaderContainerProvider({
33
+ children,
34
+ containerStyle,
35
+ contentKey,
36
+ }: Props) {
37
+ const { handleHeaderContainerLayout, headerViewPositions } =
38
+ useInternalCollapsibleContext();
39
+ const { scrollY } = useCollapsibleContext();
40
+ const currentLayout = useSharedValue<LayoutRectangle | undefined>(undefined);
41
+ const [stickyLayouts, setStickyLayouts] = useSharedValueRef<
42
+ Record<string, LayoutRectangle | undefined>
43
+ >({});
44
+
45
+ useEffect(() => {
46
+ return () => {
47
+ handleHeaderContainerLayout(contentKey);
48
+ };
49
+ // eslint-disable-next-line react-hooks/exhaustive-deps
50
+ }, [contentKey]);
51
+
52
+ const stickyHeight = useDerivedValue(
53
+ () =>
54
+ Object.values(stickyLayouts.value).reduce(
55
+ (acc, value) => acc + (value?.height ?? 0),
56
+ 0
57
+ ),
58
+ []
59
+ );
60
+
61
+ useAnimatedReaction(
62
+ () => {
63
+ if (!currentLayout.value) {
64
+ return -1;
65
+ }
66
+ return currentLayout.value.height - stickyHeight.value;
67
+ },
68
+ (result, previous) => {
69
+ if (result !== -1 && result !== previous) {
70
+ runOnJS(handleHeaderContainerLayout)(
71
+ contentKey,
72
+ currentLayout.value,
73
+ stickyHeight.value
74
+ );
75
+ }
76
+ }
77
+ );
78
+
79
+ const handleLayout = useCallback(
80
+ ({ nativeEvent: { layout } }: LayoutChangeEvent) => {
81
+ currentLayout.value = layout;
82
+ },
83
+ [currentLayout]
84
+ );
85
+
86
+ const handleStickyViewLayout = useCallback(
87
+ (stickyKey: string, layout?: LayoutRectangle) => {
88
+ setStickyLayouts({
89
+ [stickyKey]: layout,
90
+ });
91
+ },
92
+ [setStickyLayouts]
93
+ );
94
+
95
+ const translateY = useDerivedValue(() => {
96
+ const position = headerViewPositions.value[contentKey];
97
+ if (!currentLayout.value || !position) {
98
+ return scrollY.value;
99
+ }
100
+ const topPosition =
101
+ currentLayout.value.height +
102
+ currentLayout.value.y -
103
+ position.top -
104
+ position.stickyHeight;
105
+
106
+ return interpolate(
107
+ scrollY.value,
108
+ [0, topPosition, 10000],
109
+ [0, -topPosition, -topPosition],
110
+ Extrapolate.CLAMP
111
+ );
112
+ });
113
+
114
+ const animatedStyle = useAnimatedStyle(() => {
115
+ return {
116
+ transform: [
117
+ {
118
+ translateY: translateY.value,
119
+ },
120
+ ],
121
+ };
122
+ });
123
+
124
+ const animatedY = useDerivedValue(() => {
125
+ const position = headerViewPositions.value[contentKey];
126
+ if (!currentLayout.value || !position) {
127
+ return 0;
128
+ }
129
+ const value = scrollY.value - currentLayout.value.y + position.top;
130
+ const maxV = currentLayout.value.height - stickyHeight.value;
131
+
132
+ return Math.max(0, Math.min(value, maxV));
133
+ });
134
+
135
+ const value: CollapsibleContextHeaderType = useMemo(
136
+ () => ({
137
+ handleStickyViewLayout,
138
+ animatedY,
139
+ }),
140
+ [handleStickyViewLayout, animatedY]
141
+ );
142
+
143
+ return (
144
+ <CollapsibleHeaderContext.Provider value={value}>
145
+ <Animated.View
146
+ key={contentKey}
147
+ style={[styles.container, containerStyle, animatedStyle]}
148
+ pointerEvents="box-none"
149
+ onLayout={handleLayout}
150
+ >
151
+ {children}
152
+ </Animated.View>
153
+ </CollapsibleHeaderContext.Provider>
154
+ );
155
+ }
156
+
157
+ const styles = StyleSheet.create({
158
+ container: {
159
+ overflow: 'hidden',
160
+ backgroundColor: 'white',
161
+ },
162
+ });
@@ -49,8 +49,6 @@ export default function StickyView({ children, style }: Props) {
49
49
  const { height: stickyHeight, y: top } = currentLayout.value;
50
50
  const topValue = top;
51
51
 
52
- console.log({ key, animatedY: animatedY.value, top, stickyHeight });
53
-
54
52
  return interpolate(
55
53
  animatedY.value,
56
54
  [0, topValue, topValue + stickyHeight + 100],
@@ -0,0 +1,22 @@
1
+ import { createContext, ReactNode, useContext } from 'react';
2
+
3
+ export type HeaderItem = { key: string; children: ReactNode };
4
+
5
+ type CollapsibleContextHeaderConsumerType = {
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 CollapsibleHeaderConsumerContext =
13
+ // @ts-ignore
14
+ createContext<CollapsibleContextHeaderConsumerType>({});
15
+
16
+ export default function useCollapsibleHeaderConsumerContext() {
17
+ const ctx = useContext(CollapsibleHeaderConsumerContext);
18
+ if (!ctx) {
19
+ throw new Error('Component should be wrapped CollapsibleHeaderProvider');
20
+ }
21
+ return ctx;
22
+ }
package/src/types.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type React from 'react';
2
- import type { LayoutRectangle, View } from 'react-native';
2
+ import type { LayoutRectangle } from 'react-native';
3
3
  import type Animated from 'react-native-reanimated';
4
4
 
5
5
  export type ScrollToIndexParams = {
@@ -31,7 +31,6 @@ export type LayoutParams = {
31
31
 
32
32
  export type CollapsibleContextInternalType = {
33
33
  scrollViewRef: React.RefObject<any>;
34
- containerRef: React.RefObject<View>;
35
34
  contentMinHeight: Animated.SharedValue<number>;
36
35
  headerViewPositions: Animated.SharedValue<
37
36
  Record<string, { top: number; stickyHeight: number }>
@@ -17,7 +17,6 @@ export default function withCollapsibleContext<T>(Component: FC<T>) {
17
17
  const scrollY = useSharedValue(0);
18
18
  const fixedHeaderHeight = useSharedValue(0);
19
19
  const containerHeight = useSharedValue(0);
20
- const containerRef = useRef<View>(null);
21
20
  const scrollViewRef = useRef<View>(null);
22
21
  const headerContainerLayouts = useRef<
23
22
  Record<string, (LayoutRectangle & { stickyHeight?: number }) | undefined>
@@ -104,7 +103,6 @@ export default function withCollapsibleContext<T>(Component: FC<T>) {
104
103
  const internalContext = useMemo(
105
104
  () => ({
106
105
  scrollViewRef,
107
- containerRef,
108
106
  handleHeaderContainerLayout,
109
107
  setCollapsibleHandlers,
110
108
  handleContainerHeight,