@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
@@ -0,0 +1,249 @@
1
+ import { useLocale, useTheme } from '@react-navigation/native';
2
+ import * as React from 'react';
3
+ import {
4
+ Animated,
5
+ Image,
6
+ Platform,
7
+ type StyleProp,
8
+ StyleSheet,
9
+ type TextStyle,
10
+ View,
11
+ } from 'react-native';
12
+
13
+ import backIcon from '../assets/back-icon.png';
14
+ import backIconMask from '../assets/back-icon-mask.png';
15
+ import { MaskedView } from '../MaskedView';
16
+ import type { HeaderBackButtonProps } from '../types';
17
+ import { HeaderButton } from './HeaderButton';
18
+ import { HeaderIcon, ICON_MARGIN } from './HeaderIcon';
19
+
20
+ export function HeaderBackButton({
21
+ disabled,
22
+ allowFontScaling,
23
+ backImage,
24
+ label,
25
+ labelStyle,
26
+ displayMode = Platform.OS === 'ios' ? 'default' : 'minimal',
27
+ onLabelLayout,
28
+ onPress,
29
+ pressColor,
30
+ pressOpacity,
31
+ screenLayout,
32
+ tintColor,
33
+ titleLayout,
34
+ truncatedLabel = 'Back',
35
+ accessibilityLabel = label && label !== 'Back' ? `${label}, back` : 'Go back',
36
+ testID,
37
+ style,
38
+ href,
39
+ }: HeaderBackButtonProps) {
40
+ const { colors, fonts } = useTheme();
41
+ const { direction } = useLocale();
42
+
43
+ const [labelWidth, setLabelWidth] = React.useState<number | null>(null);
44
+ const [truncatedLabelWidth, setTruncatedLabelWidth] = React.useState<
45
+ number | null
46
+ >(null);
47
+
48
+ const renderBackImage = () => {
49
+ if (backImage) {
50
+ return backImage({ tintColor: tintColor ?? colors.text });
51
+ } else {
52
+ return (
53
+ <HeaderIcon
54
+ source={backIcon}
55
+ tintColor={tintColor}
56
+ style={[
57
+ styles.icon,
58
+ displayMode !== 'minimal' && styles.iconWithLabel,
59
+ ]}
60
+ />
61
+ );
62
+ }
63
+ };
64
+
65
+ const renderLabel = () => {
66
+ if (displayMode === 'minimal') {
67
+ return null;
68
+ }
69
+
70
+ const availableSpace =
71
+ titleLayout && screenLayout
72
+ ? (screenLayout.width - titleLayout.width) / 2 -
73
+ (ICON_WIDTH + ICON_MARGIN)
74
+ : null;
75
+
76
+ const potentialLabelText =
77
+ displayMode === 'default' ? label : truncatedLabel;
78
+ const finalLabelText =
79
+ availableSpace && labelWidth && truncatedLabelWidth
80
+ ? availableSpace > labelWidth
81
+ ? potentialLabelText
82
+ : availableSpace > truncatedLabelWidth
83
+ ? truncatedLabel
84
+ : null
85
+ : potentialLabelText;
86
+
87
+ const commonStyle: Animated.WithAnimatedValue<StyleProp<TextStyle>> = [
88
+ fonts.regular,
89
+ styles.label,
90
+ labelStyle,
91
+ ];
92
+
93
+ const hiddenStyle: Animated.WithAnimatedValue<StyleProp<TextStyle>> = [
94
+ commonStyle,
95
+ {
96
+ position: 'absolute',
97
+ top: 0,
98
+ left: 0,
99
+ opacity: 0,
100
+ },
101
+ ];
102
+
103
+ const labelElement = (
104
+ <View style={styles.labelWrapper}>
105
+ {label && displayMode === 'default' ? (
106
+ <Animated.Text
107
+ style={hiddenStyle}
108
+ numberOfLines={1}
109
+ onLayout={(e) => setLabelWidth(e.nativeEvent.layout.width)}
110
+ >
111
+ {label}
112
+ </Animated.Text>
113
+ ) : null}
114
+ {truncatedLabel ? (
115
+ <Animated.Text
116
+ style={hiddenStyle}
117
+ numberOfLines={1}
118
+ onLayout={(e) => setTruncatedLabelWidth(e.nativeEvent.layout.width)}
119
+ >
120
+ {truncatedLabel}
121
+ </Animated.Text>
122
+ ) : null}
123
+ {finalLabelText ? (
124
+ <Animated.Text
125
+ accessible={false}
126
+ onLayout={onLabelLayout}
127
+ style={[tintColor ? { color: tintColor } : null, commonStyle]}
128
+ numberOfLines={1}
129
+ allowFontScaling={!!allowFontScaling}
130
+ >
131
+ {finalLabelText}
132
+ </Animated.Text>
133
+ ) : null}
134
+ </View>
135
+ );
136
+
137
+ if (backImage || Platform.OS !== 'ios') {
138
+ // When a custom backimage is specified, we can't mask the label
139
+ // Otherwise there might be weird effect due to our mask not being the same as the image
140
+ return labelElement;
141
+ }
142
+
143
+ return (
144
+ <MaskedView
145
+ maskElement={
146
+ <View
147
+ style={[
148
+ styles.iconMaskContainer,
149
+ // Extend the mask to the center of the screen so that label isn't clipped during animation
150
+ screenLayout ? { minWidth: screenLayout.width / 2 - 27 } : null,
151
+ ]}
152
+ >
153
+ <Image
154
+ source={backIconMask}
155
+ resizeMode="contain"
156
+ style={[styles.iconMask, direction === 'rtl' && styles.flip]}
157
+ />
158
+ <View style={styles.iconMaskFillerRect} />
159
+ </View>
160
+ }
161
+ >
162
+ {labelElement}
163
+ </MaskedView>
164
+ );
165
+ };
166
+
167
+ const handlePress = () => {
168
+ if (onPress) {
169
+ requestAnimationFrame(() => onPress());
170
+ }
171
+ };
172
+
173
+ return (
174
+ <HeaderButton
175
+ disabled={disabled}
176
+ href={href}
177
+ accessibilityLabel={accessibilityLabel}
178
+ testID={testID}
179
+ onPress={handlePress}
180
+ pressColor={pressColor}
181
+ pressOpacity={pressOpacity}
182
+ style={[styles.container, style]}
183
+ >
184
+ <React.Fragment>
185
+ {renderBackImage()}
186
+ {renderLabel()}
187
+ </React.Fragment>
188
+ </HeaderButton>
189
+ );
190
+ }
191
+
192
+ const ICON_WIDTH = Platform.OS === 'ios' ? 13 : 24;
193
+ const ICON_MARGIN_END = Platform.OS === 'ios' ? 22 : 3;
194
+
195
+ const styles = StyleSheet.create({
196
+ container: {
197
+ paddingHorizontal: 0,
198
+ minWidth: StyleSheet.hairlineWidth, // Avoid collapsing when title is long
199
+ ...Platform.select({
200
+ ios: null,
201
+ default: {
202
+ marginVertical: 3,
203
+ marginHorizontal: 11,
204
+ },
205
+ }),
206
+ },
207
+ label: {
208
+ fontSize: 17,
209
+ // Title and back label are a bit different width due to title being bold
210
+ // Adjusting the letterSpacing makes them coincide better
211
+ letterSpacing: 0.35,
212
+ },
213
+ labelWrapper: {
214
+ // These styles will make sure that the label doesn't fill the available space
215
+ // Otherwise it messes with the measurement of the label
216
+ flexDirection: 'row',
217
+ alignItems: 'flex-start',
218
+ marginEnd: ICON_MARGIN,
219
+ },
220
+ icon: {
221
+ width: ICON_WIDTH,
222
+ marginEnd: ICON_MARGIN_END,
223
+ },
224
+ iconWithLabel:
225
+ Platform.OS === 'ios'
226
+ ? {
227
+ marginEnd: 6,
228
+ }
229
+ : {},
230
+ iconMaskContainer: {
231
+ flex: 1,
232
+ flexDirection: 'row',
233
+ justifyContent: 'center',
234
+ },
235
+ iconMaskFillerRect: {
236
+ flex: 1,
237
+ backgroundColor: '#000',
238
+ },
239
+ iconMask: {
240
+ height: 21,
241
+ width: 13,
242
+ marginStart: -14.5,
243
+ marginVertical: 12,
244
+ alignSelf: 'center',
245
+ },
246
+ flip: {
247
+ transform: 'scaleX(-1)',
248
+ },
249
+ });
@@ -0,0 +1,5 @@
1
+ import { getNamedContext } from '../getNamedContext';
2
+
3
+ export const HeaderBackContext = getNamedContext<
4
+ { title: string | undefined; href: string | undefined } | undefined
5
+ >('HeaderBackContext', undefined);
@@ -0,0 +1,60 @@
1
+ import { useTheme } from '@react-navigation/native';
2
+ import * as React from 'react';
3
+ import {
4
+ Animated,
5
+ Platform,
6
+ type StyleProp,
7
+ StyleSheet,
8
+ type ViewProps,
9
+ type ViewStyle,
10
+ } from 'react-native';
11
+
12
+ type Props = Omit<ViewProps, 'style'> & {
13
+ style?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
14
+ children?: React.ReactNode;
15
+ };
16
+
17
+ export function HeaderBackground({ style, ...rest }: Props) {
18
+ const { colors, dark } = useTheme();
19
+
20
+ return (
21
+ <Animated.View
22
+ style={[
23
+ styles.container,
24
+ {
25
+ backgroundColor: colors.card,
26
+ borderBottomColor: colors.border,
27
+ ...(Platform.OS === 'ios' && {
28
+ shadowColor: dark
29
+ ? 'rgba(255, 255, 255, 0.45)'
30
+ : 'rgba(0, 0, 0, 1)',
31
+ }),
32
+ },
33
+ style,
34
+ ]}
35
+ {...rest}
36
+ />
37
+ );
38
+ }
39
+
40
+ const styles = StyleSheet.create({
41
+ container: {
42
+ flex: 1,
43
+ ...Platform.select({
44
+ android: {
45
+ elevation: 4,
46
+ },
47
+ ios: {
48
+ shadowOpacity: 0.3,
49
+ shadowRadius: 0,
50
+ shadowOffset: {
51
+ width: 0,
52
+ height: StyleSheet.hairlineWidth,
53
+ },
54
+ },
55
+ default: {
56
+ borderBottomWidth: StyleSheet.hairlineWidth,
57
+ },
58
+ }),
59
+ },
60
+ });
@@ -0,0 +1,55 @@
1
+ import { Platform, StyleSheet } from 'react-native';
2
+
3
+ import { PlatformPressable } from '../PlatformPressable';
4
+ import type { HeaderButtonProps } from '../types';
5
+
6
+ export function HeaderButton({
7
+ disabled,
8
+ onPress,
9
+ pressColor,
10
+ pressOpacity,
11
+ accessibilityLabel,
12
+ testID,
13
+ style,
14
+ href,
15
+ children,
16
+ }: HeaderButtonProps) {
17
+ return (
18
+ <PlatformPressable
19
+ disabled={disabled}
20
+ href={href}
21
+ accessibilityLabel={accessibilityLabel}
22
+ testID={testID}
23
+ onPress={onPress}
24
+ pressColor={pressColor}
25
+ pressOpacity={pressOpacity}
26
+ android_ripple={androidRipple}
27
+ style={[styles.container, disabled && styles.disabled, style]}
28
+ hitSlop={Platform.select({
29
+ ios: undefined,
30
+ default: { top: 16, right: 16, bottom: 16, left: 16 },
31
+ })}
32
+ >
33
+ {children}
34
+ </PlatformPressable>
35
+ );
36
+ }
37
+
38
+ const androidRipple = {
39
+ borderless: true,
40
+ foreground: Platform.OS === 'android' && Platform.Version >= 23,
41
+ radius: 20,
42
+ };
43
+
44
+ const styles = StyleSheet.create({
45
+ container: {
46
+ flexDirection: 'row',
47
+ alignItems: 'center',
48
+ paddingHorizontal: 8,
49
+ // Roundness for iPad hover effect
50
+ borderRadius: 10,
51
+ },
52
+ disabled: {
53
+ opacity: 0.5,
54
+ },
55
+ });
@@ -0,0 +1,6 @@
1
+ import { getNamedContext } from '../getNamedContext';
2
+
3
+ export const HeaderHeightContext = getNamedContext<number | undefined>(
4
+ 'HeaderHeightContext',
5
+ undefined
6
+ );
@@ -0,0 +1,32 @@
1
+ import { useLocale, useTheme } from '@react-navigation/native';
2
+ import { Image, type ImageProps, Platform, StyleSheet } from 'react-native';
3
+
4
+ export function HeaderIcon({ source, style, ...rest }: ImageProps) {
5
+ const { colors } = useTheme();
6
+ const { direction } = useLocale();
7
+
8
+ return (
9
+ <Image
10
+ source={source}
11
+ resizeMode="contain"
12
+ fadeDuration={0}
13
+ tintColor={colors.text}
14
+ style={[styles.icon, direction === 'rtl' && styles.flip, style]}
15
+ {...rest}
16
+ />
17
+ );
18
+ }
19
+
20
+ export const ICON_SIZE = Platform.OS === 'ios' ? 21 : 24;
21
+ export const ICON_MARGIN = Platform.OS === 'ios' ? 8 : 3;
22
+
23
+ const styles = StyleSheet.create({
24
+ icon: {
25
+ width: ICON_SIZE,
26
+ height: ICON_SIZE,
27
+ margin: ICON_MARGIN,
28
+ },
29
+ flip: {
30
+ transform: 'scaleX(-1)',
31
+ },
32
+ });