@react-native-ohos/elements 2.3.9-rc.1

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 (222) hide show
  1. package/LICENSE +21 -0
  2. package/README.OpenSource +11 -0
  3. package/README.md +9 -0
  4. package/lib/module/Background.js +22 -0
  5. package/lib/module/Background.js.map +1 -0
  6. package/lib/module/Button.js +106 -0
  7. package/lib/module/Button.js.map +1 -0
  8. package/lib/module/Header/Header.js +338 -0
  9. package/lib/module/Header/Header.js.map +1 -0
  10. package/lib/module/Header/HeaderBackButton.js +188 -0
  11. package/lib/module/Header/HeaderBackButton.js.map +1 -0
  12. package/lib/module/Header/HeaderBackContext.js +5 -0
  13. package/lib/module/Header/HeaderBackContext.js.map +1 -0
  14. package/lib/module/Header/HeaderBackground.js +47 -0
  15. package/lib/module/Header/HeaderBackground.js.map +1 -0
  16. package/lib/module/Header/HeaderButton.js +56 -0
  17. package/lib/module/Header/HeaderButton.js.map +1 -0
  18. package/lib/module/Header/HeaderHeightContext.js +5 -0
  19. package/lib/module/Header/HeaderHeightContext.js.map +1 -0
  20. package/lib/module/Header/HeaderIcon.js +38 -0
  21. package/lib/module/Header/HeaderIcon.js.map +1 -0
  22. package/lib/module/Header/HeaderSearchBar.js +288 -0
  23. package/lib/module/Header/HeaderSearchBar.js.map +1 -0
  24. package/lib/module/Header/HeaderShownContext.js +5 -0
  25. package/lib/module/Header/HeaderShownContext.js.map +1 -0
  26. package/lib/module/Header/HeaderTitle.js +41 -0
  27. package/lib/module/Header/HeaderTitle.js.map +1 -0
  28. package/lib/module/Header/getDefaultHeaderHeight.js +45 -0
  29. package/lib/module/Header/getDefaultHeaderHeight.js.map +1 -0
  30. package/lib/module/Header/getHeaderTitle.js +6 -0
  31. package/lib/module/Header/getHeaderTitle.js.map +1 -0
  32. package/lib/module/Header/useHeaderHeight.js +12 -0
  33. package/lib/module/Header/useHeaderHeight.js.map +1 -0
  34. package/lib/module/Label/Label.js +25 -0
  35. package/lib/module/Label/Label.js.map +1 -0
  36. package/lib/module/Label/getLabel.js +6 -0
  37. package/lib/module/Label/getLabel.js.map +1 -0
  38. package/lib/module/MaskedView.android.js +4 -0
  39. package/lib/module/MaskedView.android.js.map +1 -0
  40. package/lib/module/MaskedView.ios.js +4 -0
  41. package/lib/module/MaskedView.ios.js.map +1 -0
  42. package/lib/module/MaskedView.js +12 -0
  43. package/lib/module/MaskedView.js.map +1 -0
  44. package/lib/module/MaskedViewNative.js +30 -0
  45. package/lib/module/MaskedViewNative.js.map +1 -0
  46. package/lib/module/MissingIcon.js +24 -0
  47. package/lib/module/MissingIcon.js.map +1 -0
  48. package/lib/module/PlatformPressable.js +141 -0
  49. package/lib/module/PlatformPressable.js.map +1 -0
  50. package/lib/module/ResourceSavingView.js +57 -0
  51. package/lib/module/ResourceSavingView.js.map +1 -0
  52. package/lib/module/SafeAreaProviderCompat.js +58 -0
  53. package/lib/module/SafeAreaProviderCompat.js.map +1 -0
  54. package/lib/module/Screen.js +83 -0
  55. package/lib/module/Screen.js.map +1 -0
  56. package/lib/module/Text.js +22 -0
  57. package/lib/module/Text.js.map +1 -0
  58. package/lib/module/assets/back-icon-mask.png +0 -0
  59. package/lib/module/assets/back-icon.png +0 -0
  60. package/lib/module/assets/back-icon@1x.android.png +0 -0
  61. package/lib/module/assets/back-icon@1x.ios.png +0 -0
  62. package/lib/module/assets/back-icon@2x.android.png +0 -0
  63. package/lib/module/assets/back-icon@2x.ios.png +0 -0
  64. package/lib/module/assets/back-icon@3x.android.png +0 -0
  65. package/lib/module/assets/back-icon@3x.ios.png +0 -0
  66. package/lib/module/assets/back-icon@4x.android.png +0 -0
  67. package/lib/module/assets/back-icon@4x.ios.png +0 -0
  68. package/lib/module/assets/clear-icon.png +0 -0
  69. package/lib/module/assets/clear-icon@1x.png +0 -0
  70. package/lib/module/assets/clear-icon@2x.png +0 -0
  71. package/lib/module/assets/clear-icon@3x.png +0 -0
  72. package/lib/module/assets/clear-icon@4x.png +0 -0
  73. package/lib/module/assets/close-icon.png +0 -0
  74. package/lib/module/assets/close-icon@1x.png +0 -0
  75. package/lib/module/assets/close-icon@2x.png +0 -0
  76. package/lib/module/assets/close-icon@3x.png +0 -0
  77. package/lib/module/assets/close-icon@4x.png +0 -0
  78. package/lib/module/assets/search-icon.png +0 -0
  79. package/lib/module/assets/search-icon@1x.android.png +0 -0
  80. package/lib/module/assets/search-icon@1x.ios.png +0 -0
  81. package/lib/module/assets/search-icon@2x.android.png +0 -0
  82. package/lib/module/assets/search-icon@2x.ios.png +0 -0
  83. package/lib/module/assets/search-icon@3x.android.png +0 -0
  84. package/lib/module/assets/search-icon@3x.ios.png +0 -0
  85. package/lib/module/assets/search-icon@4x.android.png +0 -0
  86. package/lib/module/assets/search-icon@4x.ios.png +0 -0
  87. package/lib/module/getDefaultSidebarWidth.js +18 -0
  88. package/lib/module/getDefaultSidebarWidth.js.map +1 -0
  89. package/lib/module/getNamedContext.js +17 -0
  90. package/lib/module/getNamedContext.js.map +1 -0
  91. package/lib/module/index.js +32 -0
  92. package/lib/module/index.js.map +1 -0
  93. package/lib/module/package.json +1 -0
  94. package/lib/module/types.js +4 -0
  95. package/lib/module/types.js.map +1 -0
  96. package/lib/typescript/package.json +1 -0
  97. package/lib/typescript/src/Background.d.ts +9 -0
  98. package/lib/typescript/src/Background.d.ts.map +1 -0
  99. package/lib/typescript/src/Button.d.ts +13 -0
  100. package/lib/typescript/src/Button.d.ts.map +1 -0
  101. package/lib/typescript/src/Header/Header.d.ts +31 -0
  102. package/lib/typescript/src/Header/Header.d.ts.map +1 -0
  103. package/lib/typescript/src/Header/HeaderBackButton.d.ts +3 -0
  104. package/lib/typescript/src/Header/HeaderBackButton.d.ts.map +1 -0
  105. package/lib/typescript/src/Header/HeaderBackContext.d.ts +5 -0
  106. package/lib/typescript/src/Header/HeaderBackContext.d.ts.map +1 -0
  107. package/lib/typescript/src/Header/HeaderBackground.d.ts +9 -0
  108. package/lib/typescript/src/Header/HeaderBackground.d.ts.map +1 -0
  109. package/lib/typescript/src/Header/HeaderButton.d.ts +3 -0
  110. package/lib/typescript/src/Header/HeaderButton.d.ts.map +1 -0
  111. package/lib/typescript/src/Header/HeaderHeightContext.d.ts +2 -0
  112. package/lib/typescript/src/Header/HeaderHeightContext.d.ts.map +1 -0
  113. package/lib/typescript/src/Header/HeaderIcon.d.ts +5 -0
  114. package/lib/typescript/src/Header/HeaderIcon.d.ts.map +1 -0
  115. package/lib/typescript/src/Header/HeaderSearchBar.d.ts +10 -0
  116. package/lib/typescript/src/Header/HeaderSearchBar.d.ts.map +1 -0
  117. package/lib/typescript/src/Header/HeaderShownContext.d.ts +2 -0
  118. package/lib/typescript/src/Header/HeaderShownContext.d.ts.map +1 -0
  119. package/lib/typescript/src/Header/HeaderTitle.d.ts +9 -0
  120. package/lib/typescript/src/Header/HeaderTitle.d.ts.map +1 -0
  121. package/lib/typescript/src/Header/getDefaultHeaderHeight.d.ts +3 -0
  122. package/lib/typescript/src/Header/getDefaultHeaderHeight.d.ts.map +1 -0
  123. package/lib/typescript/src/Header/getHeaderTitle.d.ts +6 -0
  124. package/lib/typescript/src/Header/getHeaderTitle.d.ts.map +1 -0
  125. package/lib/typescript/src/Header/useHeaderHeight.d.ts +2 -0
  126. package/lib/typescript/src/Header/useHeaderHeight.d.ts.map +1 -0
  127. package/lib/typescript/src/Label/Label.d.ts +9 -0
  128. package/lib/typescript/src/Label/Label.d.ts.map +1 -0
  129. package/lib/typescript/src/Label/getLabel.d.ts +5 -0
  130. package/lib/typescript/src/Label/getLabel.d.ts.map +1 -0
  131. package/lib/typescript/src/MaskedView.android.d.ts +2 -0
  132. package/lib/typescript/src/MaskedView.android.d.ts.map +1 -0
  133. package/lib/typescript/src/MaskedView.d.ts +11 -0
  134. package/lib/typescript/src/MaskedView.d.ts.map +1 -0
  135. package/lib/typescript/src/MaskedView.ios.d.ts +2 -0
  136. package/lib/typescript/src/MaskedView.ios.d.ts.map +1 -0
  137. package/lib/typescript/src/MaskedViewNative.d.ts +11 -0
  138. package/lib/typescript/src/MaskedViewNative.d.ts.map +1 -0
  139. package/lib/typescript/src/MissingIcon.d.ts +9 -0
  140. package/lib/typescript/src/MissingIcon.d.ts.map +1 -0
  141. package/lib/typescript/src/PlatformPressable.d.ts +21 -0
  142. package/lib/typescript/src/PlatformPressable.d.ts.map +1 -0
  143. package/lib/typescript/src/ResourceSavingView.d.ts +10 -0
  144. package/lib/typescript/src/ResourceSavingView.d.ts.map +1 -0
  145. package/lib/typescript/src/SafeAreaProviderCompat.d.ts +12 -0
  146. package/lib/typescript/src/SafeAreaProviderCompat.d.ts.map +1 -0
  147. package/lib/typescript/src/Screen.d.ts +18 -0
  148. package/lib/typescript/src/Screen.d.ts.map +1 -0
  149. package/lib/typescript/src/Text.d.ts +3 -0
  150. package/lib/typescript/src/Text.d.ts.map +1 -0
  151. package/lib/typescript/src/__tests__/PlatformPressable.test.d.ts +2 -0
  152. package/lib/typescript/src/__tests__/PlatformPressable.test.d.ts.map +1 -0
  153. package/lib/typescript/src/getDefaultSidebarWidth.d.ts +4 -0
  154. package/lib/typescript/src/getDefaultSidebarWidth.d.ts.map +1 -0
  155. package/lib/typescript/src/getNamedContext.d.ts +6 -0
  156. package/lib/typescript/src/getNamedContext.d.ts.map +1 -0
  157. package/lib/typescript/src/index.d.ts +25 -0
  158. package/lib/typescript/src/index.d.ts.map +1 -0
  159. package/lib/typescript/src/types.d.ts +325 -0
  160. package/lib/typescript/src/types.d.ts.map +1 -0
  161. package/package.json +83 -0
  162. package/src/Background.tsx +24 -0
  163. package/src/Button.tsx +120 -0
  164. package/src/Header/Header.tsx +450 -0
  165. package/src/Header/HeaderBackButton.tsx +249 -0
  166. package/src/Header/HeaderBackContext.tsx +5 -0
  167. package/src/Header/HeaderBackground.tsx +60 -0
  168. package/src/Header/HeaderButton.tsx +55 -0
  169. package/src/Header/HeaderHeightContext.tsx +6 -0
  170. package/src/Header/HeaderIcon.tsx +32 -0
  171. package/src/Header/HeaderSearchBar.tsx +323 -0
  172. package/src/Header/HeaderShownContext.tsx +3 -0
  173. package/src/Header/HeaderTitle.tsx +48 -0
  174. package/src/Header/getDefaultHeaderHeight.tsx +54 -0
  175. package/src/Header/getHeaderTitle.tsx +12 -0
  176. package/src/Header/useHeaderHeight.tsx +15 -0
  177. package/src/Label/Label.tsx +31 -0
  178. package/src/Label/getLabel.tsx +10 -0
  179. package/src/MaskedView.android.tsx +1 -0
  180. package/src/MaskedView.ios.tsx +1 -0
  181. package/src/MaskedView.tsx +13 -0
  182. package/src/MaskedViewNative.tsx +33 -0
  183. package/src/MissingIcon.tsx +19 -0
  184. package/src/PlatformPressable.tsx +196 -0
  185. package/src/ResourceSavingView.tsx +76 -0
  186. package/src/SafeAreaProviderCompat.tsx +61 -0
  187. package/src/Screen.tsx +123 -0
  188. package/src/Text.tsx +14 -0
  189. package/src/__tests__/PlatformPressable.test.tsx +81 -0
  190. package/src/assets/back-icon-mask.png +0 -0
  191. package/src/assets/back-icon.png +0 -0
  192. package/src/assets/back-icon@1x.android.png +0 -0
  193. package/src/assets/back-icon@1x.ios.png +0 -0
  194. package/src/assets/back-icon@2x.android.png +0 -0
  195. package/src/assets/back-icon@2x.ios.png +0 -0
  196. package/src/assets/back-icon@3x.android.png +0 -0
  197. package/src/assets/back-icon@3x.ios.png +0 -0
  198. package/src/assets/back-icon@4x.android.png +0 -0
  199. package/src/assets/back-icon@4x.ios.png +0 -0
  200. package/src/assets/clear-icon.png +0 -0
  201. package/src/assets/clear-icon@1x.png +0 -0
  202. package/src/assets/clear-icon@2x.png +0 -0
  203. package/src/assets/clear-icon@3x.png +0 -0
  204. package/src/assets/clear-icon@4x.png +0 -0
  205. package/src/assets/close-icon.png +0 -0
  206. package/src/assets/close-icon@1x.png +0 -0
  207. package/src/assets/close-icon@2x.png +0 -0
  208. package/src/assets/close-icon@3x.png +0 -0
  209. package/src/assets/close-icon@4x.png +0 -0
  210. package/src/assets/search-icon.png +0 -0
  211. package/src/assets/search-icon@1x.android.png +0 -0
  212. package/src/assets/search-icon@1x.ios.png +0 -0
  213. package/src/assets/search-icon@2x.android.png +0 -0
  214. package/src/assets/search-icon@2x.ios.png +0 -0
  215. package/src/assets/search-icon@3x.android.png +0 -0
  216. package/src/assets/search-icon@3x.ios.png +0 -0
  217. package/src/assets/search-icon@4x.android.png +0 -0
  218. package/src/assets/search-icon@4x.ios.png +0 -0
  219. package/src/getDefaultSidebarWidth.tsx +15 -0
  220. package/src/getNamedContext.tsx +30 -0
  221. package/src/index.tsx +38 -0
  222. package/src/types.tsx +338 -0
