@react-navigation/elements 2.0.0-rc.18 → 2.0.0-rc.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/Header/Header.js +4 -8
- package/lib/commonjs/Header/Header.js.map +1 -1
- package/lib/commonjs/Header/HeaderBackButton.js +43 -38
- package/lib/commonjs/Header/HeaderBackButton.js.map +1 -1
- package/lib/module/Header/Header.js +4 -8
- package/lib/module/Header/Header.js.map +1 -1
- package/lib/module/Header/HeaderBackButton.js +43 -38
- package/lib/module/Header/HeaderBackButton.js.map +1 -1
- package/lib/typescript/commonjs/src/Header/Header.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/Header/HeaderBackButton.d.ts +1 -1
- package/lib/typescript/commonjs/src/Header/HeaderBackButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/types.d.ts +12 -4
- package/lib/typescript/commonjs/src/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/tsconfig.build.tsbuildinfo +1 -1
- package/lib/typescript/module/src/Header/Header.d.ts.map +1 -1
- package/lib/typescript/module/src/Header/HeaderBackButton.d.ts +1 -1
- package/lib/typescript/module/src/Header/HeaderBackButton.d.ts.map +1 -1
- package/lib/typescript/module/src/types.d.ts +12 -4
- package/lib/typescript/module/src/types.d.ts.map +1 -1
- package/lib/typescript/module/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/Header/Header.tsx +4 -8
- package/src/Header/HeaderBackButton.tsx +84 -61
- package/src/types.tsx +13 -4
|
@@ -3,9 +3,10 @@ import * as React from 'react';
|
|
|
3
3
|
import {
|
|
4
4
|
Animated,
|
|
5
5
|
Image,
|
|
6
|
-
type LayoutChangeEvent,
|
|
7
6
|
Platform,
|
|
7
|
+
type StyleProp,
|
|
8
8
|
StyleSheet,
|
|
9
|
+
type TextStyle,
|
|
9
10
|
View,
|
|
10
11
|
} from 'react-native';
|
|
11
12
|
|
|
@@ -21,7 +22,7 @@ export function HeaderBackButton({
|
|
|
21
22
|
backImage,
|
|
22
23
|
label,
|
|
23
24
|
labelStyle,
|
|
24
|
-
|
|
25
|
+
displayMode = Platform.OS === 'ios' ? 'default' : 'minimal',
|
|
25
26
|
onLabelLayout,
|
|
26
27
|
onPress,
|
|
27
28
|
pressColor,
|
|
@@ -38,29 +39,10 @@ export function HeaderBackButton({
|
|
|
38
39
|
const { colors, fonts } = useTheme();
|
|
39
40
|
const { direction } = useLocale();
|
|
40
41
|
|
|
41
|
-
const [
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const handleLabelLayout = (e: LayoutChangeEvent) => {
|
|
46
|
-
onLabelLayout?.(e);
|
|
47
|
-
|
|
48
|
-
const { layout } = e.nativeEvent;
|
|
49
|
-
|
|
50
|
-
setInitialLabelWidth(
|
|
51
|
-
(direction === 'rtl' ? layout.y : layout.x) + layout.width
|
|
52
|
-
);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const shouldTruncateLabel = () => {
|
|
56
|
-
return (
|
|
57
|
-
!label ||
|
|
58
|
-
(initialLabelWidth &&
|
|
59
|
-
titleLayout &&
|
|
60
|
-
screenLayout &&
|
|
61
|
-
(screenLayout.width - titleLayout.width) / 2 < initialLabelWidth + 26)
|
|
62
|
-
);
|
|
63
|
-
};
|
|
42
|
+
const [labelWidth, setLabelWidth] = React.useState<number | null>(null);
|
|
43
|
+
const [truncatedLabelWidth, setTruncatedLabelWidth] = React.useState<
|
|
44
|
+
number | null
|
|
45
|
+
>(null);
|
|
64
46
|
|
|
65
47
|
const renderBackImage = () => {
|
|
66
48
|
if (backImage) {
|
|
@@ -71,7 +53,7 @@ export function HeaderBackButton({
|
|
|
71
53
|
style={[
|
|
72
54
|
styles.icon,
|
|
73
55
|
direction === 'rtl' && styles.flip,
|
|
74
|
-
|
|
56
|
+
displayMode !== 'minimal' && styles.iconWithLabel,
|
|
75
57
|
Boolean(tintColor) && { tintColor },
|
|
76
58
|
]}
|
|
77
59
|
resizeMode="contain"
|
|
@@ -83,32 +65,74 @@ export function HeaderBackButton({
|
|
|
83
65
|
};
|
|
84
66
|
|
|
85
67
|
const renderLabel = () => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (!labelVisible || leftLabelText === undefined) {
|
|
68
|
+
if (displayMode === 'minimal') {
|
|
89
69
|
return null;
|
|
90
70
|
}
|
|
91
71
|
|
|
72
|
+
const availableSpace =
|
|
73
|
+
titleLayout && screenLayout
|
|
74
|
+
? (screenLayout.width - titleLayout.width) / 2 -
|
|
75
|
+
(ICON_WIDTH + ICON_MARGIN_START)
|
|
76
|
+
: null;
|
|
77
|
+
|
|
78
|
+
const potentialLabelText =
|
|
79
|
+
displayMode === 'default' ? label : truncatedLabel;
|
|
80
|
+
const finalLabelText =
|
|
81
|
+
availableSpace && labelWidth && truncatedLabelWidth
|
|
82
|
+
? availableSpace > labelWidth
|
|
83
|
+
? potentialLabelText
|
|
84
|
+
: availableSpace > truncatedLabelWidth
|
|
85
|
+
? truncatedLabel
|
|
86
|
+
: null
|
|
87
|
+
: potentialLabelText;
|
|
88
|
+
|
|
89
|
+
const commonStyle: Animated.WithAnimatedValue<StyleProp<TextStyle>> = [
|
|
90
|
+
fonts.regular,
|
|
91
|
+
styles.label,
|
|
92
|
+
labelStyle,
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
const hiddenStyle: Animated.WithAnimatedValue<StyleProp<TextStyle>> = [
|
|
96
|
+
commonStyle,
|
|
97
|
+
{
|
|
98
|
+
position: 'absolute',
|
|
99
|
+
top: 0,
|
|
100
|
+
left: 0,
|
|
101
|
+
opacity: 0,
|
|
102
|
+
},
|
|
103
|
+
];
|
|
104
|
+
|
|
92
105
|
const labelElement = (
|
|
93
106
|
<View style={styles.labelWrapper}>
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
107
|
+
{label && displayMode === 'default' ? (
|
|
108
|
+
<Animated.Text
|
|
109
|
+
style={hiddenStyle}
|
|
110
|
+
numberOfLines={1}
|
|
111
|
+
onLayout={(e) => setLabelWidth(e.nativeEvent.layout.width)}
|
|
112
|
+
>
|
|
113
|
+
{label}
|
|
114
|
+
</Animated.Text>
|
|
115
|
+
) : null}
|
|
116
|
+
{truncatedLabel ? (
|
|
117
|
+
<Animated.Text
|
|
118
|
+
style={hiddenStyle}
|
|
119
|
+
numberOfLines={1}
|
|
120
|
+
onLayout={(e) => setTruncatedLabelWidth(e.nativeEvent.layout.width)}
|
|
121
|
+
>
|
|
122
|
+
{truncatedLabel}
|
|
123
|
+
</Animated.Text>
|
|
124
|
+
) : null}
|
|
125
|
+
{finalLabelText ? (
|
|
126
|
+
<Animated.Text
|
|
127
|
+
accessible={false}
|
|
128
|
+
onLayout={onLabelLayout}
|
|
129
|
+
style={[tintColor ? { color: tintColor } : null, commonStyle]}
|
|
130
|
+
numberOfLines={1}
|
|
131
|
+
allowFontScaling={!!allowFontScaling}
|
|
132
|
+
>
|
|
133
|
+
{finalLabelText}
|
|
134
|
+
</Animated.Text>
|
|
135
|
+
) : null}
|
|
112
136
|
</View>
|
|
113
137
|
);
|
|
114
138
|
|
|
@@ -167,6 +191,12 @@ export function HeaderBackButton({
|
|
|
167
191
|
);
|
|
168
192
|
}
|
|
169
193
|
|
|
194
|
+
const ICON_WIDTH = Platform.OS === 'ios' ? 13 : 24;
|
|
195
|
+
const ICON_HEIGHT = Platform.OS === 'ios' ? 21 : 24;
|
|
196
|
+
const ICON_MARGIN_START = Platform.OS === 'ios' ? 8 : 3;
|
|
197
|
+
const ICON_MARGIN_END = Platform.OS === 'ios' ? 22 : 3;
|
|
198
|
+
const ICON_MARGIN_VERTICAL = Platform.OS === 'ios' ? 8 : 3;
|
|
199
|
+
|
|
170
200
|
const styles = StyleSheet.create({
|
|
171
201
|
container: {
|
|
172
202
|
paddingHorizontal: 0,
|
|
@@ -195,20 +225,13 @@ const styles = StyleSheet.create({
|
|
|
195
225
|
default: { marginEnd: 3 },
|
|
196
226
|
}),
|
|
197
227
|
},
|
|
198
|
-
icon:
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
},
|
|
206
|
-
default: {
|
|
207
|
-
height: 24,
|
|
208
|
-
width: 24,
|
|
209
|
-
margin: 3,
|
|
210
|
-
},
|
|
211
|
-
}),
|
|
228
|
+
icon: {
|
|
229
|
+
height: ICON_HEIGHT,
|
|
230
|
+
width: ICON_WIDTH,
|
|
231
|
+
marginStart: ICON_MARGIN_START,
|
|
232
|
+
marginEnd: ICON_MARGIN_END,
|
|
233
|
+
marginVertical: ICON_MARGIN_VERTICAL,
|
|
234
|
+
},
|
|
212
235
|
iconWithLabel:
|
|
213
236
|
Platform.OS === 'ios'
|
|
214
237
|
? {
|
package/src/types.tsx
CHANGED
|
@@ -6,6 +6,8 @@ import type {
|
|
|
6
6
|
ViewStyle,
|
|
7
7
|
} from 'react-native';
|
|
8
8
|
|
|
9
|
+
export type HeaderBackButtonDisplayMode = 'default' | 'generic' | 'minimal';
|
|
10
|
+
|
|
9
11
|
export type Layout = { width: number; height: number };
|
|
10
12
|
|
|
11
13
|
export type HeaderOptions = {
|
|
@@ -41,13 +43,20 @@ export type HeaderOptions = {
|
|
|
41
43
|
tintColor?: string;
|
|
42
44
|
pressColor?: string;
|
|
43
45
|
pressOpacity?: number;
|
|
44
|
-
|
|
46
|
+
displayMode?: HeaderBackButtonDisplayMode;
|
|
45
47
|
href?: undefined;
|
|
46
48
|
}) => React.ReactNode;
|
|
47
49
|
/**
|
|
48
|
-
*
|
|
50
|
+
* How the back button displays icon and title.
|
|
51
|
+
*
|
|
52
|
+
* Supported values:
|
|
53
|
+
* - "default" - Displays one of the following depending on the available space: previous screen's title, truncated title (e.g. 'Back') or no title (only icon).
|
|
54
|
+
* - "generic" – Displays one of the following depending on the available space: truncated title (e.g. 'Back') or no title (only icon).
|
|
55
|
+
* - "minimal" – Always displays only the icon without a title.
|
|
56
|
+
*
|
|
57
|
+
* Defaults to "default" on iOS, and "minimal" on Android.
|
|
49
58
|
*/
|
|
50
|
-
|
|
59
|
+
headerBackButtonDisplayMode?: HeaderBackButtonDisplayMode;
|
|
51
60
|
/**
|
|
52
61
|
* Style object for the container of the `headerLeft` element`.
|
|
53
62
|
*/
|
|
@@ -209,7 +218,7 @@ export type HeaderBackButtonProps = Omit<HeaderButtonProps, 'children'> & {
|
|
|
209
218
|
* Whether the label text is visible.
|
|
210
219
|
* Defaults to `true` on iOS and `false` on Android.
|
|
211
220
|
*/
|
|
212
|
-
|
|
221
|
+
displayMode?: HeaderBackButtonDisplayMode;
|
|
213
222
|
/**
|
|
214
223
|
* Style object for the label.
|
|
215
224
|
*/
|