@r0b0t3d/react-native-collapsible 1.3.5-beta.4 → 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 (44) 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 -85
  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/hooks/useCollapsibleHeaderConsumerContext.js +21 -0
  10. package/lib/commonjs/hooks/useCollapsibleHeaderConsumerContext.js.map +1 -0
  11. package/lib/commonjs/withCollapsibleContext.js +0 -2
  12. package/lib/commonjs/withCollapsibleContext.js.map +1 -1
  13. package/lib/module/components/CollapsibleContainer.js +3 -2
  14. package/lib/module/components/CollapsibleContainer.js.map +1 -1
  15. package/lib/module/components/header/CollapsibleHeaderConsumer.js +57 -0
  16. package/lib/module/components/header/CollapsibleHeaderConsumer.js.map +1 -0
  17. package/lib/module/components/header/CollapsibleHeaderContainer.js +25 -86
  18. package/lib/module/components/header/CollapsibleHeaderContainer.js.map +1 -1
  19. package/lib/module/components/header/CollapsibleHeaderContainerProvider.js +96 -0
  20. package/lib/module/components/header/CollapsibleHeaderContainerProvider.js.map +1 -0
  21. package/lib/module/hooks/useCollapsibleHeaderConsumerContext.js +13 -0
  22. package/lib/module/hooks/useCollapsibleHeaderConsumerContext.js.map +1 -0
  23. package/lib/module/withCollapsibleContext.js +0 -2
  24. package/lib/module/withCollapsibleContext.js.map +1 -1
  25. package/lib/typescript/components/CollapsibleContainer.d.ts.map +1 -1
  26. package/lib/typescript/components/header/CollapsibleHeaderConsumer.d.ts +9 -0
  27. package/lib/typescript/components/header/CollapsibleHeaderConsumer.d.ts.map +1 -0
  28. package/lib/typescript/components/header/CollapsibleHeaderContainer.d.ts +2 -2
  29. package/lib/typescript/components/header/CollapsibleHeaderContainer.d.ts.map +1 -1
  30. package/lib/typescript/components/header/CollapsibleHeaderContainerProvider.d.ts +10 -0
  31. package/lib/typescript/components/header/CollapsibleHeaderContainerProvider.d.ts.map +1 -0
  32. package/lib/typescript/hooks/useCollapsibleHeaderConsumerContext.d.ts +15 -0
  33. package/lib/typescript/hooks/useCollapsibleHeaderConsumerContext.d.ts.map +1 -0
  34. package/lib/typescript/types.d.ts +1 -2
  35. package/lib/typescript/types.d.ts.map +1 -1
  36. package/lib/typescript/withCollapsibleContext.d.ts.map +1 -1
  37. package/package.json +1 -1
  38. package/src/components/CollapsibleContainer.tsx +4 -3
  39. package/src/components/header/CollapsibleHeaderConsumer.tsx +78 -0
  40. package/src/components/header/CollapsibleHeaderContainer.tsx +27 -143
  41. package/src/components/header/CollapsibleHeaderContainerProvider.tsx +162 -0
  42. package/src/hooks/useCollapsibleHeaderConsumerContext.ts +22 -0
  43. package/src/types.ts +1 -2
  44. package/src/withCollapsibleContext.tsx +0 -2
@@ -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,63 +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
- setStickyLayouts({
90
- [stickyKey]: layout,
91
- });
92
- },
93
- [setStickyLayouts]
94
- );
18
+ const { mount, unmount, update } = useCollapsibleHeaderConsumerContext();
95
19
 
96
20
  const internalStyle = useMemo(() => {
97
21
  return {
@@ -99,71 +23,31 @@ export default function CollapsibleHeaderContainer({
99
23
  };
100
24
  }, []);
101
25
 
102
- const translateY = useDerivedValue(() => {
103
- const position = headerViewPositions.value[contentKey];
104
- if (!currentLayout.value || !position) {
105
- return scrollY.value;
106
- }
107
- const topPosition =
108
- currentLayout.value.height +
109
- currentLayout.value.y -
110
- position.top -
111
- position.stickyHeight;
112
-
113
- return interpolate(
114
- scrollY.value,
115
- [0, topPosition, 10000],
116
- [0, -topPosition, -topPosition],
117
- 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>
118
35
  );
119
- });
36
+ }, [children, containerStyle, contentKey, internalStyle]);
120
37
 
121
- const animatedStyle = useAnimatedStyle(() => {
122
- return {
123
- transform: [
124
- {
125
- translateY: translateY.value,
126
- },
127
- ],
128
- };
129
- });
130
-
131
- const animatedY = useDerivedValue(() => {
132
- const position = headerViewPositions.value[contentKey];
133
- if (!currentLayout.value || !position) {
134
- return 0;
135
- }
136
- const value = scrollY.value - currentLayout.value.y + position.top;
137
- const maxV = currentLayout.value.height - stickyHeight.value;
38
+ useEffect(() => {
39
+ mount(contentKey, content);
138
40
 
139
- return Math.max(0, Math.min(value, maxV));
140
- });
41
+ return () => {
42
+ unmount(contentKey);
43
+ };
44
+ // eslint-disable-next-line react-hooks/exhaustive-deps
45
+ }, [contentKey]);
141
46
 
142
- const value: CollapsibleContextHeaderType = useMemo(
143
- () => ({
144
- handleStickyViewLayout,
145
- animatedY,
146
- }),
147
- [handleStickyViewLayout, animatedY]
148
- );
47
+ useEffect(() => {
48
+ update(contentKey, content);
49
+ // eslint-disable-next-line react-hooks/exhaustive-deps
50
+ }, [content]);
149
51
 
150
- return (
151
- <CollapsibleHeaderContext.Provider value={value}>
152
- <Animated.View
153
- key={contentKey}
154
- style={[styles.container, containerStyle, internalStyle, animatedStyle]}
155
- pointerEvents="box-none"
156
- onLayout={handleLayout}
157
- >
158
- {children}
159
- </Animated.View>
160
- </CollapsibleHeaderContext.Provider>
161
- );
52
+ return null;
162
53
  }
163
-
164
- const styles = StyleSheet.create({
165
- container: {
166
- overflow: 'hidden',
167
- backgroundColor: 'white',
168
- },
169
- });
@@ -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
+ });
@@ -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,