@space-uy/pulsar-ui 0.11.1 → 0.11.2
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.
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { StyleSheet, View } from 'react-native';
|
|
4
|
+
import Animated, { interpolate, useAnimatedStyle } from 'react-native-reanimated';
|
|
4
5
|
import Text from "./Text.js";
|
|
5
6
|
import IconButton from "./IconButton.js";
|
|
6
7
|
import useTheme from "../hooks/useTheme.js";
|
|
7
8
|
import meassures from "../theme/meassures.js";
|
|
8
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
9
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
10
|
+
const DEFAULT_COLLAPSE_THRESHOLD = 80;
|
|
9
11
|
const HEADER_BASE_HEIGHT = 52;
|
|
10
12
|
export default function Header({
|
|
11
13
|
title,
|
|
@@ -14,7 +16,9 @@ export default function Header({
|
|
|
14
16
|
rightButton,
|
|
15
17
|
style,
|
|
16
18
|
useInsets = true,
|
|
17
|
-
children
|
|
19
|
+
children,
|
|
20
|
+
scrollY,
|
|
21
|
+
collapseThreshold = DEFAULT_COLLAPSE_THRESHOLD
|
|
18
22
|
}) {
|
|
19
23
|
const {
|
|
20
24
|
colors,
|
|
@@ -22,6 +26,35 @@ export default function Header({
|
|
|
22
26
|
} = useTheme();
|
|
23
27
|
const topInset = useInsets ? theme.insets?.top || 0 : 0;
|
|
24
28
|
const isSecondary = variant === 'secondary';
|
|
29
|
+
const isCollapsible = isSecondary && scrollY != null;
|
|
30
|
+
const animatedHeaderStyle = useAnimatedStyle(() => {
|
|
31
|
+
if (!isCollapsible || scrollY == null) return {};
|
|
32
|
+
const progress = interpolate(scrollY.value, [0, collapseThreshold], [0, 1], 'clamp');
|
|
33
|
+
return {
|
|
34
|
+
paddingBottom: interpolate(progress, [0, 1], [12, 0])
|
|
35
|
+
};
|
|
36
|
+
}, [isCollapsible, collapseThreshold]);
|
|
37
|
+
const animatedTitleRowStyle = useAnimatedStyle(() => {
|
|
38
|
+
if (!isCollapsible || scrollY == null) return {};
|
|
39
|
+
const progress = interpolate(scrollY.value, [0, collapseThreshold], [0, 1], 'clamp');
|
|
40
|
+
// Estimate: h1 fontSize 24 + line height ~16 + paddingTop 4 = ~44px
|
|
41
|
+
const titleRowHeight = 44;
|
|
42
|
+
return {
|
|
43
|
+
opacity: interpolate(progress, [0, 1], [1, 0]),
|
|
44
|
+
height: interpolate(progress, [0, 1], [titleRowHeight, 0]),
|
|
45
|
+
overflow: 'hidden',
|
|
46
|
+
transform: [{
|
|
47
|
+
translateY: interpolate(progress, [0, 1], [0, -16])
|
|
48
|
+
}]
|
|
49
|
+
};
|
|
50
|
+
}, [isCollapsible, collapseThreshold]);
|
|
51
|
+
const animatedSmallTitleStyle = useAnimatedStyle(() => {
|
|
52
|
+
if (!isCollapsible || scrollY == null) return {};
|
|
53
|
+
const progress = interpolate(scrollY.value, [0, collapseThreshold], [0, 1], 'clamp');
|
|
54
|
+
return {
|
|
55
|
+
opacity: interpolate(progress, [0, 1], [0, 1])
|
|
56
|
+
};
|
|
57
|
+
}, [isCollapsible, collapseThreshold]);
|
|
25
58
|
const renderButton = button => {
|
|
26
59
|
return /*#__PURE__*/_jsx(IconButton, {
|
|
27
60
|
iconName: button.iconName,
|
|
@@ -32,20 +65,29 @@ export default function Header({
|
|
|
32
65
|
rounded: button.rounded
|
|
33
66
|
});
|
|
34
67
|
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
borderBottomColor: colors.border,
|
|
39
|
-
paddingTop: topInset
|
|
40
|
-
}, isSecondary && styles.headerSecondary, !!children && styles.paddingBottom, style],
|
|
68
|
+
const showSmallTitleInBar = !isSecondary || isCollapsible;
|
|
69
|
+
const showBigTitleRow = isSecondary;
|
|
70
|
+
const headerContent = /*#__PURE__*/_jsxs(_Fragment, {
|
|
41
71
|
children: [/*#__PURE__*/_jsxs(View, {
|
|
42
|
-
style: [styles.headerContent, isSecondary && styles.headerContentSecondary],
|
|
72
|
+
style: [styles.headerContent, isSecondary && !isCollapsible && styles.headerContentSecondary, isCollapsible && styles.headerContentSecondary],
|
|
43
73
|
children: [/*#__PURE__*/_jsx(View, {
|
|
44
74
|
style: [styles.slot, styles.leftSlot],
|
|
45
75
|
children: leftButton && renderButton(leftButton)
|
|
46
|
-
}),
|
|
76
|
+
}), showSmallTitleInBar && /*#__PURE__*/_jsx(View, {
|
|
47
77
|
style: styles.titleContainer,
|
|
48
|
-
|
|
78
|
+
pointerEvents: "none",
|
|
79
|
+
children: isCollapsible ? /*#__PURE__*/_jsx(Animated.View, {
|
|
80
|
+
style: [styles.titleContainer, animatedSmallTitleStyle],
|
|
81
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
82
|
+
variant: "h3",
|
|
83
|
+
style: [styles.title, {
|
|
84
|
+
color: colors.foreground
|
|
85
|
+
}],
|
|
86
|
+
numberOfLines: 1,
|
|
87
|
+
ellipsizeMode: "tail",
|
|
88
|
+
children: title
|
|
89
|
+
})
|
|
90
|
+
}) : /*#__PURE__*/_jsx(Text, {
|
|
49
91
|
variant: "h3",
|
|
50
92
|
style: [styles.title, {
|
|
51
93
|
color: colors.foreground
|
|
@@ -58,10 +100,21 @@ export default function Header({
|
|
|
58
100
|
style: [styles.slot, styles.rightSlot],
|
|
59
101
|
children: rightButton && renderButton(rightButton)
|
|
60
102
|
})]
|
|
61
|
-
}),
|
|
103
|
+
}), showBigTitleRow && (isCollapsible ? /*#__PURE__*/_jsx(Animated.View, {
|
|
104
|
+
style: [styles.titleRow, animatedTitleRowStyle],
|
|
105
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
106
|
+
variant: "h1",
|
|
107
|
+
style: [styles.titleSecondary, {
|
|
108
|
+
color: colors.foreground
|
|
109
|
+
}],
|
|
110
|
+
numberOfLines: 1,
|
|
111
|
+
ellipsizeMode: "tail",
|
|
112
|
+
children: title
|
|
113
|
+
})
|
|
114
|
+
}) : /*#__PURE__*/_jsx(View, {
|
|
62
115
|
style: styles.titleRow,
|
|
63
116
|
children: /*#__PURE__*/_jsx(Text, {
|
|
64
|
-
variant: "
|
|
117
|
+
variant: "h1",
|
|
65
118
|
style: [styles.titleSecondary, {
|
|
66
119
|
color: colors.foreground
|
|
67
120
|
}],
|
|
@@ -69,7 +122,22 @@ export default function Header({
|
|
|
69
122
|
ellipsizeMode: "tail",
|
|
70
123
|
children: title
|
|
71
124
|
})
|
|
72
|
-
})
|
|
125
|
+
}))]
|
|
126
|
+
});
|
|
127
|
+
const staticHeaderStyle = [styles.header, {
|
|
128
|
+
backgroundColor: colors.background,
|
|
129
|
+
borderBottomColor: colors.border,
|
|
130
|
+
paddingTop: topInset
|
|
131
|
+
}, isSecondary && !isCollapsible && styles.headerSecondary, isCollapsible && styles.headerSecondary, !!children && styles.paddingBottom, style];
|
|
132
|
+
if (isCollapsible) {
|
|
133
|
+
return /*#__PURE__*/_jsxs(Animated.View, {
|
|
134
|
+
style: [staticHeaderStyle, animatedHeaderStyle],
|
|
135
|
+
children: [headerContent, children]
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
139
|
+
style: staticHeaderStyle,
|
|
140
|
+
children: [headerContent, children]
|
|
73
141
|
});
|
|
74
142
|
}
|
|
75
143
|
const styles = StyleSheet.create({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["StyleSheet","View","Text","IconButton","useTheme","meassures","jsx","_jsx","jsxs","_jsxs","HEADER_BASE_HEIGHT","Header","title","variant","leftButton","rightButton","style","useInsets","children","colors","theme","topInset","insets","top","isSecondary","
|
|
1
|
+
{"version":3,"names":["StyleSheet","View","Animated","interpolate","useAnimatedStyle","Text","IconButton","useTheme","meassures","jsx","_jsx","jsxs","_jsxs","Fragment","_Fragment","DEFAULT_COLLAPSE_THRESHOLD","HEADER_BASE_HEIGHT","Header","title","variant","leftButton","rightButton","style","useInsets","children","scrollY","collapseThreshold","colors","theme","topInset","insets","top","isSecondary","isCollapsible","animatedHeaderStyle","progress","value","paddingBottom","animatedTitleRowStyle","titleRowHeight","opacity","height","overflow","transform","translateY","animatedSmallTitleStyle","renderButton","button","iconName","size","onPress","disabled","rounded","showSmallTitleInBar","showBigTitleRow","headerContent","styles","headerContentSecondary","slot","leftSlot","titleContainer","pointerEvents","color","foreground","numberOfLines","ellipsizeMode","rightSlot","titleRow","titleSecondary","staticHeaderStyle","header","backgroundColor","background","borderBottomColor","border","paddingTop","headerSecondary","create","borderBottomWidth","paddingHorizontal","flexDirection","alignItems","justifyContent","width","medium","flex","textAlign","marginHorizontal"],"sourceRoot":"../../../src","sources":["components/Header.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type PropsWithChildren } from 'react';
|
|
2
2
|
import { type ViewStyle, type StyleProp } from 'react-native';
|
|
3
|
+
import { type SharedValue } from 'react-native-reanimated';
|
|
3
4
|
import { type IconName } from './Icon';
|
|
4
5
|
import type { ButtonVariant } from './ButtonContainer';
|
|
5
6
|
export type HeaderVariant = 'default' | 'secondary';
|
|
@@ -17,7 +18,11 @@ type Props = PropsWithChildren & {
|
|
|
17
18
|
rightButton?: HeaderButtonProps;
|
|
18
19
|
style?: StyleProp<ViewStyle>;
|
|
19
20
|
useInsets?: boolean;
|
|
21
|
+
/** When set with variant="secondary", header animates from large title to compact as user scrolls (iOS-style). Pass the scroll view's contentOffset.y (e.g. from useAnimatedScrollHandler). */
|
|
22
|
+
scrollY?: SharedValue<number>;
|
|
23
|
+
/** Scroll offset at which the header is fully collapsed. Ignored when scrollY is not provided. */
|
|
24
|
+
collapseThreshold?: number;
|
|
20
25
|
};
|
|
21
|
-
export default function Header({ title, variant, leftButton, rightButton, style, useInsets, children, }: Props): import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
export default function Header({ title, variant, leftButton, rightButton, style, useInsets, children, scrollY, collapseThreshold, }: Props): import("react/jsx-runtime").JSX.Element;
|
|
22
27
|
export {};
|
|
23
28
|
//# sourceMappingURL=Header.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../../../src/components/Header.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAoB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../../../src/components/Header.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAoB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAChF,OAAiB,EAGf,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AAIjC,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAKvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,CAAC;AAIpD,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,OAAO,aAAa,CAAC;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,KAAK,KAAK,GAAG,iBAAiB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+LAA+L;IAC/L,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC9B,kGAAkG;IAClG,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAIF,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,EAC7B,KAAK,EACL,OAAmB,EACnB,UAAU,EACV,WAAW,EACX,KAAK,EACL,SAAgB,EAChB,QAAQ,EACR,OAAO,EACP,iBAA8C,GAC/C,EAAE,KAAK,2CAoKP"}
|
package/package.json
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { type PropsWithChildren } from 'react';
|
|
2
2
|
import { StyleSheet, View, type ViewStyle, type StyleProp } from 'react-native';
|
|
3
|
+
import Animated, {
|
|
4
|
+
interpolate,
|
|
5
|
+
useAnimatedStyle,
|
|
6
|
+
type SharedValue,
|
|
7
|
+
} from 'react-native-reanimated';
|
|
3
8
|
|
|
4
9
|
import Text from './Text';
|
|
5
10
|
import IconButton from './IconButton';
|
|
@@ -12,6 +17,8 @@ import type { ButtonVariant } from './ButtonContainer';
|
|
|
12
17
|
|
|
13
18
|
export type HeaderVariant = 'default' | 'secondary';
|
|
14
19
|
|
|
20
|
+
const DEFAULT_COLLAPSE_THRESHOLD = 80;
|
|
21
|
+
|
|
15
22
|
type HeaderButtonProps = {
|
|
16
23
|
iconName: IconName;
|
|
17
24
|
onPress?: () => void;
|
|
@@ -27,6 +34,10 @@ type Props = PropsWithChildren & {
|
|
|
27
34
|
rightButton?: HeaderButtonProps;
|
|
28
35
|
style?: StyleProp<ViewStyle>;
|
|
29
36
|
useInsets?: boolean;
|
|
37
|
+
/** When set with variant="secondary", header animates from large title to compact as user scrolls (iOS-style). Pass the scroll view's contentOffset.y (e.g. from useAnimatedScrollHandler). */
|
|
38
|
+
scrollY?: SharedValue<number>;
|
|
39
|
+
/** Scroll offset at which the header is fully collapsed. Ignored when scrollY is not provided. */
|
|
40
|
+
collapseThreshold?: number;
|
|
30
41
|
};
|
|
31
42
|
|
|
32
43
|
const HEADER_BASE_HEIGHT = 52;
|
|
@@ -39,10 +50,57 @@ export default function Header({
|
|
|
39
50
|
style,
|
|
40
51
|
useInsets = true,
|
|
41
52
|
children,
|
|
53
|
+
scrollY,
|
|
54
|
+
collapseThreshold = DEFAULT_COLLAPSE_THRESHOLD,
|
|
42
55
|
}: Props) {
|
|
43
56
|
const { colors, theme } = useTheme();
|
|
44
57
|
const topInset = useInsets ? theme.insets?.top || 0 : 0;
|
|
45
58
|
const isSecondary = variant === 'secondary';
|
|
59
|
+
const isCollapsible = isSecondary && scrollY != null;
|
|
60
|
+
|
|
61
|
+
const animatedHeaderStyle = useAnimatedStyle(() => {
|
|
62
|
+
if (!isCollapsible || scrollY == null) return {};
|
|
63
|
+
const progress = interpolate(
|
|
64
|
+
scrollY.value,
|
|
65
|
+
[0, collapseThreshold],
|
|
66
|
+
[0, 1],
|
|
67
|
+
'clamp'
|
|
68
|
+
);
|
|
69
|
+
return {
|
|
70
|
+
paddingBottom: interpolate(progress, [0, 1], [12, 0]),
|
|
71
|
+
};
|
|
72
|
+
}, [isCollapsible, collapseThreshold]);
|
|
73
|
+
|
|
74
|
+
const animatedTitleRowStyle = useAnimatedStyle(() => {
|
|
75
|
+
if (!isCollapsible || scrollY == null) return {};
|
|
76
|
+
const progress = interpolate(
|
|
77
|
+
scrollY.value,
|
|
78
|
+
[0, collapseThreshold],
|
|
79
|
+
[0, 1],
|
|
80
|
+
'clamp'
|
|
81
|
+
);
|
|
82
|
+
// Estimate: h1 fontSize 24 + line height ~16 + paddingTop 4 = ~44px
|
|
83
|
+
const titleRowHeight = 44;
|
|
84
|
+
return {
|
|
85
|
+
opacity: interpolate(progress, [0, 1], [1, 0]),
|
|
86
|
+
height: interpolate(progress, [0, 1], [titleRowHeight, 0]),
|
|
87
|
+
overflow: 'hidden' as const,
|
|
88
|
+
transform: [{ translateY: interpolate(progress, [0, 1], [0, -16]) }],
|
|
89
|
+
};
|
|
90
|
+
}, [isCollapsible, collapseThreshold]);
|
|
91
|
+
|
|
92
|
+
const animatedSmallTitleStyle = useAnimatedStyle(() => {
|
|
93
|
+
if (!isCollapsible || scrollY == null) return {};
|
|
94
|
+
const progress = interpolate(
|
|
95
|
+
scrollY.value,
|
|
96
|
+
[0, collapseThreshold],
|
|
97
|
+
[0, 1],
|
|
98
|
+
'clamp'
|
|
99
|
+
);
|
|
100
|
+
return {
|
|
101
|
+
opacity: interpolate(progress, [0, 1], [0, 1]),
|
|
102
|
+
};
|
|
103
|
+
}, [isCollapsible, collapseThreshold]);
|
|
46
104
|
|
|
47
105
|
const renderButton = (button: HeaderButtonProps) => {
|
|
48
106
|
return (
|
|
@@ -57,57 +115,104 @@ export default function Header({
|
|
|
57
115
|
);
|
|
58
116
|
};
|
|
59
117
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
backgroundColor: colors.background,
|
|
66
|
-
borderBottomColor: colors.border,
|
|
67
|
-
paddingTop: topInset,
|
|
68
|
-
},
|
|
69
|
-
isSecondary && styles.headerSecondary,
|
|
70
|
-
!!children && styles.paddingBottom,
|
|
71
|
-
style,
|
|
72
|
-
]}
|
|
73
|
-
>
|
|
118
|
+
const showSmallTitleInBar = !isSecondary || isCollapsible;
|
|
119
|
+
const showBigTitleRow = isSecondary;
|
|
120
|
+
|
|
121
|
+
const headerContent = (
|
|
122
|
+
<>
|
|
74
123
|
<View
|
|
75
124
|
style={[
|
|
76
125
|
styles.headerContent,
|
|
77
|
-
isSecondary && styles.headerContentSecondary,
|
|
126
|
+
isSecondary && !isCollapsible && styles.headerContentSecondary,
|
|
127
|
+
isCollapsible && styles.headerContentSecondary,
|
|
78
128
|
]}
|
|
79
129
|
>
|
|
80
130
|
<View style={[styles.slot, styles.leftSlot]}>
|
|
81
131
|
{leftButton && renderButton(leftButton)}
|
|
82
132
|
</View>
|
|
83
|
-
{
|
|
84
|
-
<View style={styles.titleContainer}>
|
|
133
|
+
{showSmallTitleInBar && (
|
|
134
|
+
<View style={styles.titleContainer} pointerEvents="none">
|
|
135
|
+
{isCollapsible ? (
|
|
136
|
+
<Animated.View
|
|
137
|
+
style={[styles.titleContainer, animatedSmallTitleStyle]}
|
|
138
|
+
>
|
|
139
|
+
<Text
|
|
140
|
+
variant="h3"
|
|
141
|
+
style={[styles.title, { color: colors.foreground }]}
|
|
142
|
+
numberOfLines={1}
|
|
143
|
+
ellipsizeMode="tail"
|
|
144
|
+
>
|
|
145
|
+
{title}
|
|
146
|
+
</Text>
|
|
147
|
+
</Animated.View>
|
|
148
|
+
) : (
|
|
149
|
+
<Text
|
|
150
|
+
variant="h3"
|
|
151
|
+
style={[styles.title, { color: colors.foreground }]}
|
|
152
|
+
numberOfLines={1}
|
|
153
|
+
ellipsizeMode="tail"
|
|
154
|
+
>
|
|
155
|
+
{title}
|
|
156
|
+
</Text>
|
|
157
|
+
)}
|
|
158
|
+
</View>
|
|
159
|
+
)}
|
|
160
|
+
<View style={[styles.slot, styles.rightSlot]}>
|
|
161
|
+
{rightButton && renderButton(rightButton)}
|
|
162
|
+
</View>
|
|
163
|
+
</View>
|
|
164
|
+
{showBigTitleRow &&
|
|
165
|
+
(isCollapsible ? (
|
|
166
|
+
<Animated.View style={[styles.titleRow, animatedTitleRowStyle]}>
|
|
167
|
+
<Text
|
|
168
|
+
variant="h1"
|
|
169
|
+
style={[styles.titleSecondary, { color: colors.foreground }]}
|
|
170
|
+
numberOfLines={1}
|
|
171
|
+
ellipsizeMode="tail"
|
|
172
|
+
>
|
|
173
|
+
{title}
|
|
174
|
+
</Text>
|
|
175
|
+
</Animated.View>
|
|
176
|
+
) : (
|
|
177
|
+
<View style={styles.titleRow}>
|
|
85
178
|
<Text
|
|
86
|
-
variant="
|
|
87
|
-
style={[styles.
|
|
179
|
+
variant="h1"
|
|
180
|
+
style={[styles.titleSecondary, { color: colors.foreground }]}
|
|
88
181
|
numberOfLines={1}
|
|
89
182
|
ellipsizeMode="tail"
|
|
90
183
|
>
|
|
91
184
|
{title}
|
|
92
185
|
</Text>
|
|
93
186
|
</View>
|
|
94
|
-
)}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
187
|
+
))}
|
|
188
|
+
</>
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const staticHeaderStyle = [
|
|
192
|
+
styles.header,
|
|
193
|
+
{
|
|
194
|
+
backgroundColor: colors.background,
|
|
195
|
+
borderBottomColor: colors.border,
|
|
196
|
+
paddingTop: topInset,
|
|
197
|
+
},
|
|
198
|
+
isSecondary && !isCollapsible && styles.headerSecondary,
|
|
199
|
+
isCollapsible && styles.headerSecondary,
|
|
200
|
+
!!children && styles.paddingBottom,
|
|
201
|
+
style,
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
if (isCollapsible) {
|
|
205
|
+
return (
|
|
206
|
+
<Animated.View style={[staticHeaderStyle, animatedHeaderStyle]}>
|
|
207
|
+
{headerContent}
|
|
208
|
+
{children}
|
|
209
|
+
</Animated.View>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return (
|
|
214
|
+
<View style={staticHeaderStyle}>
|
|
215
|
+
{headerContent}
|
|
111
216
|
{children}
|
|
112
217
|
</View>
|
|
113
218
|
);
|