package/src/Button.tsx ADDED
@@ -0,0 +1,120 @@
1
+ import {
2
+ type LinkProps,
3
+ useLinkProps,
4
+ useTheme,
5
+ } from '@react-navigation/native';
6
+ import Color from 'color';
7
+ import * as React from 'react';
8
+ import { Platform, StyleSheet } from 'react-native';
9
+
10
+ import {
11
+ PlatformPressable,
12
+ type Props as PlatformPressableProps,
13
+ } from './PlatformPressable';
14
+ import { Text } from './Text';
15
+
16
+ type ButtonBaseProps = Omit<PlatformPressableProps, 'children'> & {
17
+ variant?: 'plain' | 'tinted' | 'filled';
18
+ color?: string;
19
+ children: string | string[];
20
+ };
21
+
22
+ type ButtonLinkProps<ParamList extends ReactNavigation.RootParamList> =
23
+ LinkProps<ParamList> & Omit<ButtonBaseProps, 'onPress'>;
24
+
25
+ const BUTTON_RADIUS = 40;
26
+
27
+ export function Button<ParamList extends ReactNavigation.RootParamList>(
28
+ props: ButtonLinkProps<ParamList>
29
+ ): React.JSX.Element;
30
+
31
+ export function Button(props: ButtonBaseProps): React.JSX.Element;
32
+
33
+ export function Button<ParamList extends ReactNavigation.RootParamList>(
34
+ props: ButtonBaseProps | ButtonLinkProps<ParamList>
35
+ ) {
36
+ if ('screen' in props || 'action' in props) {
37
+ // @ts-expect-error: This is already type-checked by the prop types
38
+ return <ButtonLink {...props} />;
39
+ } else {
40
+ return <ButtonBase {...props} />;
41
+ }
42
+ }
43
+
44
+ function ButtonLink<ParamList extends ReactNavigation.RootParamList>({
45
+ screen,
46
+ params,
47
+ action,
48
+ href,
49
+ ...rest
50
+ }: ButtonLinkProps<ParamList>) {
51
+ // @ts-expect-error: This is already type-checked by the prop types
52
+ const props = useLinkProps({ screen, params, action, href });
53
+
54
+ return <ButtonBase {...rest} {...props} />;
55
+ }
56
+
57
+ function ButtonBase({
58
+ variant = 'tinted',
59
+ color: customColor,
60
+ android_ripple,
61
+ style,
62
+ children,
63
+ ...rest
64
+ }: ButtonBaseProps) {
65
+ const { colors, fonts } = useTheme();
66
+
67
+ const color = customColor ?? colors.primary;
68
+
69
+ let backgroundColor;
70
+ let textColor;
71
+
72
+ switch (variant) {
73
+ case 'plain':
74
+ backgroundColor = 'transparent';
75
+ textColor = color;
76
+ break;
77
+ case 'tinted':
78
+ backgroundColor = Color(color).fade(0.85).string();
79
+ textColor = color;
80
+ break;
81
+ case 'filled':
82
+ backgroundColor = color;
83
+ textColor = Color(color).isDark()
84
+ ? 'white'
85
+ : Color(color).darken(0.71).string();
86
+ break;
87
+ }
88
+
89
+ return (
90
+ <PlatformPressable
91
+ {...rest}
92
+ android_ripple={{
93
+ radius: BUTTON_RADIUS,
94
+ color: Color(textColor).fade(0.85).string(),
95
+ ...android_ripple,
96
+ }}
97
+ pressOpacity={Platform.OS === 'ios' ? undefined : 1}
98
+ hoverEffect={{ color: textColor }}
99
+ style={[{ backgroundColor }, styles.button, style]}
100
+ >
101
+ <Text style={[{ color: textColor }, fonts.regular, styles.text]}>
102
+ {children}
103
+ </Text>
104
+ </PlatformPressable>
105
+ );
106
+ }
107
+
108
+ const styles = StyleSheet.create({
109
+ button: {
110
+ paddingHorizontal: 24,
111
+ paddingVertical: 10,
112
+ borderRadius: BUTTON_RADIUS,
113
+ },
114
+ text: {
115
+ fontSize: 14,
116
+ lineHeight: 20,
117
+ letterSpacing: 0.1,
118
+ textAlign: 'center',
119
+ },
120
+ });
@@ -0,0 +1,450 @@
1
+ import { useNavigation, useTheme } from '@react-navigation/native';
2
+ import Color from 'color';
3
+ import * as React from 'react';
4
+ import {
5
+ Animated,
6
+ type LayoutChangeEvent,
7
+ Platform,
8
+ StyleSheet,
9
+ View,
10
+ type ViewStyle,
11
+ } from 'react-native';
12
+ import {
13
+ useSafeAreaFrame,
14
+ useSafeAreaInsets,
15
+ } from 'react-native-safe-area-context';
16
+
17
+ import searchIcon from '../assets/search-icon.png';
18
+ import type { HeaderOptions, Layout } from '../types';
19
+ import { getDefaultHeaderHeight } from './getDefaultHeaderHeight';
20
+ import { HeaderBackButton } from './HeaderBackButton';
21
+ import { HeaderBackground } from './HeaderBackground';
22
+ import { HeaderButton } from './HeaderButton';
23
+ import { HeaderIcon } from './HeaderIcon';
24
+ import { HeaderSearchBar } from './HeaderSearchBar';
25
+ import { HeaderShownContext } from './HeaderShownContext';
26
+ import { HeaderTitle } from './HeaderTitle';
27
+
28
+ // Width of the screen in split layout on portrait mode on iPad Mini
29
+ const IPAD_MINI_MEDIUM_WIDTH = 414;
30
+
31
+ type Props = HeaderOptions & {
32
+ /**
33
+ * Options for the back button.
34
+ */
35
+ back?: {
36
+ /**
37
+ * Title of the previous screen.
38
+ */
39
+ title: string | undefined;
40
+ /**
41
+ * The `href` to use for the anchor tag on web
42
+ */
43
+ href: string | undefined;
44
+ };
45
+ /**
46
+ * Whether the header is in a modal
47
+ */
48
+ modal?: boolean;
49
+ /**
50
+ * Layout of the screen.
51
+ */
52
+ layout?: Layout;
53
+ /**
54
+ * Title text for the header.
55
+ */
56
+ title: string;
57
+ };
58
+
59
+ const warnIfHeaderStylesDefined = (styles: Record<string, any>) => {
60
+ Object.keys(styles).forEach((styleProp) => {
61
+ const value = styles[styleProp];
62
+
63
+ if (styleProp === 'position' && value === 'absolute') {
64
+ console.warn(
65
+ "position: 'absolute' is not supported on headerStyle. If you would like to render content under the header, use the 'headerTransparent' option."
66
+ );
67
+ } else if (value !== undefined) {
68
+ console.warn(
69
+ `${styleProp} was given a value of ${value}, this has no effect on headerStyle.`
70
+ );
71
+ }
72
+ });
73
+ };
74
+
75
+ export function Header(props: Props) {
76
+ const insets = useSafeAreaInsets();
77
+ const frame = useSafeAreaFrame();
78
+ const { colors } = useTheme();
79
+
80
+ const navigation = useNavigation();
81
+ const isParentHeaderShown = React.useContext(HeaderShownContext);
82
+
83
+ const [searchBarVisible, setSearchBarVisible] = React.useState(false);
84
+ const [titleLayout, setTitleLayout] = React.useState<Layout | undefined>(
85
+ undefined
86
+ );
87
+
88
+ const onTitleLayout = (e: LayoutChangeEvent) => {
89
+ const { height, width } = e.nativeEvent.layout;
90
+
91
+ setTitleLayout((titleLayout) => {
92
+ if (
93
+ titleLayout &&
94
+ height === titleLayout.height &&
95
+ width === titleLayout.width
96
+ ) {
97
+ return titleLayout;
98
+ }
99
+
100
+ return { height, width };
101
+ });
102
+ };
103
+
104
+ const {
105
+ layout = frame,
106
+ modal = false,
107
+ back,
108
+ title,
109
+ headerTitle: customTitle,
110
+ headerTitleAlign = Platform.OS === 'ios' ? 'center' : 'left',
111
+ headerLeft = back ? (props) => <HeaderBackButton {...props} /> : undefined,
112
+ headerSearchBarOptions,
113
+ headerTransparent,
114
+ headerTintColor,
115
+ headerBackground,
116
+ headerRight,
117
+ headerTitleAllowFontScaling: titleAllowFontScaling,
118
+ headerTitleStyle: titleStyle,
119
+ headerLeftContainerStyle: leftContainerStyle,
120
+ headerRightContainerStyle: rightContainerStyle,
121
+ headerTitleContainerStyle: titleContainerStyle,
122
+ headerBackButtonDisplayMode = Platform.OS === 'ios' ? 'default' : 'minimal',
123
+ headerBackTitleStyle,
124
+ headerBackgroundContainerStyle: backgroundContainerStyle,
125
+ headerStyle: customHeaderStyle,
126
+ headerShadowVisible,
127
+ headerPressColor,
128
+ headerPressOpacity,
129
+ headerStatusBarHeight = isParentHeaderShown ? 0 : insets.top,
130
+ } = props;
131
+
132
+ const defaultHeight = getDefaultHeaderHeight(
133
+ layout,
134
+ modal,
135
+ headerStatusBarHeight
136
+ );
137
+
138
+ const {
139
+ height = defaultHeight,
140
+ minHeight,
141
+ maxHeight,
142
+ backgroundColor,
143
+ borderBottomColor,
144
+ borderBottomEndRadius,
145
+ borderBottomLeftRadius,
146
+ borderBottomRightRadius,
147
+ borderBottomStartRadius,
148
+ borderBottomWidth,
149
+ borderColor,
150
+ borderEndColor,
151
+ borderEndWidth,
152
+ borderLeftColor,
153
+ borderLeftWidth,
154
+ borderRadius,
155
+ borderRightColor,
156
+ borderRightWidth,
157
+ borderStartColor,
158
+ borderStartWidth,
159
+ borderStyle,
160
+ borderTopColor,
161
+ borderTopEndRadius,
162
+ borderTopLeftRadius,
163
+ borderTopRightRadius,
164
+ borderTopStartRadius,
165
+ borderTopWidth,
166
+ borderWidth,
167
+ boxShadow,
168
+ elevation,
169
+ shadowColor,
170
+ shadowOffset,
171
+ shadowOpacity,
172
+ shadowRadius,
173
+ opacity,
174
+ transform,
175
+ ...unsafeStyles
176
+ } = StyleSheet.flatten(customHeaderStyle || {}) as ViewStyle;
177
+
178
+ if (process.env.NODE_ENV !== 'production') {
179
+ warnIfHeaderStylesDefined(unsafeStyles);
180
+ }
181
+
182
+ const safeStyles: ViewStyle = {
183
+ backgroundColor,
184
+ borderBottomColor,
185
+ borderBottomEndRadius,
186
+ borderBottomLeftRadius,
187
+ borderBottomRightRadius,
188
+ borderBottomStartRadius,
189
+ borderBottomWidth,
190
+ borderColor,
191
+ borderEndColor,
192
+ borderEndWidth,
193
+ borderLeftColor,
194
+ borderLeftWidth,
195
+ borderRadius,
196
+ borderRightColor,
197
+ borderRightWidth,
198
+ borderStartColor,
199
+ borderStartWidth,
200
+ borderStyle,
201
+ borderTopColor,
202
+ borderTopEndRadius,
203
+ borderTopLeftRadius,
204
+ borderTopRightRadius,
205
+ borderTopStartRadius,
206
+ borderTopWidth,
207
+ borderWidth,
208
+ boxShadow,
209
+ elevation,
210
+ shadowColor,
211
+ shadowOffset,
212
+ shadowOpacity,
213
+ shadowRadius,
214
+ opacity,
215
+ transform,
216
+ };
217
+
218
+ // Setting a property to undefined triggers default style
219
+ // So we need to filter them out
220
+ // Users can use `null` instead
221
+ for (const styleProp in safeStyles) {
222
+ // @ts-expect-error: typescript wrongly complains that styleProp cannot be used to index safeStyles
223
+ if (safeStyles[styleProp] === undefined) {
224
+ // @ts-expect-error don't need to care about index signature for deletion
225
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
226
+ delete safeStyles[styleProp];
227
+ }
228
+ }
229
+
230
+ const backgroundStyle = {
231
+ ...(headerTransparent && { backgroundColor: 'transparent' }),
232
+ ...((headerTransparent || headerShadowVisible === false) && {
233
+ borderBottomWidth: 0,
234
+ ...Platform.select({
235
+ android: {
236
+ elevation: 0,
237
+ },
238
+ web: {
239
+ boxShadow: 'none',
240
+ },
241
+ default: {
242
+ shadowOpacity: 0,
243
+ },
244
+ }),
245
+ }),
246
+ ...safeStyles,
247
+ };
248
+
249
+ const iconTintColor =
250
+ headerTintColor ??
251
+ Platform.select({
252
+ ios: colors.primary,
253
+ default: colors.text,
254
+ });
255
+
256
+ const leftButton = headerLeft
257
+ ? headerLeft({
258
+ tintColor: iconTintColor,
259
+ pressColor: headerPressColor,
260
+ pressOpacity: headerPressOpacity,
261
+ displayMode: headerBackButtonDisplayMode,
262
+ titleLayout,
263
+ screenLayout: layout,
264
+ canGoBack: Boolean(back),
265
+ onPress: back ? navigation.goBack : undefined,
266
+ label: back?.title,
267
+ labelStyle: headerBackTitleStyle,
268
+ href: back?.href,
269
+ })
270
+ : null;
271
+
272
+ const rightButton = headerRight
273
+ ? headerRight({
274
+ tintColor: iconTintColor,
275
+ pressColor: headerPressColor,
276
+ pressOpacity: headerPressOpacity,
277
+ canGoBack: Boolean(back),
278
+ })
279
+ : null;
280
+
281
+ const headerTitle =
282
+ typeof customTitle !== 'function'
283
+ ? (props: React.ComponentProps<typeof HeaderTitle>) => (
284
+ <HeaderTitle {...props} />
285
+ )
286
+ : customTitle;
287
+
288
+ return (
289
+ <Animated.View
290
+ pointerEvents="box-none"
291
+ style={[{ height, minHeight, maxHeight, opacity, transform }]}
292
+ >
293
+ <Animated.View
294
+ pointerEvents="box-none"
295
+ style={[StyleSheet.absoluteFill, backgroundContainerStyle]}
296
+ >
297
+ {headerBackground ? (
298
+ headerBackground({ style: backgroundStyle })
299
+ ) : (
300
+ <HeaderBackground
301
+ pointerEvents={
302
+ // Allow touch through the header when background color is transparent
303
+ headerTransparent &&
304
+ (backgroundStyle.backgroundColor === 'transparent' ||
305
+ Color(backgroundStyle.backgroundColor).alpha() === 0)
306
+ ? 'none'
307
+ : 'auto'
308
+ }
309
+ style={backgroundStyle}
310
+ />
311
+ )}
312
+ </Animated.View>
313
+ <View pointerEvents="none" style={{ height: headerStatusBarHeight }} />
314
+ <View
315
+ pointerEvents="box-none"
316
+ style={[
317
+ styles.content,
318
+ Platform.OS === 'ios' && frame.width >= IPAD_MINI_MEDIUM_WIDTH
319
+ ? styles.large
320
+ : null,
321
+ ]}
322
+ >
323
+ <Animated.View
324
+ pointerEvents="box-none"
325
+ style={[
326
+ styles.start,
327
+ !searchBarVisible && headerTitleAlign === 'center' && styles.expand,
328
+ { marginStart: insets.left },
329
+ leftContainerStyle,
330
+ ]}
331
+ >
332
+ {leftButton}
333
+ </Animated.View>
334
+ {Platform.OS === 'ios' || !searchBarVisible ? (
335
+ <>
336
+ <Animated.View
337
+ pointerEvents="box-none"
338
+ style={[
339
+ styles.title,
340
+ {
341
+ // Avoid the title from going offscreen or overlapping buttons
342
+ maxWidth:
343
+ headerTitleAlign === 'center'
344
+ ? layout.width -
345
+ ((leftButton
346
+ ? headerBackButtonDisplayMode !== 'minimal'
347
+ ? 80
348
+ : 32
349
+ : 16) +
350
+ (rightButton || headerSearchBarOptions ? 16 : 0) +
351
+ Math.max(insets.left, insets.right)) *
352
+ 2
353
+ : layout.width -
354
+ ((leftButton ? 52 : 16) +
355
+ (rightButton || headerSearchBarOptions ? 52 : 16) +
356
+ insets.left -
357
+ insets.right),
358
+ },
359
+ headerTitleAlign === 'left' && leftButton
360
+ ? { marginStart: 4 }
361
+ : { marginHorizontal: 16 },
362
+ titleContainerStyle,
363
+ ]}
364
+ >
365
+ {headerTitle({
366
+ children: title,
367
+ allowFontScaling: titleAllowFontScaling,
368
+ tintColor: headerTintColor,
369
+ onLayout: onTitleLayout,
370
+ style: titleStyle,
371
+ })}
372
+ </Animated.View>
373
+ <Animated.View
374
+ pointerEvents="box-none"
375
+ style={[
376
+ styles.end,
377
+ styles.expand,
378
+ { marginEnd: insets.right },
379
+ rightContainerStyle,
380
+ ]}
381
+ >
382
+ {rightButton}
383
+ {headerSearchBarOptions ? (
384
+ <HeaderButton
385
+ tintColor={iconTintColor}
386
+ pressColor={headerPressColor}
387
+ pressOpacity={headerPressOpacity}
388
+ onPress={() => {
389
+ setSearchBarVisible(true);
390
+ headerSearchBarOptions?.onOpen?.();
391
+ }}
392
+ >
393
+ <HeaderIcon source={searchIcon} tintColor={iconTintColor} />
394
+ </HeaderButton>
395
+ ) : null}
396
+ </Animated.View>
397
+ </>
398
+ ) : null}
399
+ {Platform.OS === 'ios' || searchBarVisible ? (
400
+ <HeaderSearchBar
401
+ {...headerSearchBarOptions}
402
+ visible={searchBarVisible}
403
+ onClose={() => {
404
+ setSearchBarVisible(false);
405
+ headerSearchBarOptions?.onClose?.();
406
+ }}
407
+ tintColor={headerTintColor}
408
+ style={[
409
+ Platform.OS === 'ios'
410
+ ? [
411
+ StyleSheet.absoluteFill,
412
+ { paddingTop: headerStatusBarHeight ? 0 : 4 },
413
+ { backgroundColor: backgroundColor ?? colors.card },
414
+ ]
415
+ : !leftButton && { marginStart: 8 },
416
+ ]}
417
+ />
418
+ ) : null}
419
+ </View>
420
+ </Animated.View>
421
+ );
422
+ }
423
+
424
+ const styles = StyleSheet.create({
425
+ content: {
426
+ flex: 1,
427
+ flexDirection: 'row',
428
+ alignItems: 'stretch',
429
+ },
430
+ large: {
431
+ marginHorizontal: 5,
432
+ },
433
+ title: {
434
+ justifyContent: 'center',
435
+ },
436
+ start: {
437
+ flexDirection: 'row',
438
+ alignItems: 'center',
439
+ justifyContent: 'flex-start',
440
+ },
441
+ end: {
442
+ flexDirection: 'row',
443
+ alignItems: 'center',
444
+ justifyContent: 'flex-end',
445
+ },
446
+ expand: {
447
+ flexGrow: 1,
448
+ flexBasis: 0,
449
+ },
450
+ });