@react-navigation/elements 2.9.5 → 3.0.0-alpha.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.
- package/lib/module/Badge.js +2 -2
- package/lib/module/Badge.js.map +1 -1
- package/lib/module/BlurEffectBackground.js +59 -0
- package/lib/module/BlurEffectBackground.js.map +1 -0
- package/lib/module/Button.js +7 -6
- package/lib/module/Button.js.map +1 -1
- package/lib/module/Color.js +11 -0
- package/lib/module/Color.js.map +1 -0
- package/lib/module/Container.js +42 -0
- package/lib/module/Container.js.map +1 -0
- package/lib/module/Header/Header.js +156 -97
- package/lib/module/Header/Header.js.map +1 -1
- package/lib/module/Header/HeaderBackButton.js +130 -121
- package/lib/module/Header/HeaderBackButton.js.map +1 -1
- package/lib/module/Header/HeaderBackground.js +10 -17
- package/lib/module/Header/HeaderBackground.js.map +1 -1
- package/lib/module/Header/HeaderButton.js +6 -2
- package/lib/module/Header/HeaderButton.js.map +1 -1
- package/lib/module/Header/HeaderButtonBackground.js +34 -0
- package/lib/module/Header/HeaderButtonBackground.js.map +1 -0
- package/lib/module/Header/HeaderSearchBar.js +174 -123
- package/lib/module/Header/HeaderSearchBar.js.map +1 -1
- package/lib/module/Header/HeaderTitle.js.map +1 -1
- package/lib/module/Header/getDefaultHeaderHeight.js +22 -10
- package/lib/module/Header/getDefaultHeaderHeight.js.map +1 -1
- package/lib/module/Label/Label.js.map +1 -1
- package/lib/module/LiquidGlassView.ios.js +21 -0
- package/lib/module/LiquidGlassView.ios.js.map +1 -0
- package/lib/module/LiquidGlassView.js +13 -0
- package/lib/module/LiquidGlassView.js.map +1 -0
- package/lib/module/MissingIcon.js +1 -0
- package/lib/module/MissingIcon.js.map +1 -1
- package/lib/module/PlatformColor.js +9 -0
- package/lib/module/PlatformColor.js.map +1 -0
- package/lib/module/PlatformColor.native.js +4 -0
- package/lib/module/PlatformColor.native.js.map +1 -0
- package/lib/module/PlatformPressable.js.map +1 -1
- package/lib/module/Screen.js +29 -23
- package/lib/module/Screen.js.map +1 -1
- package/lib/module/assets/back-icon.ios.svg +4 -0
- package/lib/module/assets/back-icon@1x.ios.png +0 -0
- package/lib/module/assets/back-icon@2x.ios.png +0 -0
- package/lib/module/assets/back-icon@3x.ios.png +0 -0
- package/lib/module/assets/back-icon@4x.ios.png +0 -0
- package/lib/module/assets/search-icon-legacy.png +0 -0
- package/lib/module/assets/search-icon-legacy@1x.ios.png +0 -0
- package/lib/module/assets/search-icon-legacy@2x.ios.png +0 -0
- package/lib/module/assets/search-icon-legacy@3x.ios.png +0 -0
- package/lib/module/assets/search-icon-legacy@4x.ios.png +0 -0
- package/lib/module/assets/search-icon.ios.svg +4 -0
- package/lib/module/assets/search-icon@1x.ios.png +0 -0
- package/lib/module/assets/search-icon@2x.ios.png +0 -0
- package/lib/module/assets/search-icon@3x.ios.png +0 -0
- package/lib/module/assets/search-icon@4x.ios.png +0 -0
- package/lib/module/getBlurBackgroundColor.js +48 -0
- package/lib/module/getBlurBackgroundColor.js.map +1 -0
- package/lib/module/index.js +2 -8
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal.js +10 -0
- package/lib/module/internal.js.map +1 -0
- package/lib/module/useFrameSize.js +4 -4
- package/lib/module/useFrameSize.js.map +1 -1
- package/lib/typescript/src/Badge.d.ts.map +1 -1
- package/lib/typescript/src/BlurEffectBackground.d.ts +16 -0
- package/lib/typescript/src/BlurEffectBackground.d.ts.map +1 -0
- package/lib/typescript/src/Button.d.ts +5 -4
- package/lib/typescript/src/Button.d.ts.map +1 -1
- package/lib/typescript/src/Color.d.ts +13 -0
- package/lib/typescript/src/Color.d.ts.map +1 -0
- package/lib/typescript/src/Container.d.ts +8 -0
- package/lib/typescript/src/Container.d.ts.map +1 -0
- package/lib/typescript/src/Header/Header.d.ts +1 -5
- package/lib/typescript/src/Header/Header.d.ts.map +1 -1
- package/lib/typescript/src/Header/HeaderBackButton.d.ts +1 -1
- package/lib/typescript/src/Header/HeaderBackButton.d.ts.map +1 -1
- package/lib/typescript/src/Header/HeaderBackground.d.ts +5 -3
- package/lib/typescript/src/Header/HeaderBackground.d.ts.map +1 -1
- package/lib/typescript/src/Header/HeaderButton.d.ts +2 -0
- package/lib/typescript/src/Header/HeaderButton.d.ts.map +1 -1
- package/lib/typescript/src/Header/HeaderButtonBackground.d.ts +7 -0
- package/lib/typescript/src/Header/HeaderButtonBackground.d.ts.map +1 -0
- package/lib/typescript/src/Header/HeaderSearchBar.d.ts +5 -2
- package/lib/typescript/src/Header/HeaderSearchBar.d.ts.map +1 -1
- package/lib/typescript/src/Header/HeaderTitle.d.ts +2 -2
- package/lib/typescript/src/Header/HeaderTitle.d.ts.map +1 -1
- package/lib/typescript/src/Header/getDefaultHeaderHeight.d.ts +5 -2
- package/lib/typescript/src/Header/getDefaultHeaderHeight.d.ts.map +1 -1
- package/lib/typescript/src/Label/Label.d.ts +2 -2
- package/lib/typescript/src/Label/Label.d.ts.map +1 -1
- package/lib/typescript/src/LiquidGlassView.d.ts +9 -0
- package/lib/typescript/src/LiquidGlassView.d.ts.map +1 -0
- package/lib/typescript/src/LiquidGlassView.ios.d.ts +5 -0
- package/lib/typescript/src/LiquidGlassView.ios.d.ts.map +1 -0
- package/lib/typescript/src/MissingIcon.d.ts +2 -2
- package/lib/typescript/src/MissingIcon.d.ts.map +1 -1
- package/lib/typescript/src/PlatformColor.d.ts +7 -0
- package/lib/typescript/src/PlatformColor.d.ts.map +1 -0
- package/lib/typescript/src/PlatformColor.native.d.ts +2 -0
- package/lib/typescript/src/PlatformColor.native.d.ts.map +1 -0
- package/lib/typescript/src/PlatformPressable.d.ts +3 -3
- package/lib/typescript/src/PlatformPressable.d.ts.map +1 -1
- package/lib/typescript/src/Screen.d.ts.map +1 -1
- package/lib/typescript/src/getBlurBackgroundColor.d.ts +7 -0
- package/lib/typescript/src/getBlurBackgroundColor.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +0 -6
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/internal.d.ts +8 -0
- package/lib/typescript/src/internal.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +47 -31
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +19 -17
- package/src/Badge.tsx +3 -2
- package/src/BlurEffectBackground.tsx +90 -0
- package/src/Button.tsx +33 -21
- package/src/Color.tsx +21 -0
- package/src/Container.tsx +44 -0
- package/src/Header/Header.tsx +230 -156
- package/src/Header/HeaderBackButton.tsx +194 -168
- package/src/Header/HeaderBackground.tsx +17 -19
- package/src/Header/HeaderButton.tsx +7 -2
- package/src/Header/HeaderButtonBackground.tsx +35 -0
- package/src/Header/HeaderSearchBar.tsx +227 -129
- package/src/Header/HeaderTitle.tsx +2 -1
- package/src/Header/getDefaultHeaderHeight.tsx +29 -18
- package/src/Label/Label.tsx +2 -1
- package/src/LiquidGlassView.ios.tsx +39 -0
- package/src/LiquidGlassView.tsx +20 -0
- package/src/MissingIcon.tsx +12 -3
- package/src/PlatformColor.native.tsx +1 -0
- package/src/PlatformColor.tsx +8 -0
- package/src/PlatformPressable.tsx +2 -1
- package/src/Screen.tsx +24 -25
- package/src/assets/back-icon.ios.svg +4 -0
- package/src/assets/back-icon@1x.ios.png +0 -0
- package/src/assets/back-icon@2x.ios.png +0 -0
- package/src/assets/back-icon@3x.ios.png +0 -0
- package/src/assets/back-icon@4x.ios.png +0 -0
- package/src/assets/search-icon-legacy.png +0 -0
- package/src/assets/search-icon-legacy@1x.ios.png +0 -0
- package/src/assets/search-icon-legacy@2x.ios.png +0 -0
- package/src/assets/search-icon-legacy@3x.ios.png +0 -0
- package/src/assets/search-icon-legacy@4x.ios.png +0 -0
- package/src/assets/search-icon.ios.svg +4 -0
- package/src/assets/search-icon@1x.ios.png +0 -0
- package/src/assets/search-icon@2x.ios.png +0 -0
- package/src/assets/search-icon@3x.ios.png +0 -0
- package/src/assets/search-icon@4x.ios.png +0 -0
- package/src/getBlurBackgroundColor.tsx +68 -0
- package/src/index.tsx +2 -8
- package/src/internal.tsx +7 -0
- package/src/types.tsx +50 -32
- package/src/useFrameSize.tsx +4 -4
- package/lib/module/Background.js +0 -22
- package/lib/module/Background.js.map +0 -1
- package/lib/module/MaskedView.android.js +0 -4
- package/lib/module/MaskedView.android.js.map +0 -1
- package/lib/module/MaskedView.ios.js +0 -4
- package/lib/module/MaskedView.ios.js.map +0 -1
- package/lib/module/MaskedView.js +0 -12
- package/lib/module/MaskedView.js.map +0 -1
- package/lib/module/MaskedViewNative.js +0 -30
- package/lib/module/MaskedViewNative.js.map +0 -1
- package/lib/module/ResourceSavingView.js +0 -57
- package/lib/module/ResourceSavingView.js.map +0 -1
- package/lib/module/assets/back-icon-mask.png +0 -0
- package/lib/typescript/src/Background.d.ts +0 -9
- package/lib/typescript/src/Background.d.ts.map +0 -1
- package/lib/typescript/src/MaskedView.android.d.ts +0 -2
- package/lib/typescript/src/MaskedView.android.d.ts.map +0 -1
- package/lib/typescript/src/MaskedView.d.ts +0 -11
- package/lib/typescript/src/MaskedView.d.ts.map +0 -1
- package/lib/typescript/src/MaskedView.ios.d.ts +0 -2
- package/lib/typescript/src/MaskedView.ios.d.ts.map +0 -1
- package/lib/typescript/src/MaskedViewNative.d.ts +0 -11
- package/lib/typescript/src/MaskedViewNative.d.ts.map +0 -1
- package/lib/typescript/src/ResourceSavingView.d.ts +0 -10
- package/lib/typescript/src/ResourceSavingView.d.ts.map +0 -1
- package/src/Background.tsx +0 -24
- package/src/MaskedView.android.tsx +0 -1
- package/src/MaskedView.ios.tsx +0 -1
- package/src/MaskedView.tsx +0 -13
- package/src/MaskedViewNative.tsx +0 -33
- package/src/ResourceSavingView.tsx +0 -76
- package/src/assets/back-icon-mask.png +0 -0
|
@@ -1,30 +1,43 @@
|
|
|
1
1
|
import { useNavigation, useTheme } from '@react-navigation/native';
|
|
2
|
-
import Color from 'color';
|
|
3
2
|
import * as React from 'react';
|
|
4
3
|
import {
|
|
5
4
|
Animated,
|
|
5
|
+
BackHandler,
|
|
6
|
+
type ColorValue,
|
|
6
7
|
Image,
|
|
8
|
+
type NativeEventSubscription,
|
|
7
9
|
Platform,
|
|
8
10
|
type StyleProp,
|
|
9
11
|
StyleSheet,
|
|
10
12
|
TextInput,
|
|
11
|
-
|
|
13
|
+
type TextStyle,
|
|
12
14
|
type ViewStyle,
|
|
13
15
|
} from 'react-native';
|
|
14
16
|
|
|
15
17
|
import clearIcon from '../assets/clear-icon.png';
|
|
16
18
|
import closeIcon from '../assets/close-icon.png';
|
|
17
19
|
import searchIcon from '../assets/search-icon.png';
|
|
20
|
+
import searchIconLegacy from '../assets/search-icon-legacy.png';
|
|
21
|
+
import { Color } from '../Color';
|
|
22
|
+
import {
|
|
23
|
+
AnimatedLiquidGlassContainerView,
|
|
24
|
+
isLiquidGlassSupported,
|
|
25
|
+
} from '../LiquidGlassView';
|
|
18
26
|
import { PlatformPressable } from '../PlatformPressable';
|
|
19
27
|
import { Text } from '../Text';
|
|
20
28
|
import type { HeaderSearchBarOptions, HeaderSearchBarRef } from '../types';
|
|
21
|
-
import {
|
|
29
|
+
import { HeaderBackButton } from './HeaderBackButton';
|
|
30
|
+
import { BUTTON_SIZE, BUTTON_SPACING, HeaderButton } from './HeaderButton';
|
|
31
|
+
import { HeaderButtonBackground } from './HeaderButtonBackground';
|
|
22
32
|
import { HeaderIcon } from './HeaderIcon';
|
|
23
33
|
|
|
24
34
|
type Props = Omit<HeaderSearchBarOptions, 'ref'> & {
|
|
25
35
|
visible: boolean;
|
|
26
36
|
onClose: () => void;
|
|
27
|
-
tintColor?:
|
|
37
|
+
tintColor?: ColorValue;
|
|
38
|
+
pressColor?: ColorValue;
|
|
39
|
+
pressOpacity?: number;
|
|
40
|
+
statusBarHeight: number;
|
|
28
41
|
style?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
|
|
29
42
|
};
|
|
30
43
|
|
|
@@ -44,11 +57,14 @@ function HeaderSearchBarInternal(
|
|
|
44
57
|
autoFocus = true,
|
|
45
58
|
autoCapitalize,
|
|
46
59
|
placeholder = 'Search',
|
|
47
|
-
cancelButtonText = 'Cancel',
|
|
48
60
|
enterKeyHint = 'search',
|
|
49
|
-
|
|
61
|
+
cancelButtonText = 'Cancel',
|
|
62
|
+
onChange,
|
|
50
63
|
onClose,
|
|
51
64
|
tintColor,
|
|
65
|
+
pressColor,
|
|
66
|
+
pressOpacity,
|
|
67
|
+
statusBarHeight,
|
|
52
68
|
style,
|
|
53
69
|
...rest
|
|
54
70
|
}: Props,
|
|
@@ -57,38 +73,11 @@ function HeaderSearchBarInternal(
|
|
|
57
73
|
const navigation = useNavigation();
|
|
58
74
|
const { dark, colors, fonts } = useTheme();
|
|
59
75
|
const [value, setValue] = React.useState('');
|
|
60
|
-
const [rendered, setRendered] = React.useState(visible);
|
|
61
|
-
const [visibleAnim] = React.useState(
|
|
62
|
-
() => new Animated.Value(visible ? 1 : 0)
|
|
63
|
-
);
|
|
64
76
|
const [clearVisibleAnim] = React.useState(() => new Animated.Value(0));
|
|
65
77
|
|
|
66
|
-
const visibleValueRef = React.useRef(visible);
|
|
67
78
|
const clearVisibleValueRef = React.useRef(false);
|
|
68
79
|
const inputRef = React.useRef<TextInput>(null);
|
|
69
80
|
|
|
70
|
-
React.useEffect(() => {
|
|
71
|
-
// Avoid act warning in tests just by rendering header
|
|
72
|
-
if (visible === visibleValueRef.current) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
Animated.timing(visibleAnim, {
|
|
77
|
-
toValue: visible ? 1 : 0,
|
|
78
|
-
duration: 100,
|
|
79
|
-
useNativeDriver,
|
|
80
|
-
}).start(({ finished }) => {
|
|
81
|
-
if (finished) {
|
|
82
|
-
setRendered(visible);
|
|
83
|
-
visibleValueRef.current = visible;
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
return () => {
|
|
88
|
-
visibleAnim.stopAnimation();
|
|
89
|
-
};
|
|
90
|
-
}, [visible, visibleAnim]);
|
|
91
|
-
|
|
92
81
|
const hasText = value !== '';
|
|
93
82
|
|
|
94
83
|
React.useEffect(() => {
|
|
@@ -117,18 +106,49 @@ function HeaderSearchBarInternal(
|
|
|
117
106
|
clearText();
|
|
118
107
|
// FIXME: figure out how to create a SyntheticEvent
|
|
119
108
|
// @ts-expect-error: we don't have the native event here
|
|
120
|
-
|
|
121
|
-
}, [clearText,
|
|
109
|
+
onChange?.({ nativeEvent: { text: '' } });
|
|
110
|
+
}, [clearText, onChange]);
|
|
122
111
|
|
|
123
112
|
const cancelSearch = React.useCallback(() => {
|
|
124
|
-
|
|
113
|
+
// FIXME: figure out how to create a SyntheticEvent
|
|
114
|
+
// @ts-expect-error: we don't have the native event here
|
|
115
|
+
onChange?.({ nativeEvent: { text: '' } });
|
|
125
116
|
onClose();
|
|
126
|
-
|
|
117
|
+
setValue('');
|
|
118
|
+
}, [onChange, onClose]);
|
|
127
119
|
|
|
128
|
-
React.useEffect(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
120
|
+
React.useEffect(() => {
|
|
121
|
+
const unsubscribeBlur = navigation?.addListener('blur', cancelSearch);
|
|
122
|
+
|
|
123
|
+
const onKeyup = (e: KeyboardEvent) => {
|
|
124
|
+
if (e.key === 'Escape') {
|
|
125
|
+
cancelSearch();
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
let backHandlerSubscription: NativeEventSubscription | undefined;
|
|
130
|
+
|
|
131
|
+
if (Platform.OS === 'web') {
|
|
132
|
+
document?.body?.addEventListener?.('keyup', onKeyup);
|
|
133
|
+
} else {
|
|
134
|
+
backHandlerSubscription = BackHandler.addEventListener(
|
|
135
|
+
'hardwareBackPress',
|
|
136
|
+
() => {
|
|
137
|
+
cancelSearch();
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return () => {
|
|
144
|
+
unsubscribeBlur();
|
|
145
|
+
backHandlerSubscription?.remove();
|
|
146
|
+
|
|
147
|
+
if (Platform.OS === 'web') {
|
|
148
|
+
document?.body?.removeEventListener?.('keyup', onKeyup);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}, [cancelSearch, navigation]);
|
|
132
152
|
|
|
133
153
|
React.useImperativeHandle(
|
|
134
154
|
ref,
|
|
@@ -149,29 +169,60 @@ function HeaderSearchBarInternal(
|
|
|
149
169
|
[cancelSearch, clearText]
|
|
150
170
|
);
|
|
151
171
|
|
|
152
|
-
if (!visible && !rendered) {
|
|
153
|
-
return null;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
172
|
const textColor = tintColor ?? colors.text;
|
|
157
173
|
|
|
174
|
+
// When status bar height is provided, add spacing below it
|
|
175
|
+
// Otherwise, use a smaller top margin to align with the header content
|
|
176
|
+
const STATUS_BAR_TOP_ADJUSTMENT = 2;
|
|
177
|
+
const topMargin = Platform.select({
|
|
178
|
+
ios: statusBarHeight
|
|
179
|
+
? statusBarHeight + BUTTON_SPACING
|
|
180
|
+
: BUTTON_SPACING - STATUS_BAR_TOP_ADJUSTMENT,
|
|
181
|
+
default: statusBarHeight,
|
|
182
|
+
});
|
|
183
|
+
|
|
158
184
|
return (
|
|
159
|
-
<
|
|
160
|
-
|
|
185
|
+
<AnimatedLiquidGlassContainerView
|
|
186
|
+
spacing={BUTTON_SPACING}
|
|
161
187
|
aria-live="polite"
|
|
162
188
|
aria-hidden={!visible}
|
|
163
|
-
style={[
|
|
189
|
+
style={[
|
|
190
|
+
styles.container,
|
|
191
|
+
Platform.OS === 'ios' && {
|
|
192
|
+
gap: BUTTON_SPACING,
|
|
193
|
+
margin: BUTTON_SPACING,
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
marginTop: topMargin,
|
|
197
|
+
},
|
|
198
|
+
style,
|
|
199
|
+
]}
|
|
164
200
|
>
|
|
165
|
-
|
|
166
|
-
<
|
|
167
|
-
|
|
168
|
-
tintColor={
|
|
169
|
-
|
|
201
|
+
{Platform.OS !== 'ios' ? (
|
|
202
|
+
<HeaderBackButton
|
|
203
|
+
accessibilityLabel={cancelButtonText}
|
|
204
|
+
tintColor={tintColor ?? colors.text}
|
|
205
|
+
pressColor={pressColor}
|
|
206
|
+
pressOpacity={pressOpacity}
|
|
207
|
+
onPress={cancelSearch}
|
|
208
|
+
style={styles.backButton}
|
|
170
209
|
/>
|
|
210
|
+
) : null}
|
|
211
|
+
<HeaderButtonBackground style={styles.searchbarContainer}>
|
|
212
|
+
{Platform.OS === 'ios' ? (
|
|
213
|
+
<HeaderIcon
|
|
214
|
+
source={isLiquidGlassSupported ? searchIcon : searchIconLegacy}
|
|
215
|
+
tintColor={textColor}
|
|
216
|
+
style={[
|
|
217
|
+
styles.inputSearchIconIos,
|
|
218
|
+
!isLiquidGlassSupported && styles.inputSearchIconIosLegacy,
|
|
219
|
+
]}
|
|
220
|
+
/>
|
|
221
|
+
) : null}
|
|
171
222
|
<TextInput
|
|
172
223
|
{...rest}
|
|
173
224
|
ref={inputRef}
|
|
174
|
-
onChange={
|
|
225
|
+
onChange={onChange}
|
|
175
226
|
onChangeText={setValue}
|
|
176
227
|
autoFocus={autoFocus}
|
|
177
228
|
autoCapitalize={
|
|
@@ -180,144 +231,191 @@ function HeaderSearchBarInternal(
|
|
|
180
231
|
inputMode={INPUT_TYPE_TO_MODE[inputType ?? 'text']}
|
|
181
232
|
enterKeyHint={enterKeyHint}
|
|
182
233
|
placeholder={placeholder}
|
|
183
|
-
placeholderTextColor={Color(textColor)
|
|
234
|
+
placeholderTextColor={Color(textColor)?.alpha(0.5).string()}
|
|
184
235
|
cursorColor={colors.primary}
|
|
185
236
|
selectionHandleColor={colors.primary}
|
|
186
|
-
selectionColor={Color(colors.primary)
|
|
237
|
+
selectionColor={Color(colors.primary)?.alpha(0.3).string()}
|
|
187
238
|
style={[
|
|
188
|
-
|
|
239
|
+
Platform.select({
|
|
240
|
+
ios: isLiquidGlassSupported ? fonts.medium : fonts.regular,
|
|
241
|
+
default: fonts.regular,
|
|
242
|
+
}),
|
|
189
243
|
styles.searchbar,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
},
|
|
244
|
+
Platform.OS === 'ios' &&
|
|
245
|
+
!isLiquidGlassSupported && {
|
|
246
|
+
backgroundColor: dark
|
|
247
|
+
? 'rgba(255, 255, 255, 0.1)'
|
|
248
|
+
: 'rgba(0, 0, 0, 0.1)',
|
|
249
|
+
},
|
|
250
|
+
{ color: textColor },
|
|
198
251
|
]}
|
|
199
252
|
/>
|
|
200
253
|
{Platform.OS === 'ios' ? (
|
|
201
254
|
<PlatformPressable
|
|
255
|
+
accessibilityLabel="Clear"
|
|
202
256
|
onPress={onClear}
|
|
203
257
|
style={[
|
|
204
258
|
{
|
|
205
259
|
opacity: clearVisibleAnim,
|
|
206
260
|
transform: [{ scale: clearVisibleAnim }],
|
|
207
261
|
},
|
|
208
|
-
styles.
|
|
262
|
+
styles.clearButtonIos,
|
|
263
|
+
!isLiquidGlassSupported && styles.clearButtonIosLegacy,
|
|
209
264
|
]}
|
|
210
265
|
>
|
|
211
266
|
<Image
|
|
212
267
|
source={clearIcon}
|
|
213
268
|
resizeMode="contain"
|
|
214
269
|
tintColor={textColor}
|
|
215
|
-
style={styles.
|
|
270
|
+
style={styles.clearIconIos}
|
|
216
271
|
/>
|
|
217
272
|
</PlatformPressable>
|
|
218
273
|
) : null}
|
|
219
|
-
</
|
|
274
|
+
</HeaderButtonBackground>
|
|
220
275
|
{Platform.OS !== 'ios' ? (
|
|
221
276
|
<HeaderButton
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
} else {
|
|
226
|
-
onClose();
|
|
227
|
-
}
|
|
228
|
-
}}
|
|
229
|
-
style={styles.closeButton}
|
|
277
|
+
accessibilityLabel="Clear"
|
|
278
|
+
onPress={onClear}
|
|
279
|
+
style={[styles.closeButton, { opacity: clearVisibleAnim }]}
|
|
230
280
|
>
|
|
231
281
|
<HeaderIcon source={closeIcon} tintColor={textColor} />
|
|
232
282
|
</HeaderButton>
|
|
233
283
|
) : null}
|
|
234
284
|
{Platform.OS === 'ios' ? (
|
|
235
|
-
|
|
236
|
-
<
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
{
|
|
240
|
-
|
|
241
|
-
|
|
285
|
+
isLiquidGlassSupported ? (
|
|
286
|
+
<HeaderButtonBackground style={styles.closeButtonContainerIos}>
|
|
287
|
+
<HeaderButton
|
|
288
|
+
accessibilityLabel={cancelButtonText}
|
|
289
|
+
onPress={cancelSearch}
|
|
290
|
+
>
|
|
291
|
+
<HeaderIcon source={closeIcon} tintColor={textColor} />
|
|
292
|
+
</HeaderButton>
|
|
293
|
+
</HeaderButtonBackground>
|
|
294
|
+
) : (
|
|
295
|
+
<PlatformPressable
|
|
296
|
+
accessibilityLabel={cancelButtonText}
|
|
297
|
+
onPress={cancelSearch}
|
|
298
|
+
style={styles.cancelButton}
|
|
242
299
|
>
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
300
|
+
<Text
|
|
301
|
+
style={[
|
|
302
|
+
fonts.regular,
|
|
303
|
+
{ color: tintColor ?? colors.primary },
|
|
304
|
+
styles.cancelText,
|
|
305
|
+
]}
|
|
306
|
+
>
|
|
307
|
+
{cancelButtonText}
|
|
308
|
+
</Text>
|
|
309
|
+
</PlatformPressable>
|
|
310
|
+
)
|
|
246
311
|
) : null}
|
|
247
|
-
</
|
|
312
|
+
</AnimatedLiquidGlassContainerView>
|
|
248
313
|
);
|
|
249
314
|
}
|
|
250
315
|
|
|
316
|
+
const SEARCH_ICON_SIZE = 18;
|
|
317
|
+
const CLEAR_ICON_SIZE = 16;
|
|
318
|
+
const CANCEL_FONT_SIZE = 17;
|
|
319
|
+
const SEARCHBAR_FONT_SIZE = Platform.OS === 'ios' ? 17 : 18;
|
|
320
|
+
|
|
321
|
+
const SEARCHBAR_ICON_SPACING = 5;
|
|
322
|
+
const SEARCHBAR_HEIGHT_IOS = isLiquidGlassSupported ? BUTTON_SIZE : 36;
|
|
323
|
+
|
|
324
|
+
// The top inset on iOS is a bit less than the status bar height
|
|
325
|
+
const SEARCHBAR_LEGACY_VERTICAL_OFFSET_IOS = -4;
|
|
326
|
+
|
|
251
327
|
const styles = StyleSheet.create({
|
|
252
328
|
container: {
|
|
253
329
|
flex: 1,
|
|
254
330
|
flexDirection: 'row',
|
|
255
331
|
alignItems: 'stretch',
|
|
256
332
|
},
|
|
257
|
-
|
|
333
|
+
inputSearchIconIos: {
|
|
258
334
|
position: 'absolute',
|
|
259
335
|
opacity: 0.5,
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
336
|
+
top: SEARCHBAR_ICON_SPACING,
|
|
337
|
+
left: SEARCHBAR_ICON_SPACING,
|
|
338
|
+
height: SEARCH_ICON_SIZE,
|
|
339
|
+
width: SEARCH_ICON_SIZE,
|
|
340
|
+
},
|
|
341
|
+
inputSearchIconIosLegacy: {
|
|
342
|
+
top: SEARCHBAR_LEGACY_VERTICAL_OFFSET_IOS,
|
|
343
|
+
},
|
|
344
|
+
backButton: {
|
|
345
|
+
alignSelf: 'center',
|
|
346
|
+
marginLeft: BUTTON_SPACING / 2,
|
|
269
347
|
},
|
|
270
348
|
closeButton: {
|
|
271
349
|
position: 'absolute',
|
|
272
350
|
opacity: 0.5,
|
|
273
|
-
right:
|
|
274
|
-
|
|
351
|
+
right: BUTTON_SPACING,
|
|
352
|
+
height: '100%',
|
|
353
|
+
},
|
|
354
|
+
closeButtonContainerIos: {
|
|
355
|
+
alignSelf: 'center',
|
|
275
356
|
},
|
|
276
|
-
|
|
357
|
+
clearButtonIos: {
|
|
277
358
|
position: 'absolute',
|
|
278
359
|
right: 0,
|
|
279
|
-
top:
|
|
360
|
+
top: 0,
|
|
280
361
|
bottom: 0,
|
|
362
|
+
width: SEARCHBAR_HEIGHT_IOS,
|
|
281
363
|
justifyContent: 'center',
|
|
282
|
-
|
|
364
|
+
alignItems: 'center',
|
|
283
365
|
},
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
366
|
+
clearButtonIosLegacy: {
|
|
367
|
+
top: SEARCHBAR_LEGACY_VERTICAL_OFFSET_IOS - SEARCHBAR_ICON_SPACING,
|
|
368
|
+
},
|
|
369
|
+
clearIconIos: {
|
|
370
|
+
height: CLEAR_ICON_SIZE,
|
|
371
|
+
width: CLEAR_ICON_SIZE,
|
|
287
372
|
opacity: 0.5,
|
|
288
373
|
},
|
|
289
374
|
cancelButton: {
|
|
290
375
|
alignSelf: 'center',
|
|
291
|
-
top: -4,
|
|
292
376
|
},
|
|
293
377
|
cancelText: {
|
|
294
|
-
fontSize:
|
|
295
|
-
|
|
378
|
+
fontSize: CANCEL_FONT_SIZE,
|
|
379
|
+
marginRight: BUTTON_SPACING / 2,
|
|
296
380
|
},
|
|
297
381
|
searchbarContainer: {
|
|
298
382
|
flex: 1,
|
|
383
|
+
flexDirection: 'row',
|
|
384
|
+
alignItems: 'stretch',
|
|
385
|
+
...Platform.select<ViewStyle>({
|
|
386
|
+
ios: isLiquidGlassSupported
|
|
387
|
+
? {}
|
|
388
|
+
: {
|
|
389
|
+
minHeight: SEARCHBAR_HEIGHT_IOS,
|
|
390
|
+
},
|
|
391
|
+
default: {
|
|
392
|
+
borderRadius: 0,
|
|
393
|
+
},
|
|
394
|
+
}),
|
|
395
|
+
},
|
|
396
|
+
searchbar: {
|
|
397
|
+
flex: 1,
|
|
398
|
+
backgroundColor: 'transparent',
|
|
399
|
+
fontSize: SEARCHBAR_FONT_SIZE,
|
|
400
|
+
...Platform.select<TextStyle>({
|
|
401
|
+
ios: {
|
|
402
|
+
paddingHorizontal:
|
|
403
|
+
BUTTON_SPACING + SEARCH_ICON_SIZE + SEARCHBAR_ICON_SPACING * 2,
|
|
404
|
+
...(!isLiquidGlassSupported
|
|
405
|
+
? {
|
|
406
|
+
marginTop: SEARCHBAR_LEGACY_VERTICAL_OFFSET_IOS,
|
|
407
|
+
marginBottom: SEARCHBAR_ICON_SPACING,
|
|
408
|
+
borderRadius: BUTTON_SPACING,
|
|
409
|
+
borderCurve: 'continuous',
|
|
410
|
+
}
|
|
411
|
+
: null),
|
|
412
|
+
},
|
|
413
|
+
default: {
|
|
414
|
+
paddingLeft: BUTTON_SPACING,
|
|
415
|
+
paddingRight: BUTTON_SIZE + BUTTON_SPACING,
|
|
416
|
+
},
|
|
417
|
+
}),
|
|
299
418
|
},
|
|
300
|
-
searchbar: Platform.select({
|
|
301
|
-
ios: {
|
|
302
|
-
flex: 1,
|
|
303
|
-
fontSize: 17,
|
|
304
|
-
paddingHorizontal: 32,
|
|
305
|
-
marginLeft: 16,
|
|
306
|
-
marginTop: -1,
|
|
307
|
-
marginBottom: 4,
|
|
308
|
-
borderRadius: 8,
|
|
309
|
-
borderCurve: 'continuous',
|
|
310
|
-
},
|
|
311
|
-
default: {
|
|
312
|
-
flex: 1,
|
|
313
|
-
fontSize: 18,
|
|
314
|
-
paddingHorizontal: 36,
|
|
315
|
-
marginRight: 8,
|
|
316
|
-
marginTop: 8,
|
|
317
|
-
marginBottom: 8,
|
|
318
|
-
borderBottomWidth: 1,
|
|
319
|
-
},
|
|
320
|
-
}),
|
|
321
419
|
});
|
|
322
420
|
|
|
323
421
|
export const HeaderSearchBar = React.forwardRef(HeaderSearchBarInternal);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useTheme } from '@react-navigation/native';
|
|
2
2
|
import {
|
|
3
3
|
Animated,
|
|
4
|
+
type ColorValue,
|
|
4
5
|
Platform,
|
|
5
6
|
type StyleProp,
|
|
6
7
|
StyleSheet,
|
|
@@ -9,7 +10,7 @@ import {
|
|
|
9
10
|
} from 'react-native';
|
|
10
11
|
|
|
11
12
|
type Props = Omit<TextProps, 'style'> & {
|
|
12
|
-
tintColor?:
|
|
13
|
+
tintColor?: ColorValue;
|
|
13
14
|
children?: string;
|
|
14
15
|
style?: Animated.WithAnimatedValue<StyleProp<TextStyle>>;
|
|
15
16
|
};
|
|
@@ -1,35 +1,46 @@
|
|
|
1
1
|
import { PixelRatio, Platform } from 'react-native';
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import { isLiquidGlassSupported } from '../LiquidGlassView';
|
|
4
4
|
|
|
5
|
-
export function getDefaultHeaderHeight(
|
|
6
|
-
|
|
7
|
-
modalPresentation
|
|
8
|
-
topInset
|
|
9
|
-
|
|
5
|
+
export function getDefaultHeaderHeight({
|
|
6
|
+
landscape,
|
|
7
|
+
modalPresentation,
|
|
8
|
+
topInset,
|
|
9
|
+
}: {
|
|
10
|
+
landscape: boolean;
|
|
11
|
+
modalPresentation: boolean;
|
|
12
|
+
topInset: number;
|
|
13
|
+
}): number {
|
|
10
14
|
let headerHeight;
|
|
11
15
|
|
|
12
16
|
// On models with Dynamic Island the status bar height is smaller than the safe area top inset.
|
|
13
17
|
const hasDynamicIsland = Platform.OS === 'ios' && topInset > 50;
|
|
14
|
-
const statusBarHeight =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const isLandscape = layout.width > layout.height;
|
|
18
|
+
const statusBarHeight = Math.max(
|
|
19
|
+
topInset - (hasDynamicIsland ? 5 + 1 / PixelRatio.get() : 0),
|
|
20
|
+
0
|
|
21
|
+
);
|
|
19
22
|
|
|
20
23
|
if (Platform.OS === 'ios') {
|
|
21
|
-
if (
|
|
22
|
-
if (modalPresentation) {
|
|
23
|
-
headerHeight =
|
|
24
|
+
if (isLiquidGlassSupported) {
|
|
25
|
+
if (modalPresentation && !Platform.isPad && !Platform.isTV) {
|
|
26
|
+
headerHeight = 70;
|
|
24
27
|
} else {
|
|
25
|
-
|
|
28
|
+
if (hasDynamicIsland) {
|
|
29
|
+
headerHeight = 60;
|
|
30
|
+
} else {
|
|
31
|
+
headerHeight = 64;
|
|
32
|
+
}
|
|
26
33
|
}
|
|
27
34
|
} else {
|
|
28
|
-
if (
|
|
29
|
-
headerHeight = 32;
|
|
30
|
-
} else {
|
|
35
|
+
if (Platform.isPad || Platform.isTV) {
|
|
31
36
|
if (modalPresentation) {
|
|
32
37
|
headerHeight = 56;
|
|
38
|
+
} else {
|
|
39
|
+
headerHeight = 50;
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
if (modalPresentation && !landscape) {
|
|
43
|
+
headerHeight = 56;
|
|
33
44
|
} else {
|
|
34
45
|
headerHeight = 44;
|
|
35
46
|
}
|
package/src/Label/Label.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type ColorValue,
|
|
2
3
|
type StyleProp,
|
|
3
4
|
StyleSheet,
|
|
4
5
|
type TextProps,
|
|
@@ -8,7 +9,7 @@ import {
|
|
|
8
9
|
import { Text } from '../Text';
|
|
9
10
|
|
|
10
11
|
type Props = Omit<TextProps, 'style'> & {
|
|
11
|
-
tintColor?:
|
|
12
|
+
tintColor?: ColorValue;
|
|
12
13
|
children?: string;
|
|
13
14
|
style?: StyleProp<TextStyle>;
|
|
14
15
|
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Animated, View } from 'react-native';
|
|
2
|
+
|
|
3
|
+
type CallstackLiquidGlass = typeof import('@callstack/liquid-glass');
|
|
4
|
+
|
|
5
|
+
let isLiquidGlassSupported: boolean,
|
|
6
|
+
LiquidGlassView: CallstackLiquidGlass['LiquidGlassView'],
|
|
7
|
+
LiquidGlassContainerView: CallstackLiquidGlass['LiquidGlassContainerView'],
|
|
8
|
+
AnimatedLiquidGlassView: Animated.AnimatedComponent<typeof LiquidGlassView>,
|
|
9
|
+
AnimatedLiquidGlassContainerView: Animated.AnimatedComponent<
|
|
10
|
+
typeof LiquidGlassContainerView
|
|
11
|
+
>;
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
// Add try/catch to support usage even if it's not installed, since it's optional.
|
|
15
|
+
isLiquidGlassSupported =
|
|
16
|
+
require('@callstack/liquid-glass').isLiquidGlassSupported;
|
|
17
|
+
LiquidGlassView = require('@callstack/liquid-glass').LiquidGlassView;
|
|
18
|
+
LiquidGlassContainerView =
|
|
19
|
+
require('@callstack/liquid-glass').LiquidGlassContainerView;
|
|
20
|
+
AnimatedLiquidGlassView = Animated.createAnimatedComponent(LiquidGlassView);
|
|
21
|
+
AnimatedLiquidGlassContainerView = Animated.createAnimatedComponent(
|
|
22
|
+
LiquidGlassContainerView
|
|
23
|
+
);
|
|
24
|
+
} catch (e) {
|
|
25
|
+
isLiquidGlassSupported = false;
|
|
26
|
+
LiquidGlassView = View;
|
|
27
|
+
// @ts-expect-error: this is fine
|
|
28
|
+
AnimatedLiquidGlassView = Animated.View;
|
|
29
|
+
// @ts-expect-error: this is fine
|
|
30
|
+
AnimatedLiquidGlassContainerView = Animated.View;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
AnimatedLiquidGlassContainerView,
|
|
35
|
+
AnimatedLiquidGlassView,
|
|
36
|
+
isLiquidGlassSupported,
|
|
37
|
+
LiquidGlassContainerView,
|
|
38
|
+
LiquidGlassView,
|
|
39
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Animated, View } from 'react-native';
|
|
2
|
+
|
|
3
|
+
type CallstackLiquidGlass = typeof import('@callstack/liquid-glass');
|
|
4
|
+
|
|
5
|
+
export const LiquidGlassView: CallstackLiquidGlass['LiquidGlassView'] = View;
|
|
6
|
+
|
|
7
|
+
export const LiquidGlassContainerView: CallstackLiquidGlass['LiquidGlassContainerView'] =
|
|
8
|
+
View;
|
|
9
|
+
|
|
10
|
+
// @ts-expect-error: this is fine
|
|
11
|
+
export const AnimatedLiquidGlassView: Animated.AnimatedComponent<
|
|
12
|
+
typeof LiquidGlassView
|
|
13
|
+
> = Animated.View;
|
|
14
|
+
|
|
15
|
+
// @ts-expect-error: this is fine
|
|
16
|
+
export const AnimatedLiquidGlassContainerView: Animated.AnimatedComponent<
|
|
17
|
+
typeof LiquidGlassContainerView
|
|
18
|
+
> = Animated.View;
|
|
19
|
+
|
|
20
|
+
export const isLiquidGlassSupported = false;
|
package/src/MissingIcon.tsx
CHANGED
|
@@ -1,15 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type ColorValue,
|
|
3
|
+
type StyleProp,
|
|
4
|
+
StyleSheet,
|
|
5
|
+
type TextStyle,
|
|
6
|
+
} from 'react-native';
|
|
2
7
|
|
|
3
8
|
import { Text } from './Text';
|
|
4
9
|
|
|
5
10
|
type Props = {
|
|
6
|
-
color?:
|
|
11
|
+
color?: ColorValue;
|
|
7
12
|
size?: number;
|
|
8
13
|
style?: StyleProp<TextStyle>;
|
|
9
14
|
};
|
|
10
15
|
|
|
11
16
|
export function MissingIcon({ color, size, style }: Props) {
|
|
12
|
-
return
|
|
17
|
+
return (
|
|
18
|
+
<Text aria-hidden style={[styles.icon, { color, fontSize: size }, style]}>
|
|
19
|
+
⏷
|
|
20
|
+
</Text>
|
|
21
|
+
);
|
|
13
22
|
}
|
|
14
23
|
|
|
15
24
|
const styles = StyleSheet.create({
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PlatformColor } from 'react-native';
|