@momo-kits/foundation 0.169.7-beta.8 → 0.169.7-beta.9
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/Application/BottomTab/ActiveIndicator.tsx +1 -5
- package/Application/BottomTab/BottomTabBar.styles.ts +1 -18
- package/Application/BottomTab/BottomTabBar.tsx +10 -8
- package/Application/BottomTab/CurvedContainer.tsx +2 -8
- package/Application/BottomTab/CustomBottomTabItem.tsx +2 -2
- package/Application/BottomTab/DuoTabBar.tsx +3 -15
- package/Application/BottomTab/metrics.ts +3 -23
- package/Application/Components/HeaderAnimated.tsx +13 -37
- package/Application/Components/HeaderBackground.tsx +3 -16
- package/Application/Components/HeaderExtendHeader.tsx +28 -41
- package/Application/Components/HeaderLeft.tsx +18 -4
- package/Application/Components/HeaderRight.styles.ts +13 -15
- package/Application/Components/HeaderTitle.shared.ts +11 -10
- package/Application/Components/HeaderToolkitAction.tsx +37 -12
- package/Application/Components/NavigationButton.tsx +6 -9
- package/Application/Components/SearchHeader.tsx +7 -20
- package/Application/StackScreen.tsx +0 -9
- package/Application/index.ts +1 -11
- package/Application/navigationOptions.tsx +15 -6
- package/Application/types.header.ts +2 -7
- package/Application/types.tabs.ts +1 -0
- package/Application/types.ts +0 -7
- package/Input/InputSearch.tsx +2 -18
- package/Input/index.tsx +1 -7
- package/Layout/Card.tsx +10 -10
- package/Layout/Item.tsx +2 -2
- package/Layout/Screen.tsx +0 -3
- package/Layout/Section.tsx +8 -9
- package/Layout/constants.ts +19 -0
- package/Layout/screenHeader.tsx +52 -55
- package/Layout/screenTypes.ts +2 -10
- package/Layout/types.ts +37 -1
- package/Layout/useGridSystem.ts +49 -0
- package/Layout/utils.ts +0 -8
- package/package.json +1 -1
- package/Application/headerLayout.ts +0 -158
package/Layout/screenHeader.tsx
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef } from 'react';
|
|
2
2
|
import { StatusBar, StatusBarStyle } from 'react-native';
|
|
3
3
|
import { StackNavigationOptions } from '@react-navigation/stack';
|
|
4
|
-
import type { SharedValue } from 'react-native-reanimated';
|
|
5
4
|
import Navigation from '../Application/Navigation';
|
|
6
5
|
import { AnimatedHeader, SearchHeaderProps } from '../Application/types';
|
|
7
6
|
import { exportHeaderTitle } from '../Application/navigationOptions';
|
|
@@ -13,11 +12,6 @@ import {
|
|
|
13
12
|
SearchHeader,
|
|
14
13
|
} from '../Application';
|
|
15
14
|
import { DuoGlassBackground } from '../Application/Components/DuoGlassBackground';
|
|
16
|
-
import {
|
|
17
|
-
type HeaderContentLayout,
|
|
18
|
-
useHeaderFrameOptions,
|
|
19
|
-
useHeaderLayout,
|
|
20
|
-
} from '../Application/headerLayout';
|
|
21
15
|
import { getHeaderMargin } from './utils';
|
|
22
16
|
import { ANIMATED_BANNER_HEIGHT } from './screenTypes';
|
|
23
17
|
import { HeaderType } from './types';
|
|
@@ -35,31 +29,6 @@ type ScreenHeaderParams = {
|
|
|
35
29
|
gradientColor?: string;
|
|
36
30
|
headerBackground?: string;
|
|
37
31
|
layoutOffset: number;
|
|
38
|
-
contentLayout?: HeaderContentLayout;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Transparent header for an `inputSearchProps` Screen: its title fades out over the
|
|
43
|
-
* first 50pt of scroll while the search collapses into the bar.
|
|
44
|
-
*/
|
|
45
|
-
const getSearchTitleOptions = (
|
|
46
|
-
sharedValue: SharedValue<number>,
|
|
47
|
-
): StackNavigationOptions => {
|
|
48
|
-
return {
|
|
49
|
-
headerShown: true,
|
|
50
|
-
headerTransparent: true,
|
|
51
|
-
headerBackground: () => null,
|
|
52
|
-
headerTitle: (props: any) => (
|
|
53
|
-
<HeaderTitle
|
|
54
|
-
{...props}
|
|
55
|
-
interpolate={{
|
|
56
|
-
inputRange: [0, 50],
|
|
57
|
-
outputRange: [1, 0],
|
|
58
|
-
}}
|
|
59
|
-
animatedValue={sharedValue}
|
|
60
|
-
/>
|
|
61
|
-
),
|
|
62
|
-
};
|
|
63
32
|
};
|
|
64
33
|
|
|
65
34
|
/**
|
|
@@ -79,12 +48,9 @@ export const useScreenHeader = ({
|
|
|
79
48
|
gradientColor,
|
|
80
49
|
headerBackground,
|
|
81
50
|
layoutOffset,
|
|
82
|
-
contentLayout,
|
|
83
51
|
}: ScreenHeaderParams) => {
|
|
84
52
|
const currentTint = useRef<string | undefined>(undefined);
|
|
85
53
|
const appliedHeaderMode = useRef<string | undefined>(undefined);
|
|
86
|
-
const headerLayout = useHeaderLayout(contentLayout);
|
|
87
|
-
const frameOptions = useHeaderFrameOptions(contentLayout);
|
|
88
54
|
|
|
89
55
|
// keepTitle leaves a title the screen set itself when the same type is re-applied
|
|
90
56
|
const setHeaderType = useCallback(
|
|
@@ -113,7 +79,21 @@ export const useScreenHeader = ({
|
|
|
113
79
|
headerTitle: (props: any) => <HeaderTitle {...props} />,
|
|
114
80
|
};
|
|
115
81
|
if (inputSearchProps) {
|
|
116
|
-
options =
|
|
82
|
+
options = {
|
|
83
|
+
headerShown: true,
|
|
84
|
+
headerTransparent: true,
|
|
85
|
+
headerBackground: () => null,
|
|
86
|
+
headerTitle: (props: any) => (
|
|
87
|
+
<HeaderTitle
|
|
88
|
+
{...props}
|
|
89
|
+
interpolate={{
|
|
90
|
+
inputRange: [0, 50],
|
|
91
|
+
outputRange: [1, 0],
|
|
92
|
+
}}
|
|
93
|
+
animatedValue={sharedValue}
|
|
94
|
+
/>
|
|
95
|
+
),
|
|
96
|
+
};
|
|
117
97
|
}
|
|
118
98
|
break;
|
|
119
99
|
|
|
@@ -147,7 +127,21 @@ export const useScreenHeader = ({
|
|
|
147
127
|
headerTitle: (props: any) => <HeaderTitle {...props} />,
|
|
148
128
|
};
|
|
149
129
|
if (inputSearchProps) {
|
|
150
|
-
options =
|
|
130
|
+
options = {
|
|
131
|
+
headerShown: true,
|
|
132
|
+
headerTransparent: true,
|
|
133
|
+
headerBackground: () => null,
|
|
134
|
+
headerTitle: (props: any) => (
|
|
135
|
+
<HeaderTitle
|
|
136
|
+
{...props}
|
|
137
|
+
interpolate={{
|
|
138
|
+
inputRange: [0, 50],
|
|
139
|
+
outputRange: [1, 0],
|
|
140
|
+
}}
|
|
141
|
+
animatedValue={sharedValue}
|
|
142
|
+
/>
|
|
143
|
+
),
|
|
144
|
+
};
|
|
151
145
|
}
|
|
152
146
|
}
|
|
153
147
|
|
|
@@ -155,11 +149,7 @@ export const useScreenHeader = ({
|
|
|
155
149
|
delete options.headerTitle;
|
|
156
150
|
}
|
|
157
151
|
|
|
158
|
-
navigation?.instance?.setOptions({
|
|
159
|
-
header: undefined,
|
|
160
|
-
...frameOptions,
|
|
161
|
-
...options,
|
|
162
|
-
});
|
|
152
|
+
navigation?.instance?.setOptions({ header: undefined, ...options });
|
|
163
153
|
},
|
|
164
154
|
[
|
|
165
155
|
gradientColor,
|
|
@@ -170,7 +160,6 @@ export const useScreenHeader = ({
|
|
|
170
160
|
useShadowHeader,
|
|
171
161
|
hasSideBar,
|
|
172
162
|
quickReturnOptions,
|
|
173
|
-
frameOptions,
|
|
174
163
|
],
|
|
175
164
|
);
|
|
176
165
|
|
|
@@ -218,7 +207,7 @@ export const useScreenHeader = ({
|
|
|
218
207
|
};
|
|
219
208
|
}
|
|
220
209
|
|
|
221
|
-
navigation?.instance?.setOptions(
|
|
210
|
+
navigation?.instance?.setOptions(options);
|
|
222
211
|
},
|
|
223
212
|
[
|
|
224
213
|
gradientColor,
|
|
@@ -229,23 +218,32 @@ export const useScreenHeader = ({
|
|
|
229
218
|
hasSideBar,
|
|
230
219
|
layoutOffset,
|
|
231
220
|
quickReturnOptions,
|
|
232
|
-
frameOptions,
|
|
233
221
|
],
|
|
234
222
|
);
|
|
235
223
|
|
|
236
224
|
const setAnimatedSearch = useCallback(() => {
|
|
237
|
-
const options =
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
225
|
+
const options: StackNavigationOptions = {
|
|
226
|
+
headerShown: true,
|
|
227
|
+
headerTransparent: true,
|
|
228
|
+
headerBackground: () => null,
|
|
229
|
+
headerTitle: (props: any) => (
|
|
230
|
+
<HeaderTitle
|
|
231
|
+
{...props}
|
|
232
|
+
interpolate={{
|
|
233
|
+
inputRange: [0, 50],
|
|
234
|
+
outputRange: [1, 0],
|
|
235
|
+
}}
|
|
236
|
+
animatedValue={sharedValue}
|
|
237
|
+
/>
|
|
238
|
+
),
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
navigation?.instance?.setOptions({ header: undefined, ...options });
|
|
242
|
+
}, [navigation?.instance, sharedValue]);
|
|
244
243
|
|
|
245
|
-
// the search field spans the content
|
|
246
|
-
// and status bar clusters
|
|
244
|
+
// the search field spans the content, clear of the side bar and status bar clusters
|
|
247
245
|
const setSearchHeader = (params: SearchHeaderProps) => {
|
|
248
|
-
let searchWidth =
|
|
246
|
+
let searchWidth = layout.width - 24;
|
|
249
247
|
let searchLeft = Spacing.M;
|
|
250
248
|
if (layout.sideBar) {
|
|
251
249
|
searchWidth = layout.contentWidth - Spacing.M * 2;
|
|
@@ -256,7 +254,6 @@ export const useScreenHeader = ({
|
|
|
256
254
|
searchWidth -= clearance.left + clearance.right;
|
|
257
255
|
}
|
|
258
256
|
const options: StackNavigationOptions = {
|
|
259
|
-
...frameOptions,
|
|
260
257
|
headerRight: undefined,
|
|
261
258
|
headerTitleContainerStyle: {
|
|
262
259
|
width: searchWidth,
|
package/Layout/screenTypes.ts
CHANGED
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
import { FloatingButtonProps } from './FloatingButton';
|
|
10
10
|
import { HeaderType } from './types';
|
|
11
11
|
import { InputRef } from '../Input';
|
|
12
|
-
import type { HeaderContentLayout } from '../Application/headerLayout';
|
|
13
12
|
|
|
14
13
|
export const ANIMATED_BANNER_HEIGHT = 210;
|
|
15
14
|
|
|
@@ -78,17 +77,10 @@ export interface ScreenProps extends ViewProps {
|
|
|
78
77
|
layoutOffset?: -8 | -24 | -56 | number;
|
|
79
78
|
|
|
80
79
|
/**
|
|
81
|
-
* Optional. Width of the right header. Defaults to the toolkit width (
|
|
80
|
+
* Optional. Width of the right header. Defaults to the toolkit width (73), or 0 when
|
|
82
81
|
* iPhone Duo floats the toolkit into its side bar.
|
|
83
82
|
*/
|
|
84
|
-
headerRightWidth?: 0 |
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Optional. `stretch` centers back, title or search and the right cluster of the
|
|
88
|
-
* header in a 600pt frame on wide windows (foldable inner display, tablet); the
|
|
89
|
-
* background and status bar stay full width. Defaults to `grid`.
|
|
90
|
-
*/
|
|
91
|
-
contentLayout?: HeaderContentLayout;
|
|
83
|
+
headerRightWidth?: 0 | 73 | 110 | number;
|
|
92
84
|
|
|
93
85
|
/**
|
|
94
86
|
* Optional. Props for the floating action button.
|
package/Layout/types.ts
CHANGED
|
@@ -13,7 +13,43 @@ export type ScreenRef = {
|
|
|
13
13
|
*/
|
|
14
14
|
setSearchHeader: (params: SearchHeaderProps) => void;
|
|
15
15
|
};
|
|
16
|
-
export type SpanNumber =
|
|
16
|
+
export type SpanNumber =
|
|
17
|
+
| 1
|
|
18
|
+
| 2
|
|
19
|
+
| 3
|
|
20
|
+
| 4
|
|
21
|
+
| 5
|
|
22
|
+
| 6
|
|
23
|
+
| 7
|
|
24
|
+
| 8
|
|
25
|
+
| 9
|
|
26
|
+
| 10
|
|
27
|
+
| 11
|
|
28
|
+
| 12
|
|
29
|
+
| 13
|
|
30
|
+
| 14
|
|
31
|
+
| 15
|
|
32
|
+
| 16
|
|
33
|
+
| 17
|
|
34
|
+
| 18
|
|
35
|
+
| 19
|
|
36
|
+
| 20
|
|
37
|
+
| 21
|
|
38
|
+
| 22
|
|
39
|
+
| 23
|
|
40
|
+
| 24
|
|
41
|
+
| 25
|
|
42
|
+
| 26
|
|
43
|
+
| 27
|
|
44
|
+
| 28
|
|
45
|
+
| 29
|
|
46
|
+
| 30
|
|
47
|
+
| 31
|
|
48
|
+
| 32
|
|
49
|
+
| 33
|
|
50
|
+
| 34
|
|
51
|
+
| 35
|
|
52
|
+
| 36;
|
|
17
53
|
|
|
18
54
|
export type GridContextProps = {
|
|
19
55
|
/**
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GRID_DESKTOP_COLUMNS,
|
|
3
|
+
GRID_DESKTOP_MIN_WIDTH,
|
|
4
|
+
GRID_PHONE_COLUMNS,
|
|
5
|
+
GRID_PHONE_MAX_WIDTH,
|
|
6
|
+
GRID_TABLET_COLUMNS,
|
|
7
|
+
GRID_TABLET_MIN_WIDTH,
|
|
8
|
+
} from './constants';
|
|
9
|
+
import { useScreenLayout } from './utils';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Column count for a content width: 12 below 800pt, 24 below 1100pt, 36 from there
|
|
13
|
+
*/
|
|
14
|
+
const getGridColumns = (width: number) => {
|
|
15
|
+
if (width >= GRID_DESKTOP_MIN_WIDTH) {
|
|
16
|
+
return GRID_DESKTOP_COLUMNS;
|
|
17
|
+
}
|
|
18
|
+
if (width >= GRID_TABLET_MIN_WIDTH) {
|
|
19
|
+
return GRID_TABLET_COLUMNS;
|
|
20
|
+
}
|
|
21
|
+
return GRID_PHONE_COLUMNS;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Grid width for a content width: the 12-column grid stops at 600pt and is centered,
|
|
26
|
+
* the wider grids fill the content
|
|
27
|
+
*/
|
|
28
|
+
const getGridWidth = (width: number) => {
|
|
29
|
+
if (width < GRID_TABLET_MIN_WIDTH) {
|
|
30
|
+
return Math.min(width, GRID_PHONE_MAX_WIDTH);
|
|
31
|
+
}
|
|
32
|
+
return width;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Grid for the current content width: column count, grid width and the horizontal
|
|
37
|
+
* offset that centers a grid narrower than the content
|
|
38
|
+
*/
|
|
39
|
+
const useGridSystem = () => {
|
|
40
|
+
const { contentWidth } = useScreenLayout();
|
|
41
|
+
const gridWidth = getGridWidth(contentWidth);
|
|
42
|
+
return {
|
|
43
|
+
numberOfColumns: getGridColumns(contentWidth),
|
|
44
|
+
gridWidth,
|
|
45
|
+
gridOffset: (contentWidth - gridWidth) / 2,
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export { useGridSystem };
|
package/Layout/utils.ts
CHANGED
|
@@ -357,13 +357,6 @@ const useSideBarItemStyle = (
|
|
|
357
357
|
};
|
|
358
358
|
};
|
|
359
359
|
|
|
360
|
-
/** Column count of the content grid: 24 on content wider than 600pt, otherwise 12. */
|
|
361
|
-
const useGridSystem = () => {
|
|
362
|
-
const { contentWidth } = useScreenLayout();
|
|
363
|
-
const numberOfColumns = contentWidth > 600 ? 24 : 12;
|
|
364
|
-
return { numberOfColumns };
|
|
365
|
-
};
|
|
366
|
-
|
|
367
360
|
export type { ScreenLayout, SideBarEdge, SideBarLayout, StatusBarClearance };
|
|
368
361
|
|
|
369
362
|
export {
|
|
@@ -372,7 +365,6 @@ export {
|
|
|
372
365
|
InnerEdgeStyles,
|
|
373
366
|
getHeaderMargin,
|
|
374
367
|
getHeaderRowOptions,
|
|
375
|
-
useGridSystem,
|
|
376
368
|
useScreenLayout,
|
|
377
369
|
useSideBarItemStyle,
|
|
378
370
|
validateChildren,
|
package/package.json
CHANGED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
2
|
-
import { useWindowDimensions, type ViewStyle } from 'react-native';
|
|
3
|
-
import type { StackNavigationOptions } from '@react-navigation/stack';
|
|
4
|
-
import { Spacing } from '../Consts';
|
|
5
|
-
import { getHeaderMargin } from '../Layout/utils';
|
|
6
|
-
import { FOLDABLE_MIN_WIDTH } from './modalLayout';
|
|
7
|
-
import { isIPhoneDuo } from './utils';
|
|
8
|
-
|
|
9
|
-
// Top navigation spec, shared with the Compose / SwiftUI kits
|
|
10
|
-
const HEADER_FRAME_MAX_WIDTH = 600;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Top navigation geometry on every device
|
|
14
|
-
* - buttonSize / iconSize: round back and shortcut buttons, icons inside them and the pill
|
|
15
|
-
* - pillWidth / pillHeight: help center | home capsule
|
|
16
|
-
* - clusterWidth: shortcut, gap and pill on the right of the bar
|
|
17
|
-
* - searchHeight: search field inside the header
|
|
18
|
-
* - titleGap: space between back and the title, and the title and the right cluster
|
|
19
|
-
* - sidePadding: bar edge to back and to the right cluster
|
|
20
|
-
* - gradientHeight: header gradient, kept at the phone height on wide windows
|
|
21
|
-
* - bannerWidth: animated banner image, kept at the phone width on wide windows
|
|
22
|
-
*/
|
|
23
|
-
const HeaderBarMetrics = {
|
|
24
|
-
buttonSize: 32,
|
|
25
|
-
iconSize: 20,
|
|
26
|
-
pillWidth: 72,
|
|
27
|
-
pillHeight: 32,
|
|
28
|
-
clusterWidth: 112,
|
|
29
|
-
searchHeight: 32,
|
|
30
|
-
titleGap: Spacing.S,
|
|
31
|
-
sidePadding: Spacing.M,
|
|
32
|
-
gradientHeight: 154,
|
|
33
|
-
bannerWidth: 375,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* `grid` keeps the header row at the bar edges, `stretch` centers it in a 600pt
|
|
38
|
-
* frame on wide windows. Background and status bar always span the window.
|
|
39
|
-
*/
|
|
40
|
-
type HeaderContentLayout = 'grid' | 'stretch';
|
|
41
|
-
|
|
42
|
-
type HeaderLayout = typeof HeaderBarMetrics & {
|
|
43
|
-
/**
|
|
44
|
-
* Window whose short side is at least 600 (Galaxy Z Fold / Pixel Fold inner
|
|
45
|
-
* display, tablets), iPhone Duo excluded. Phones, landscape included, are not.
|
|
46
|
-
*/
|
|
47
|
-
isWide: boolean;
|
|
48
|
-
/**
|
|
49
|
-
* Window edge to back and to the right cluster: `sidePadding`, or centering the
|
|
50
|
-
* row in the 600pt frame with `stretch` on a wide window.
|
|
51
|
-
*/
|
|
52
|
-
frameInset: number;
|
|
53
|
-
/**
|
|
54
|
-
* Header row width between the two `frameInset`s.
|
|
55
|
-
*/
|
|
56
|
-
frameWidth: number;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
type HeaderLayoutInput = {
|
|
60
|
-
width: number;
|
|
61
|
-
height: number;
|
|
62
|
-
isDuo: boolean;
|
|
63
|
-
contentLayout?: HeaderContentLayout;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Header geometry for a window, pure so it can be tested without a device.
|
|
68
|
-
*/
|
|
69
|
-
const getHeaderLayout = ({
|
|
70
|
-
width,
|
|
71
|
-
height,
|
|
72
|
-
isDuo,
|
|
73
|
-
contentLayout = 'grid',
|
|
74
|
-
}: HeaderLayoutInput): HeaderLayout => {
|
|
75
|
-
const { sidePadding } = HeaderBarMetrics;
|
|
76
|
-
const isWide = !isDuo && Math.min(width, height) >= FOLDABLE_MIN_WIDTH;
|
|
77
|
-
let frameInset = sidePadding;
|
|
78
|
-
if (isWide && contentLayout === 'stretch') {
|
|
79
|
-
const centered = (width - HEADER_FRAME_MAX_WIDTH) / 2;
|
|
80
|
-
frameInset = Math.max(sidePadding, centered);
|
|
81
|
-
}
|
|
82
|
-
return {
|
|
83
|
-
...HeaderBarMetrics,
|
|
84
|
-
isWide,
|
|
85
|
-
frameInset,
|
|
86
|
-
frameWidth: width - frameInset * 2,
|
|
87
|
-
};
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Widest a title can be between back and the right cluster of the header row.
|
|
92
|
-
*/
|
|
93
|
-
const getTitleBudget = (layout: HeaderLayout) => {
|
|
94
|
-
const { buttonSize, titleGap, clusterWidth } = layout;
|
|
95
|
-
return layout.frameWidth - buttonSize - titleGap * 2 - clusterWidth;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Header geometry for the current window; follows fold, unfold and rotation.
|
|
100
|
-
*/
|
|
101
|
-
const useHeaderLayout = (contentLayout?: HeaderContentLayout): HeaderLayout => {
|
|
102
|
-
const { width, height } = useWindowDimensions();
|
|
103
|
-
const isDuo = isIPhoneDuo();
|
|
104
|
-
return useMemo(() => {
|
|
105
|
-
return getHeaderLayout({ width, height, isDuo, contentLayout });
|
|
106
|
-
}, [width, height, isDuo, contentLayout]);
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
const TITLE_CONTAINER_RESET: ViewStyle = {
|
|
110
|
-
marginLeft: 0,
|
|
111
|
-
marginEnd: 0,
|
|
112
|
-
marginStart: 0,
|
|
113
|
-
marginHorizontal: 0,
|
|
114
|
-
marginVertical: 0,
|
|
115
|
-
margin: 0,
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* React Navigation container styles that keep back, title and the right cluster
|
|
120
|
-
* in the `stretch` frame. `undefined` for `grid`, and on iPhone Duo, which keeps
|
|
121
|
-
* its own header row.
|
|
122
|
-
*/
|
|
123
|
-
const useHeaderFrameOptions = (
|
|
124
|
-
contentLayout?: HeaderContentLayout,
|
|
125
|
-
): StackNavigationOptions | undefined => {
|
|
126
|
-
const layout = useHeaderLayout(contentLayout);
|
|
127
|
-
const { width } = useWindowDimensions();
|
|
128
|
-
const isDuo = isIPhoneDuo();
|
|
129
|
-
return useMemo(() => {
|
|
130
|
-
if (contentLayout !== 'stretch' || isDuo) {
|
|
131
|
-
return undefined;
|
|
132
|
-
}
|
|
133
|
-
// the header content row already sits this far in on large iOS windows
|
|
134
|
-
const shift = layout.frameInset - layout.sidePadding;
|
|
135
|
-
const containerShift = Math.max(0, shift - getHeaderMargin(width));
|
|
136
|
-
return {
|
|
137
|
-
headerLeftContainerStyle: { paddingLeft: containerShift },
|
|
138
|
-
headerRightContainerStyle: { paddingRight: containerShift },
|
|
139
|
-
headerTitleContainerStyle: {
|
|
140
|
-
...TITLE_CONTAINER_RESET,
|
|
141
|
-
left: layout.titleGap,
|
|
142
|
-
maxWidth: getTitleBudget(layout),
|
|
143
|
-
},
|
|
144
|
-
};
|
|
145
|
-
}, [contentLayout, isDuo, layout, width]);
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
export type { HeaderContentLayout, HeaderLayout };
|
|
149
|
-
|
|
150
|
-
export {
|
|
151
|
-
HeaderBarMetrics,
|
|
152
|
-
HEADER_FRAME_MAX_WIDTH,
|
|
153
|
-
TITLE_CONTAINER_RESET,
|
|
154
|
-
getHeaderLayout,
|
|
155
|
-
getTitleBudget,
|
|
156
|
-
useHeaderLayout,
|
|
157
|
-
useHeaderFrameOptions,
|
|
158
|
-
};
|