@r0b0t3d/react-native-collapsible 1.2.2 → 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/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/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/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/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/CollapsibleHeaderConsumer.tsx +61 -0
- package/src/components/header/CollapsibleHeaderContainer.tsx +13 -82
- package/src/components/header/CollapsibleHeaderProvider.tsx +70 -0
- package/src/hooks/useCollapsibleHeaderContext.ts +22 -0
- package/src/types.ts +1 -1
- package/src/withCollapsibleContext.tsx +15 -26
|
@@ -1,64 +1,25 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/exhaustive-deps */
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { Platform, StyleSheet, View } from 'react-native';
|
|
5
|
-
import Animated, { interpolate, useAnimatedStyle, useDerivedValue, useSharedValue } from 'react-native-reanimated';
|
|
6
|
-
import useCollapsibleContext from '../../hooks/useCollapsibleContext';
|
|
2
|
+
import { useEffect, useMemo } from 'react';
|
|
3
|
+
import useCollapsibleHeaderContext from '../../hooks/useCollapsibleHeaderContext';
|
|
7
4
|
let key = 0;
|
|
8
5
|
export default function CollapsibleHeaderContainer({
|
|
9
|
-
children
|
|
10
|
-
containerStyle
|
|
6
|
+
children
|
|
11
7
|
}) {
|
|
12
8
|
const contentKey = useMemo(() => `collapsible-header-${key++}`, []);
|
|
13
9
|
const {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} = useInternalCollapsibleContext();
|
|
19
|
-
const headerHeight = useSharedValue(0);
|
|
10
|
+
mount,
|
|
11
|
+
unmount,
|
|
12
|
+
update
|
|
13
|
+
} = useCollapsibleHeaderContext();
|
|
20
14
|
useEffect(() => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
nativeEvent: {
|
|
25
|
-
layout: {
|
|
26
|
-
height
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}) => {
|
|
30
|
-
headerHeight.value = height;
|
|
31
|
-
handleHeaderContainerLayout(contentKey, height);
|
|
32
|
-
}, [contentKey]);
|
|
33
|
-
const headerTranslate = useDerivedValue(() => interpolate(scrollY.value, // FIXME: can improve by geting maxY value of header and sticky views
|
|
34
|
-
[-250, 0, 100000], [250, 0, -100000], Animated.Extrapolate.CLAMP), []);
|
|
35
|
-
const headerStyle = useAnimatedStyle(() => {
|
|
36
|
-
return {
|
|
37
|
-
transform: [{
|
|
38
|
-
translateY: headerTranslate.value
|
|
39
|
-
}],
|
|
40
|
-
minHeight: headerHeight.value
|
|
41
|
-
};
|
|
42
|
-
}, [headerHeight, headerTranslate]);
|
|
43
|
-
const internalStyle = useMemo(() => {
|
|
44
|
-
return {
|
|
45
|
-
zIndex: 100000 - key
|
|
15
|
+
mount(contentKey, children);
|
|
16
|
+
return () => {
|
|
17
|
+
unmount(contentKey);
|
|
46
18
|
};
|
|
47
|
-
}, []);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
key: contentKey,
|
|
53
|
-
onLayout: handleHeaderLayout,
|
|
54
|
-
pointerEvents: "box-none",
|
|
55
|
-
style: [styles.container, containerStyle]
|
|
56
|
-
}, children));
|
|
19
|
+
}, [contentKey]);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
update(contentKey, children);
|
|
22
|
+
}, [children]);
|
|
23
|
+
return null;
|
|
57
24
|
}
|
|
58
|
-
const styles = StyleSheet.create({
|
|
59
|
-
container: {
|
|
60
|
-
backgroundColor: 'white',
|
|
61
|
-
marginTop: Platform.OS === 'android' ? -1 : 0
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
25
|
//# sourceMappingURL=CollapsibleHeaderContainer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["CollapsibleHeaderContainer.tsx"],"names":["
|
|
1
|
+
{"version":3,"sources":["CollapsibleHeaderContainer.tsx"],"names":["useEffect","useMemo","useCollapsibleHeaderContext","key","CollapsibleHeaderContainer","children","contentKey","mount","unmount","update"],"mappings":"AAAA;AACA,SAAoBA,SAApB,EAA+BC,OAA/B,QAA8C,OAA9C;AAEA,OAAOC,2BAAP,MAAwC,yCAAxC;AAOA,IAAIC,GAAG,GAAG,CAAV;AAEA,eAAe,SAASC,0BAAT,CAAoC;AAAEC,EAAAA;AAAF,CAApC,EAAyD;AACtE,QAAMC,UAAU,GAAGL,OAAO,CAAC,MAAO,sBAAqBE,GAAG,EAAG,EAAnC,EAAsC,EAAtC,CAA1B;AACA,QAAM;AAAEI,IAAAA,KAAF;AAASC,IAAAA,OAAT;AAAkBC,IAAAA;AAAlB,MAA6BP,2BAA2B,EAA9D;AAEAF,EAAAA,SAAS,CAAC,MAAM;AACdO,IAAAA,KAAK,CAACD,UAAD,EAAaD,QAAb,CAAL;AAEA,WAAO,MAAM;AACXG,MAAAA,OAAO,CAACF,UAAD,CAAP;AACD,KAFD;AAGD,GANQ,EAMN,CAACA,UAAD,CANM,CAAT;AAQAN,EAAAA,SAAS,CAAC,MAAM;AACdS,IAAAA,MAAM,CAACH,UAAD,EAAaD,QAAb,CAAN;AACD,GAFQ,EAEN,CAACA,QAAD,CAFM,CAAT;AAIA,SAAO,IAAP;AACD","sourcesContent":["/* eslint-disable react-hooks/exhaustive-deps */\nimport { ReactNode, useEffect, useMemo } from 'react';\nimport type { StyleProp, ViewStyle } from 'react-native';\nimport useCollapsibleHeaderContext from '../../hooks/useCollapsibleHeaderContext';\n\ntype Props = {\n children: ReactNode;\n containerStyle?: StyleProp<ViewStyle>;\n};\n\nlet key = 0;\n\nexport default function CollapsibleHeaderContainer({ children }: Props) {\n const contentKey = useMemo(() => `collapsible-header-${key++}`, []);\n const { mount, unmount, update } = useCollapsibleHeaderContext();\n\n useEffect(() => {\n mount(contentKey, children);\n\n return () => {\n unmount(contentKey);\n };\n }, [contentKey]);\n\n useEffect(() => {\n update(contentKey, children);\n }, [children]);\n\n return null;\n}\n"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/* eslint-disable no-shadow */
|
|
2
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { CollapsibleHeaderContext } from '../../hooks/useCollapsibleHeaderContext';
|
|
4
|
+
export default function CollapsibleHeaderProvider({
|
|
5
|
+
children
|
|
6
|
+
}) {
|
|
7
|
+
const [headers, setHeaders] = useState([]);
|
|
8
|
+
const mounted = useRef(false);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
mounted.current = true;
|
|
11
|
+
return () => {
|
|
12
|
+
mounted.current = false;
|
|
13
|
+
};
|
|
14
|
+
}, []);
|
|
15
|
+
const mount = useCallback((key, children) => {
|
|
16
|
+
setHeaders(prev => [...prev, {
|
|
17
|
+
key,
|
|
18
|
+
children
|
|
19
|
+
}]);
|
|
20
|
+
}, []);
|
|
21
|
+
const unmount = useCallback(key => {
|
|
22
|
+
setHeaders(prev => prev.filter(h => h.key !== key));
|
|
23
|
+
}, []);
|
|
24
|
+
const update = useCallback((key, children) => {
|
|
25
|
+
if (!mounted.current) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
setHeaders(prev => prev.map(item => {
|
|
30
|
+
if (item.key === key) {
|
|
31
|
+
return { ...item,
|
|
32
|
+
children
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return item;
|
|
37
|
+
}));
|
|
38
|
+
}, []);
|
|
39
|
+
const context = useMemo(() => ({
|
|
40
|
+
headers,
|
|
41
|
+
mount,
|
|
42
|
+
unmount,
|
|
43
|
+
update
|
|
44
|
+
}), [headers, mount, unmount, update]);
|
|
45
|
+
return /*#__PURE__*/React.createElement(CollapsibleHeaderContext.Provider, {
|
|
46
|
+
value: context
|
|
47
|
+
}, children);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=CollapsibleHeaderProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["CollapsibleHeaderProvider.tsx"],"names":["React","useCallback","useEffect","useMemo","useRef","useState","CollapsibleHeaderContext","CollapsibleHeaderProvider","children","headers","setHeaders","mounted","current","mount","key","prev","unmount","filter","h","update","map","item","context"],"mappings":"AAAA;AACA,OAAOA,KAAP,IAEEC,WAFF,EAGEC,SAHF,EAIEC,OAJF,EAKEC,MALF,EAMEC,QANF,QAOO,OAPP;AAQA,SACEC,wBADF,QAGO,yCAHP;AAKA,eAAe,SAASC,yBAAT,CAAmC;AAChDC,EAAAA;AADgD,CAAnC,EAIZ;AACD,QAAM,CAACC,OAAD,EAAUC,UAAV,IAAwBL,QAAQ,CAAe,EAAf,CAAtC;AACA,QAAMM,OAAO,GAAGP,MAAM,CAAC,KAAD,CAAtB;AAEAF,EAAAA,SAAS,CAAC,MAAM;AACdS,IAAAA,OAAO,CAACC,OAAR,GAAkB,IAAlB;AACA,WAAO,MAAM;AACXD,MAAAA,OAAO,CAACC,OAAR,GAAkB,KAAlB;AACD,KAFD;AAGD,GALQ,EAKN,EALM,CAAT;AAOA,QAAMC,KAAK,GAAGZ,WAAW,CAAC,CAACa,GAAD,EAAcN,QAAd,KAAsC;AAC9DE,IAAAA,UAAU,CAAEK,IAAD,IAAU,CAAC,GAAGA,IAAJ,EAAU;AAAED,MAAAA,GAAF;AAAON,MAAAA;AAAP,KAAV,CAAX,CAAV;AACD,GAFwB,EAEtB,EAFsB,CAAzB;AAIA,QAAMQ,OAAO,GAAGf,WAAW,CAAEa,GAAD,IAAiB;AAC3CJ,IAAAA,UAAU,CAAEK,IAAD,IAAUA,IAAI,CAACE,MAAL,CAAaC,CAAD,IAAOA,CAAC,CAACJ,GAAF,KAAUA,GAA7B,CAAX,CAAV;AACD,GAF0B,EAExB,EAFwB,CAA3B;AAIA,QAAMK,MAAM,GAAGlB,WAAW,CAAC,CAACa,GAAD,EAAcN,QAAd,KAAsC;AAC/D,QAAI,CAACG,OAAO,CAACC,OAAb,EAAsB;AACpB;AACD;;AACDF,IAAAA,UAAU,CAAEK,IAAD,IACTA,IAAI,CAACK,GAAL,CAAUC,IAAD,IAAU;AACjB,UAAIA,IAAI,CAACP,GAAL,KAAaA,GAAjB,EAAsB;AACpB,eAAO,EACL,GAAGO,IADE;AAELb,UAAAA;AAFK,SAAP;AAID;;AACD,aAAOa,IAAP;AACD,KARD,CADQ,CAAV;AAWD,GAfyB,EAevB,EAfuB,CAA1B;AAiBA,QAAMC,OAAO,GAAGnB,OAAO,CACrB,OAAO;AACLM,IAAAA,OADK;AAELI,IAAAA,KAFK;AAGLG,IAAAA,OAHK;AAILG,IAAAA;AAJK,GAAP,CADqB,EAOrB,CAACV,OAAD,EAAUI,KAAV,EAAiBG,OAAjB,EAA0BG,MAA1B,CAPqB,CAAvB;AAUA,sBACE,oBAAC,wBAAD,CAA0B,QAA1B;AAAmC,IAAA,KAAK,EAAEG;AAA1C,KACGd,QADH,CADF;AAKD","sourcesContent":["/* eslint-disable no-shadow */\nimport React, {\n ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n CollapsibleHeaderContext,\n HeaderItem,\n} from '../../hooks/useCollapsibleHeaderContext';\n\nexport default function CollapsibleHeaderProvider({\n children,\n}: {\n children: ReactNode;\n}) {\n const [headers, setHeaders] = useState<HeaderItem[]>([]);\n const mounted = useRef(false);\n\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n\n const mount = useCallback((key: string, children: ReactNode) => {\n setHeaders((prev) => [...prev, { key, children }]);\n }, []);\n\n const unmount = useCallback((key: string) => {\n setHeaders((prev) => prev.filter((h) => h.key !== key));\n }, []);\n\n const update = useCallback((key: string, children: ReactNode) => {\n if (!mounted.current) {\n return;\n }\n setHeaders((prev) =>\n prev.map((item) => {\n if (item.key === key) {\n return {\n ...item,\n children,\n };\n }\n return item;\n })\n );\n }, []);\n\n const context = useMemo(\n () => ({\n headers,\n mount,\n unmount,\n update,\n }),\n [headers, mount, unmount, update]\n );\n\n return (\n <CollapsibleHeaderContext.Provider value={context}>\n {children}\n </CollapsibleHeaderContext.Provider>\n );\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
export const CollapsibleHeaderContext =
|
|
3
|
+
/*#__PURE__*/
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
createContext({});
|
|
6
|
+
export default function useCollapsibleHeaderContext() {
|
|
7
|
+
const ctx = useContext(CollapsibleHeaderContext);
|
|
8
|
+
|
|
9
|
+
if (!ctx) {
|
|
10
|
+
throw new Error('Component should be wrapped CollapsibleHeaderProvider');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return ctx;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=useCollapsibleHeaderContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["useCollapsibleHeaderContext.ts"],"names":["createContext","useContext","CollapsibleHeaderContext","useCollapsibleHeaderContext","ctx","Error"],"mappings":"AAAA,SAASA,aAAT,EAAmCC,UAAnC,QAAqD,OAArD;AAWA,OAAO,MAAMC,wBAAwB;AAAA;AACnC;AACAF,aAAa,CAA+B,EAA/B,CAFR;AAIP,eAAe,SAASG,2BAAT,GAAuC;AACpD,QAAMC,GAAG,GAAGH,UAAU,CAACC,wBAAD,CAAtB;;AACA,MAAI,CAACE,GAAL,EAAU;AACR,UAAM,IAAIC,KAAJ,CAAU,uDAAV,CAAN;AACD;;AACD,SAAOD,GAAP;AACD","sourcesContent":["import { createContext, ReactNode, useContext } from 'react';\n\nexport type HeaderItem = { key: string; children: ReactNode };\n\ntype CollapsibleContextHeaderType = {\n headers: HeaderItem[];\n mount: (key: string, header: ReactNode) => void;\n update: (key: string, header: ReactNode) => void;\n unmount: (key: string) => void;\n};\n\nexport const CollapsibleHeaderContext =\n // @ts-ignore\n createContext<CollapsibleContextHeaderType>({});\n\nexport default function useCollapsibleHeaderContext() {\n const ctx = useContext(CollapsibleHeaderContext);\n if (!ctx) {\n throw new Error('Component should be wrapped CollapsibleHeaderProvider');\n }\n return ctx;\n}\n"]}
|
|
@@ -7,6 +7,7 @@ import { InternalCollapsibleContext } from './hooks/useInternalCollapsibleContex
|
|
|
7
7
|
import { useAnimatedReaction, useDerivedValue, useSharedValue, withTiming } from 'react-native-reanimated';
|
|
8
8
|
import { debounce } from './utils/debounce';
|
|
9
9
|
import PullToRefreshProvider from './components/pullToRefresh/PullToRefreshProvider';
|
|
10
|
+
import CollapsibleHeaderProvider from './components/header/CollapsibleHeaderProvider';
|
|
10
11
|
export default function withCollapsibleContext(Component) {
|
|
11
12
|
return props => {
|
|
12
13
|
const collapsibleHandlers = useRef();
|
|
@@ -20,13 +21,9 @@ export default function withCollapsibleContext(Component) {
|
|
|
20
21
|
const stickyHeaderHeight = useSharedValue(0);
|
|
21
22
|
const containerHeight = useSharedValue(0);
|
|
22
23
|
const firstStickyViewY = useSharedValue(1000000);
|
|
23
|
-
const headerContainersHeight = useRef({});
|
|
24
24
|
const containerRef = useRef(null);
|
|
25
25
|
const scrollViewRef = useRef(null);
|
|
26
26
|
const setCollapsibleHandlers = useCallback(handlers => {
|
|
27
|
-
console.log({
|
|
28
|
-
handlers
|
|
29
|
-
});
|
|
30
27
|
collapsibleHandlers.current = handlers;
|
|
31
28
|
}, []);
|
|
32
29
|
const headerCollapsed = useDerivedValue(() => {
|
|
@@ -105,18 +102,11 @@ export default function withCollapsibleContext(Component) {
|
|
|
105
102
|
});
|
|
106
103
|
}, 200);
|
|
107
104
|
}, []);
|
|
108
|
-
const handleHeaderContainerLayout = useCallback(
|
|
109
|
-
|
|
110
|
-
delete headerContainersHeight.current[viewKey];
|
|
111
|
-
} else {
|
|
112
|
-
headerContainersHeight.current[viewKey] = height;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const totalHeight = Object.keys(headerContainersHeight.current).reduce((acc, key) => headerContainersHeight.current[key] + acc, 0);
|
|
116
|
-
headerHeight.value = withTiming(totalHeight, {
|
|
105
|
+
const handleHeaderContainerLayout = useCallback(height => {
|
|
106
|
+
headerHeight.value = withTiming(height, {
|
|
117
107
|
duration: fixedHeaderHeight.value === 0 ? 0 : 10
|
|
118
108
|
});
|
|
119
|
-
fixedHeaderHeight.value =
|
|
109
|
+
fixedHeaderHeight.value = height; // Try refresh sticky positions
|
|
120
110
|
|
|
121
111
|
debounceRefreshStickyPositions();
|
|
122
112
|
}, []);
|
|
@@ -167,7 +157,7 @@ export default function withCollapsibleContext(Component) {
|
|
|
167
157
|
value: context
|
|
168
158
|
}, /*#__PURE__*/React.createElement(InternalCollapsibleContext.Provider, {
|
|
169
159
|
value: internalContext
|
|
170
|
-
}, /*#__PURE__*/React.createElement(PullToRefreshProvider, null, /*#__PURE__*/React.createElement(Component, props))));
|
|
160
|
+
}, /*#__PURE__*/React.createElement(CollapsibleHeaderProvider, null, /*#__PURE__*/React.createElement(PullToRefreshProvider, null, /*#__PURE__*/React.createElement(Component, props)))));
|
|
171
161
|
};
|
|
172
162
|
}
|
|
173
163
|
//# sourceMappingURL=withCollapsibleContext.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["withCollapsibleContext.tsx"],"names":["React","useCallback","useMemo","useRef","CollapsibleContext","InternalCollapsibleContext","useAnimatedReaction","useDerivedValue","useSharedValue","withTiming","debounce","PullToRefreshProvider","withCollapsibleContext","Component","props","collapsibleHandlers","headerHeight","scrollY","stickyViewRefs","stickyViewTops","stickyViewPositionsRef","stickyViewPositions","fixedHeaderHeight","stickyHeaderHeight","containerHeight","firstStickyViewY","headerContainersHeight","containerRef","scrollViewRef","setCollapsibleHandlers","handlers","console","log","current","headerCollapsed","maxY","value","contentMinHeight","totalHeight","Object","keys","reduce","acc","item","top","result","previous","viewPositions","sortedKeys","sort","a","b","totalTop","values","i","length","height","stickyHeader","key","data","isInsideHeader","handleStickyViewLayout","viewKey","viewRef","measureLayout","left","width","debounceRefreshStickyPositions","forEach","handleHeaderContainerLayout","duration","handleContainerHeight","context","collapse","animated","expand","scrollTo","offset","animate","scrollToIndex","params","internalContext"],"mappings":"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","sourcesContent":["/* eslint-disable no-shadow */\n/* eslint-disable react-hooks/exhaustive-deps */\nimport React, { FC, useCallback, useMemo, useRef } from 'react';\nimport type { CollapsibleHandles, LayoutParams } from './types';\nimport { CollapsibleContext } from './hooks/useCollapsibleContext';\nimport { InternalCollapsibleContext } from './hooks/useInternalCollapsibleContext';\nimport {\n useAnimatedReaction,\n useDerivedValue,\n useSharedValue,\n withTiming,\n} from 'react-native-reanimated';\nimport type { View } from 'react-native';\nimport { debounce } from './utils/debounce';\nimport PullToRefreshProvider from './components/pullToRefresh/PullToRefreshProvider';\n\nexport default function withCollapsibleContext<T>(Component: FC<T>) {\n return (props: T) => {\n const collapsibleHandlers = useRef<CollapsibleHandles>();\n const headerHeight = useSharedValue(0);\n const scrollY = useSharedValue(0);\n const stickyViewRefs = useRef<Record<string, React.RefObject<View>>>({});\n const stickyViewTops = useSharedValue<Record<string, number>>({});\n const stickyViewPositionsRef = useRef<Record<string, LayoutParams>>({});\n const stickyViewPositions = useSharedValue<Record<string, LayoutParams>>(\n {}\n );\n const fixedHeaderHeight = useSharedValue(0);\n const stickyHeaderHeight = useSharedValue(0);\n const containerHeight = useSharedValue(0);\n const firstStickyViewY = useSharedValue(1000000);\n const headerContainersHeight = useRef<Record<string, number>>({});\n const containerRef = useRef<View>(null);\n const scrollViewRef = useRef<View>(null);\n\n const setCollapsibleHandlers = useCallback((handlers) => {\n console.log({ handlers });\n\n collapsibleHandlers.current = handlers;\n }, []);\n\n const headerCollapsed = useDerivedValue(() => {\n const maxY = fixedHeaderHeight.value - firstStickyViewY.value;\n return scrollY.value >= maxY;\n }, []);\n\n const contentMinHeight = useDerivedValue(() => {\n return (\n containerHeight.value +\n fixedHeaderHeight.value -\n stickyHeaderHeight.value\n );\n }, []);\n\n useAnimatedReaction(\n () => {\n const totalHeight = Object.keys(stickyViewPositions.value).reduce(\n (acc, item) => {\n return acc + stickyViewPositions.value[item].top;\n },\n 0\n );\n return totalHeight - fixedHeaderHeight.value;\n },\n (result, previous) => {\n if (result !== previous) {\n const viewPositions = stickyViewPositions.value;\n const headerHeight = fixedHeaderHeight.value;\n const sortedKeys = Object.keys(viewPositions).sort(\n (a, b) => viewPositions[a].top - viewPositions[b].top\n );\n let totalTop = 0;\n const values: any = {};\n for (let i = 0; i < sortedKeys.length; i++) {\n values[sortedKeys[i]] = totalTop;\n // Try minus 1 make it filled when scrolling up.\n // Otherwise, we can see a small space between the persits views\n totalTop += viewPositions[sortedKeys[i]].height - 1;\n }\n stickyViewTops.value = values;\n firstStickyViewY.value = viewPositions[sortedKeys[0]]?.top || 0;\n const stickyHeader = sortedKeys.reduce((acc, key) => {\n const data = viewPositions[key];\n const isInsideHeader = data.top < headerHeight;\n if (isInsideHeader) {\n return acc + data.height;\n }\n return acc;\n }, 0);\n stickyHeaderHeight.value = stickyHeader;\n }\n }\n );\n\n const handleStickyViewLayout = useCallback(\n (viewKey: string, viewRef?: React.RefObject<View>) => {\n if (viewRef && viewRef.current && containerRef.current) {\n stickyViewRefs.current[viewKey] = viewRef;\n viewRef.current.measureLayout(\n // @ts-ignore\n containerRef.current,\n (left, top, width, height) => {\n stickyViewPositionsRef.current = {\n ...stickyViewPositionsRef.current,\n [viewKey]: { left, top, width, height },\n };\n stickyViewPositions.value = stickyViewPositionsRef.current;\n },\n () => {}\n );\n } else {\n delete stickyViewRefs.current[viewKey];\n delete stickyViewPositionsRef.current[viewKey];\n stickyViewPositions.value = stickyViewPositionsRef.current;\n }\n },\n []\n );\n\n const debounceRefreshStickyPositions = useMemo(() => {\n return debounce(() => {\n Object.keys(stickyViewRefs.current).forEach((key) => {\n const viewRef = stickyViewRefs.current[key];\n if (viewRef) {\n handleStickyViewLayout(key, viewRef);\n }\n });\n }, 200);\n }, []);\n\n const handleHeaderContainerLayout = useCallback(\n (viewKey: string, height?: number) => {\n if (!height) {\n delete headerContainersHeight.current[viewKey];\n } else {\n headerContainersHeight.current[viewKey] = height;\n }\n const totalHeight = Object.keys(headerContainersHeight.current).reduce(\n (acc, key) => headerContainersHeight.current[key] + acc,\n 0\n );\n headerHeight.value = withTiming(totalHeight, {\n duration: fixedHeaderHeight.value === 0 ? 0 : 10,\n });\n fixedHeaderHeight.value = totalHeight;\n // Try refresh sticky positions\n debounceRefreshStickyPositions();\n },\n []\n );\n\n const handleContainerHeight = useCallback((height: number) => {\n containerHeight.value = height;\n }, []);\n\n const context = useMemo(() => {\n return {\n collapse: (animated?: boolean) =>\n collapsibleHandlers.current?.collapse(animated),\n expand: () => collapsibleHandlers.current?.expand(),\n scrollTo: (offset: number, animate?: boolean) =>\n collapsibleHandlers.current?.scrollTo(offset, animate),\n scrollToIndex: (params: any) =>\n collapsibleHandlers.current?.scrollToIndex(params),\n headerHeight,\n scrollY,\n headerCollapsed,\n };\n }, [scrollY, headerHeight, headerCollapsed]);\n\n const internalContext = useMemo(\n () => ({\n scrollViewRef,\n containerRef,\n handleStickyViewLayout,\n handleHeaderContainerLayout,\n setCollapsibleHandlers,\n handleContainerHeight,\n firstStickyViewY,\n stickyViewTops,\n stickyViewPositions,\n fixedHeaderHeight,\n contentMinHeight,\n }),\n [\n setCollapsibleHandlers,\n handleStickyViewLayout,\n handleHeaderContainerLayout,\n handleContainerHeight,\n firstStickyViewY,\n stickyViewTops,\n stickyViewPositions,\n fixedHeaderHeight,\n contentMinHeight,\n ]\n );\n\n return (\n <CollapsibleContext.Provider value={context}>\n <InternalCollapsibleContext.Provider value={internalContext}>\n <PullToRefreshProvider>\n <Component {...props} />\n </PullToRefreshProvider>\n </InternalCollapsibleContext.Provider>\n </CollapsibleContext.Provider>\n );\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["withCollapsibleContext.tsx"],"names":["React","useCallback","useMemo","useRef","CollapsibleContext","InternalCollapsibleContext","useAnimatedReaction","useDerivedValue","useSharedValue","withTiming","debounce","PullToRefreshProvider","CollapsibleHeaderProvider","withCollapsibleContext","Component","props","collapsibleHandlers","headerHeight","scrollY","stickyViewRefs","stickyViewTops","stickyViewPositionsRef","stickyViewPositions","fixedHeaderHeight","stickyHeaderHeight","containerHeight","firstStickyViewY","containerRef","scrollViewRef","setCollapsibleHandlers","handlers","current","headerCollapsed","maxY","value","contentMinHeight","totalHeight","Object","keys","reduce","acc","item","top","result","previous","viewPositions","sortedKeys","sort","a","b","totalTop","values","i","length","height","stickyHeader","key","data","isInsideHeader","handleStickyViewLayout","viewKey","viewRef","measureLayout","left","width","debounceRefreshStickyPositions","forEach","handleHeaderContainerLayout","duration","handleContainerHeight","context","collapse","animated","expand","scrollTo","offset","animate","scrollToIndex","params","internalContext"],"mappings":"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","sourcesContent":["/* eslint-disable no-shadow */\n/* eslint-disable react-hooks/exhaustive-deps */\nimport React, { FC, useCallback, useMemo, useRef } from 'react';\nimport type { CollapsibleHandles, LayoutParams } from './types';\nimport { CollapsibleContext } from './hooks/useCollapsibleContext';\nimport { InternalCollapsibleContext } from './hooks/useInternalCollapsibleContext';\nimport {\n useAnimatedReaction,\n useDerivedValue,\n useSharedValue,\n withTiming,\n} from 'react-native-reanimated';\nimport type { View } from 'react-native';\nimport { debounce } from './utils/debounce';\nimport PullToRefreshProvider from './components/pullToRefresh/PullToRefreshProvider';\nimport CollapsibleHeaderProvider from './components/header/CollapsibleHeaderProvider';\n\nexport default function withCollapsibleContext<T>(Component: FC<T>) {\n return (props: T) => {\n const collapsibleHandlers = useRef<CollapsibleHandles>();\n const headerHeight = useSharedValue(0);\n const scrollY = useSharedValue(0);\n const stickyViewRefs = useRef<Record<string, React.RefObject<View>>>({});\n const stickyViewTops = useSharedValue<Record<string, number>>({});\n const stickyViewPositionsRef = useRef<Record<string, LayoutParams>>({});\n const stickyViewPositions = useSharedValue<Record<string, LayoutParams>>(\n {}\n );\n const fixedHeaderHeight = useSharedValue(0);\n const stickyHeaderHeight = useSharedValue(0);\n const containerHeight = useSharedValue(0);\n const firstStickyViewY = useSharedValue(1000000);\n const containerRef = useRef<View>(null);\n const scrollViewRef = useRef<View>(null);\n\n const setCollapsibleHandlers = useCallback((handlers) => {\n collapsibleHandlers.current = handlers;\n }, []);\n\n const headerCollapsed = useDerivedValue(() => {\n const maxY = fixedHeaderHeight.value - firstStickyViewY.value;\n return scrollY.value >= maxY;\n }, []);\n\n const contentMinHeight = useDerivedValue(() => {\n return (\n containerHeight.value +\n fixedHeaderHeight.value -\n stickyHeaderHeight.value\n );\n }, []);\n\n useAnimatedReaction(\n () => {\n const totalHeight = Object.keys(stickyViewPositions.value).reduce(\n (acc, item) => {\n return acc + stickyViewPositions.value[item].top;\n },\n 0\n );\n return totalHeight - fixedHeaderHeight.value;\n },\n (result, previous) => {\n if (result !== previous) {\n const viewPositions = stickyViewPositions.value;\n const headerHeight = fixedHeaderHeight.value;\n const sortedKeys = Object.keys(viewPositions).sort(\n (a, b) => viewPositions[a].top - viewPositions[b].top\n );\n let totalTop = 0;\n const values: any = {};\n for (let i = 0; i < sortedKeys.length; i++) {\n values[sortedKeys[i]] = totalTop;\n // Try minus 1 make it filled when scrolling up.\n // Otherwise, we can see a small space between the persits views\n totalTop += viewPositions[sortedKeys[i]].height - 1;\n }\n stickyViewTops.value = values;\n firstStickyViewY.value = viewPositions[sortedKeys[0]]?.top || 0;\n const stickyHeader = sortedKeys.reduce((acc, key) => {\n const data = viewPositions[key];\n const isInsideHeader = data.top < headerHeight;\n if (isInsideHeader) {\n return acc + data.height;\n }\n return acc;\n }, 0);\n stickyHeaderHeight.value = stickyHeader;\n }\n }\n );\n\n const handleStickyViewLayout = useCallback(\n (viewKey: string, viewRef?: React.RefObject<View>) => {\n if (viewRef && viewRef.current && containerRef.current) {\n stickyViewRefs.current[viewKey] = viewRef;\n viewRef.current.measureLayout(\n // @ts-ignore\n containerRef.current,\n (left, top, width, height) => {\n stickyViewPositionsRef.current = {\n ...stickyViewPositionsRef.current,\n [viewKey]: { left, top, width, height },\n };\n stickyViewPositions.value = stickyViewPositionsRef.current;\n },\n () => {}\n );\n } else {\n delete stickyViewRefs.current[viewKey];\n delete stickyViewPositionsRef.current[viewKey];\n stickyViewPositions.value = stickyViewPositionsRef.current;\n }\n },\n []\n );\n\n const debounceRefreshStickyPositions = useMemo(() => {\n return debounce(() => {\n Object.keys(stickyViewRefs.current).forEach((key) => {\n const viewRef = stickyViewRefs.current[key];\n if (viewRef) {\n handleStickyViewLayout(key, viewRef);\n }\n });\n }, 200);\n }, []);\n\n const handleHeaderContainerLayout = useCallback((height: number) => {\n headerHeight.value = withTiming(height, {\n duration: fixedHeaderHeight.value === 0 ? 0 : 10,\n });\n fixedHeaderHeight.value = height;\n // Try refresh sticky positions\n debounceRefreshStickyPositions();\n }, []);\n\n const handleContainerHeight = useCallback((height: number) => {\n containerHeight.value = height;\n }, []);\n\n const context = useMemo(() => {\n return {\n collapse: (animated?: boolean) =>\n collapsibleHandlers.current?.collapse(animated),\n expand: () => collapsibleHandlers.current?.expand(),\n scrollTo: (offset: number, animate?: boolean) =>\n collapsibleHandlers.current?.scrollTo(offset, animate),\n scrollToIndex: (params: any) =>\n collapsibleHandlers.current?.scrollToIndex(params),\n headerHeight,\n scrollY,\n headerCollapsed,\n };\n }, [scrollY, headerHeight, headerCollapsed]);\n\n const internalContext = useMemo(\n () => ({\n scrollViewRef,\n containerRef,\n handleStickyViewLayout,\n handleHeaderContainerLayout,\n setCollapsibleHandlers,\n handleContainerHeight,\n firstStickyViewY,\n stickyViewTops,\n stickyViewPositions,\n fixedHeaderHeight,\n contentMinHeight,\n }),\n [\n setCollapsibleHandlers,\n handleStickyViewLayout,\n handleHeaderContainerLayout,\n handleContainerHeight,\n firstStickyViewY,\n stickyViewTops,\n stickyViewPositions,\n fixedHeaderHeight,\n contentMinHeight,\n ]\n );\n\n return (\n <CollapsibleContext.Provider value={context}>\n <InternalCollapsibleContext.Provider value={internalContext}>\n <CollapsibleHeaderProvider>\n <PullToRefreshProvider>\n {/** @ts-ignore */}\n <Component {...props} />\n </PullToRefreshProvider>\n </CollapsibleHeaderProvider>\n </InternalCollapsibleContext.Provider>\n </CollapsibleContext.Provider>\n );\n };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function CollapsibleHeaderConsumer(): JSX.Element;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { StyleProp, ViewStyle } from 'react-native';
|
|
2
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
3
3
|
declare type Props = {
|
|
4
4
|
children: ReactNode;
|
|
5
5
|
containerStyle?: StyleProp<ViewStyle>;
|
|
6
6
|
};
|
|
7
|
-
export default function CollapsibleHeaderContainer({ children
|
|
7
|
+
export default function CollapsibleHeaderContainer({ children }: Props): null;
|
|
8
8
|
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export declare type HeaderItem = {
|
|
3
|
+
key: string;
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
};
|
|
6
|
+
declare type CollapsibleContextHeaderType = {
|
|
7
|
+
headers: HeaderItem[];
|
|
8
|
+
mount: (key: string, header: ReactNode) => void;
|
|
9
|
+
update: (key: string, header: ReactNode) => void;
|
|
10
|
+
unmount: (key: string) => void;
|
|
11
|
+
};
|
|
12
|
+
export declare const CollapsibleHeaderContext: import("react").Context<CollapsibleContextHeaderType>;
|
|
13
|
+
export default function useCollapsibleHeaderContext(): CollapsibleContextHeaderType;
|
|
14
|
+
export {};
|
|
@@ -34,7 +34,7 @@ export declare type CollapsibleContextInternalType = {
|
|
|
34
34
|
fixedHeaderHeight: Animated.SharedValue<number>;
|
|
35
35
|
handleContainerHeight: (height: number) => void;
|
|
36
36
|
handleStickyViewLayout: (viewKey: string, viewRef?: React.RefObject<View>) => void;
|
|
37
|
-
handleHeaderContainerLayout: (
|
|
37
|
+
handleHeaderContainerLayout: (height: number) => void;
|
|
38
38
|
setCollapsibleHandlers: (handlers: CollapsibleHandles) => void;
|
|
39
39
|
};
|
|
40
40
|
export declare type CollapsibleProps = {
|
package/package.json
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import useKeyboardShowEvent from '../hooks/useKeyboardShowEvent';
|
|
12
12
|
import useInternalCollapsibleContext from '../hooks/useInternalCollapsibleContext';
|
|
13
13
|
import useCollapsibleContext from '../hooks/useCollapsibleContext';
|
|
14
|
+
import CollapsibleHeaderConsumer from './header/CollapsibleHeaderConsumer';
|
|
14
15
|
|
|
15
16
|
type Props = Omit<ViewProps, 'ref' | 'onLayout'> & {
|
|
16
17
|
children: Element;
|
|
@@ -72,8 +73,10 @@ export default function CollapsibleContainer({
|
|
|
72
73
|
ref={containerRef}
|
|
73
74
|
style={[styles.container, props.style]}
|
|
74
75
|
onLayout={handleContainerLayout}
|
|
76
|
+
collapsable={false}
|
|
75
77
|
>
|
|
76
78
|
{children}
|
|
79
|
+
<CollapsibleHeaderConsumer />
|
|
77
80
|
</View>
|
|
78
81
|
</KeyboardAvoidingView>
|
|
79
82
|
);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import useInternalCollapsibleContext from '../../hooks/useInternalCollapsibleContext';
|
|
3
|
+
import useCollapsibleHeaderContext from '../../hooks/useCollapsibleHeaderContext';
|
|
4
|
+
import Animated, {
|
|
5
|
+
interpolate,
|
|
6
|
+
useAnimatedStyle,
|
|
7
|
+
useDerivedValue,
|
|
8
|
+
} from 'react-native-reanimated';
|
|
9
|
+
import useCollapsibleContext from '../../hooks/useCollapsibleContext';
|
|
10
|
+
import { LayoutChangeEvent, StyleSheet } from 'react-native';
|
|
11
|
+
|
|
12
|
+
export default function CollapsibleHeaderConsumer() {
|
|
13
|
+
const { headers } = useCollapsibleHeaderContext();
|
|
14
|
+
const { handleHeaderContainerLayout } = useInternalCollapsibleContext();
|
|
15
|
+
const { scrollY, headerHeight } = useCollapsibleContext();
|
|
16
|
+
|
|
17
|
+
const headerTranslate = useDerivedValue(
|
|
18
|
+
() =>
|
|
19
|
+
interpolate(
|
|
20
|
+
scrollY.value,
|
|
21
|
+
// FIXME: can improve by geting maxY value of header and sticky views
|
|
22
|
+
[-250, 0, 100000],
|
|
23
|
+
[250, 0, -100000],
|
|
24
|
+
Animated.Extrapolate.CLAMP
|
|
25
|
+
),
|
|
26
|
+
[]
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const headerStyle = useAnimatedStyle(() => {
|
|
30
|
+
return {
|
|
31
|
+
transform: [{ translateY: headerTranslate.value }],
|
|
32
|
+
};
|
|
33
|
+
}, [headerHeight, headerTranslate]);
|
|
34
|
+
|
|
35
|
+
const handleHeaderLayout = useCallback(
|
|
36
|
+
({
|
|
37
|
+
nativeEvent: {
|
|
38
|
+
layout: { height },
|
|
39
|
+
},
|
|
40
|
+
}: LayoutChangeEvent) => {
|
|
41
|
+
handleHeaderContainerLayout(height);
|
|
42
|
+
},
|
|
43
|
+
[handleHeaderContainerLayout]
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<Animated.View
|
|
48
|
+
onLayout={handleHeaderLayout}
|
|
49
|
+
style={[styles.container, headerStyle]}
|
|
50
|
+
pointerEvents="box-none"
|
|
51
|
+
>
|
|
52
|
+
{headers.map((item) => item.children)}
|
|
53
|
+
</Animated.View>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const styles = StyleSheet.create({
|
|
58
|
+
container: {
|
|
59
|
+
backgroundColor: 'white',
|
|
60
|
+
},
|
|
61
|
+
});
|
|
@@ -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
|
+
}
|