@momo-kits/foundation 0.168.1-beta.37 → 0.168.1-beta.39
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/BottomSheet.hooks.ts +8 -8
- package/Application/BottomSheet.parts.tsx +44 -34
- package/Application/BottomSheet.tsx +35 -26
- package/Application/BottomTab/ActiveIndicator.tsx +15 -14
- package/Application/BottomTab/BottomTabBar.tsx +49 -62
- package/Application/BottomTab/BottomTabInset.tsx +8 -4
- package/Application/BottomTab/CurvedContainer.tsx +14 -12
- package/Application/BottomTab/CustomBottomTabItem.tsx +13 -13
- package/Application/BottomTab/DuoBarCompression.tsx +13 -19
- package/Application/BottomTab/DuoRailTabBar.tsx +20 -24
- package/Application/BottomTab/DuoTabBar.tsx +8 -10
- package/Application/BottomTab/TabBarIcon.tsx +15 -29
- package/Application/BottomTab/TabScreen.tsx +1 -5
- package/Application/BottomTab/index.tsx +33 -30
- package/Application/BottomTab/metrics.ts +23 -23
- package/Application/BottomTab/tabItems.ts +1 -1
- package/Application/BottomTab/usePressLift.ts +2 -2
- package/Application/Components/BackgroundImageView.tsx +4 -0
- package/Application/Components/DuoGlassBackground.tsx +5 -4
- package/Application/Components/HeaderAnimated.tsx +40 -12
- package/Application/Components/HeaderBackground.tsx +19 -2
- package/Application/Components/HeaderExtendHeader.tsx +51 -37
- package/Application/Components/HeaderLeft.tsx +5 -18
- package/Application/Components/HeaderRight.styles.ts +15 -13
- package/Application/Components/HeaderRight.tsx +2 -1
- package/Application/Components/HeaderTitle.shared.ts +17 -16
- package/Application/Components/HeaderTitle.tsx +4 -3
- package/Application/Components/HeaderToolkitAction.tsx +29 -57
- package/Application/Components/NavigationButton.tsx +10 -6
- package/Application/Components/SearchHeader.tsx +37 -17
- package/Application/Components/TitleJourney.tsx +2 -2
- package/Application/Components/TitleLocation.tsx +2 -2
- package/Application/Components/TitleUser.tsx +2 -2
- package/Application/Components/useToolkitActions.tsx +17 -32
- package/Application/Localize.ts +7 -0
- package/Application/ModalScreen.tsx +9 -3
- package/Application/Navigation.ts +14 -16
- package/Application/NavigationContainer.tsx +19 -16
- package/Application/Navigator.ts +20 -48
- package/Application/ScaleSizeProvider.tsx +13 -6
- package/Application/StackScreen.tracking.ts +11 -26
- package/Application/StackScreen.tsx +17 -35
- package/Application/TooltipPortal.tsx +12 -5
- package/Application/WidgetContainer.tsx +10 -4
- package/Application/headerLayout.ts +158 -0
- package/Application/index.ts +11 -1
- package/Application/modalLayout.ts +13 -14
- package/Application/navigationOptions.tsx +27 -32
- package/Application/types.header.ts +7 -2
- package/Application/types.ts +7 -0
- package/Badge/Badge.tsx +5 -0
- package/Badge/BadgeDot.tsx +1 -0
- package/Badge/BadgeDotAnimation.tsx +15 -7
- package/Badge/BadgeRibbon.tsx +46 -38
- package/Badge/Shape.tsx +2 -0
- package/Badge/types.ts +2 -2
- package/Button/index.tsx +5 -16
- package/Button/utils.ts +9 -15
- package/CheckBox/index.tsx +4 -0
- package/Consts/theme.ts +10 -10
- package/Context/index.ts +5 -1
- package/Divider/DashDivider.tsx +1 -0
- package/Divider/index.tsx +4 -0
- package/FoundationList/index.tsx +4 -0
- package/Icon/index.tsx +6 -6
- package/Icon/types.ts +1 -1
- package/IconButton/index.tsx +4 -12
- package/Image/index.tsx +9 -7
- package/Input/Input.tsx +8 -9
- package/Input/InputDropDown.tsx +10 -12
- package/Input/InputMoney.tsx +12 -8
- package/Input/InputMoneyView.tsx +14 -7
- package/Input/InputOTP.tsx +35 -33
- package/Input/InputPhoneNumber.tsx +8 -9
- package/Input/InputSearch.tsx +22 -8
- package/Input/InputTextArea.tsx +4 -0
- package/Input/SearchTextTyping.tsx +4 -0
- package/Input/SystemTextInput.tsx +7 -2
- package/Input/TextTyping.tsx +4 -0
- package/Input/common.tsx +26 -12
- package/Input/index.tsx +24 -21
- package/Input/moneyUtils.ts +10 -4
- package/Input/styles.ts +0 -5
- package/Input/utils.ts +14 -12
- package/Layout/Card.tsx +7 -4
- package/Layout/FloatingButton.tsx +4 -0
- package/Layout/Item.tsx +6 -2
- package/Layout/ItemList.tsx +9 -7
- package/Layout/ItemSectionList.tsx +2 -1
- package/Layout/ReservedRegions.tsx +25 -25
- package/Layout/Screen.tsx +59 -58
- package/Layout/Section.tsx +8 -5
- package/Layout/TrackingScope.tsx +1 -0
- package/Layout/screenContent.tsx +4 -2
- package/Layout/screenFooter.tsx +28 -18
- package/Layout/screenHeader.tsx +88 -82
- package/Layout/screenQuickReturn.tsx +17 -20
- package/Layout/screenScroll.ts +4 -7
- package/Layout/screenTypes.ts +13 -4
- package/Layout/types.ts +2 -4
- package/Layout/utils.ts +31 -37
- package/Loader/DotLoader.tsx +4 -0
- package/Loader/Loader.tsx +4 -0
- package/Loader/ProgressBar.tsx +1 -0
- package/Loader/Spinner.tsx +4 -0
- package/Loader/utils.ts +11 -7
- package/Pagination/Dot.tsx +4 -0
- package/Pagination/PaginationDot.tsx +1 -0
- package/Pagination/PaginationNumber.tsx +5 -3
- package/Pagination/PaginationScroll.tsx +5 -0
- package/Pagination/PaginationWhiteDot.tsx +1 -0
- package/Pagination/index.tsx +4 -0
- package/Pagination/types.ts +2 -2
- package/Popup/PopupNotify.tsx +44 -48
- package/Popup/PopupPromotion.tsx +4 -7
- package/Popup/types.ts +4 -4
- package/Popup/utils.ts +4 -0
- package/Radio/index.tsx +4 -0
- package/Skeleton/index.tsx +8 -0
- package/Switch/index.tsx +1 -0
- package/Tag/index.tsx +5 -1
- package/Tag/types.ts +3 -3
- package/Text/index.tsx +14 -3
- package/Text/styles.ts +1 -1
- package/Text/types.ts +1 -6
- package/Text/utils.ts +20 -4
- package/Title/index.tsx +41 -32
- package/ViewBoundary/index.tsx +4 -2
- package/index.ts +0 -6
- package/package.json +37 -37
- package/Application/__tests__/modalLayout.test.ts +0 -128
package/Layout/Screen.tsx
CHANGED
|
@@ -37,6 +37,10 @@ import { useScreenQuickReturn } from './screenQuickReturn';
|
|
|
37
37
|
|
|
38
38
|
export type { ScreenProps };
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Screen container: sets the navigation header, lays children on the grid, and adds the
|
|
42
|
+
* scroll view, floating button and footer, with iPhone Duo side bar and tab bar insets.
|
|
43
|
+
*/
|
|
40
44
|
const Screen = forwardRef(
|
|
41
45
|
(
|
|
42
46
|
{
|
|
@@ -63,6 +67,7 @@ const Screen = forwardRef(
|
|
|
63
67
|
headerBackground,
|
|
64
68
|
gradientColor,
|
|
65
69
|
trackingParams,
|
|
70
|
+
contentLayout,
|
|
66
71
|
}: ScreenProps,
|
|
67
72
|
ref: any,
|
|
68
73
|
) => {
|
|
@@ -108,14 +113,12 @@ const Screen = forwardRef(
|
|
|
108
113
|
const isIOS = Platform.OS === 'ios';
|
|
109
114
|
const bottomInset = isIOS ? Math.min(insets.bottom, 21) : insets.bottom;
|
|
110
115
|
const hasSideBar = !!layout.sideBar;
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
!animatedHeader &&
|
|
115
|
-
!inputSearchProps;
|
|
116
|
+
const isPlainHeader = headerType === 'default' || headerType === 'extended';
|
|
117
|
+
const hasCustomHeader = !!animatedHeader || !!inputSearchProps;
|
|
118
|
+
const useDuoGlass = hasSideBar && isPlainHeader && !hasCustomHeader;
|
|
116
119
|
|
|
117
|
-
const
|
|
118
|
-
|
|
120
|
+
const hasOverlayHeader = useDuoGlass || !!animatedHeader;
|
|
121
|
+
const useQuickReturn = hasSideBar && scrollable && hasOverlayHeader;
|
|
119
122
|
const { quickReturnOptions, snapQuickReturnHeader } = useScreenQuickReturn(
|
|
120
123
|
sharedValue,
|
|
121
124
|
useQuickReturn,
|
|
@@ -123,18 +126,10 @@ const Screen = forwardRef(
|
|
|
123
126
|
);
|
|
124
127
|
|
|
125
128
|
let keyboardOffset = heightHeader - bottomInset;
|
|
126
|
-
if (
|
|
127
|
-
headerType === 'extended' ||
|
|
128
|
-
animatedHeader ||
|
|
129
|
-
inputSearchProps ||
|
|
130
|
-
useDuoGlass
|
|
131
|
-
) {
|
|
129
|
+
if (headerType === 'extended' || hasCustomHeader || useDuoGlass) {
|
|
132
130
|
keyboardOffset = -bottomInset;
|
|
133
131
|
}
|
|
134
132
|
|
|
135
|
-
/**
|
|
136
|
-
* inject params for screen tracking
|
|
137
|
-
*/
|
|
138
133
|
screen?.onSetParams?.(trackingParams);
|
|
139
134
|
|
|
140
135
|
const { setSearchHeader, currentTint } = useScreenHeader({
|
|
@@ -150,11 +145,10 @@ const Screen = forwardRef(
|
|
|
150
145
|
gradientColor,
|
|
151
146
|
headerBackground,
|
|
152
147
|
layoutOffset,
|
|
148
|
+
contentLayout,
|
|
153
149
|
});
|
|
154
150
|
|
|
155
|
-
|
|
156
|
-
* expose ref for screen
|
|
157
|
-
*/
|
|
151
|
+
// mutates the content node so callers keep its methods plus the header setters
|
|
158
152
|
useImperativeHandle(ref, () => {
|
|
159
153
|
return Object.assign(screenRef.current || {}, {
|
|
160
154
|
setOptions: (params: NavigationOptions) => {
|
|
@@ -165,19 +159,18 @@ const Screen = forwardRef(
|
|
|
165
159
|
});
|
|
166
160
|
});
|
|
167
161
|
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
});
|
|
162
|
+
const scrollHandlers = createScrollHandlers({
|
|
163
|
+
scrollable,
|
|
164
|
+
animatedValue: animatedValue.current,
|
|
165
|
+
sharedValue,
|
|
166
|
+
scrollViewProps,
|
|
167
|
+
animatedHeader,
|
|
168
|
+
inputSearchProps,
|
|
169
|
+
currentTint,
|
|
170
|
+
navigation,
|
|
171
|
+
snapQuickReturnHeader,
|
|
172
|
+
ref,
|
|
173
|
+
});
|
|
181
174
|
const Component: any = scrollable ? Animated.ScrollView : View;
|
|
182
175
|
|
|
183
176
|
const getHeight = () => {
|
|
@@ -207,6 +200,36 @@ const Screen = forwardRef(
|
|
|
207
200
|
floatingButtonBottom = 12 + duoTabInset;
|
|
208
201
|
}
|
|
209
202
|
|
|
203
|
+
const renderHeaderLayer = () => {
|
|
204
|
+
if (useDuoGlass) {
|
|
205
|
+
return (
|
|
206
|
+
<DuoScrollGradient
|
|
207
|
+
animatedValue={sharedValue}
|
|
208
|
+
gradientColor={gradientColor}
|
|
209
|
+
headerBackground={headerBackground}
|
|
210
|
+
heightHeader={heightHeader}
|
|
211
|
+
extended={headerType === 'extended'}
|
|
212
|
+
followScroll={useQuickReturn}
|
|
213
|
+
/>
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
return (
|
|
217
|
+
<HeaderExtendHeader
|
|
218
|
+
headerType={headerType}
|
|
219
|
+
heightHeader={heightHeader}
|
|
220
|
+
headerRightWidth={headerRightWidth}
|
|
221
|
+
animatedValue={sharedValue}
|
|
222
|
+
inputSearchProps={inputSearchProps}
|
|
223
|
+
navigation={navigation}
|
|
224
|
+
inputSearchRef={inputSearchRef}
|
|
225
|
+
useShadowHeader={useShadowHeader}
|
|
226
|
+
gradientColor={gradientColor}
|
|
227
|
+
headerBackground={headerBackground}
|
|
228
|
+
contentLayout={contentLayout}
|
|
229
|
+
/>
|
|
230
|
+
);
|
|
231
|
+
};
|
|
232
|
+
|
|
210
233
|
return (
|
|
211
234
|
<View
|
|
212
235
|
style={[
|
|
@@ -217,29 +240,7 @@ const Screen = forwardRef(
|
|
|
217
240
|
},
|
|
218
241
|
]}
|
|
219
242
|
>
|
|
220
|
-
{
|
|
221
|
-
<DuoScrollGradient
|
|
222
|
-
animatedValue={sharedValue}
|
|
223
|
-
gradientColor={gradientColor}
|
|
224
|
-
headerBackground={headerBackground}
|
|
225
|
-
heightHeader={heightHeader}
|
|
226
|
-
extended={headerType === 'extended'}
|
|
227
|
-
followScroll={useQuickReturn}
|
|
228
|
-
/>
|
|
229
|
-
) : (
|
|
230
|
-
<HeaderExtendHeader
|
|
231
|
-
headerType={headerType}
|
|
232
|
-
heightHeader={heightHeader}
|
|
233
|
-
headerRightWidth={headerRightWidth}
|
|
234
|
-
animatedValue={sharedValue}
|
|
235
|
-
inputSearchProps={inputSearchProps}
|
|
236
|
-
navigation={navigation}
|
|
237
|
-
inputSearchRef={inputSearchRef}
|
|
238
|
-
useShadowHeader={useShadowHeader}
|
|
239
|
-
gradientColor={gradientColor}
|
|
240
|
-
headerBackground={headerBackground}
|
|
241
|
-
/>
|
|
242
|
-
)}
|
|
243
|
+
{renderHeaderLayer()}
|
|
243
244
|
|
|
244
245
|
<KeyboardAvoidingView
|
|
245
246
|
style={[
|
|
@@ -259,9 +260,9 @@ const Screen = forwardRef(
|
|
|
259
260
|
{...scrollViewProps}
|
|
260
261
|
ref={screenRef}
|
|
261
262
|
showsVerticalScrollIndicator={false}
|
|
262
|
-
onScroll={handleScroll}
|
|
263
|
-
onScrollEndDrag={handleScrollEnd}
|
|
264
|
-
onMomentumScrollEnd={handleMomentumScrollEnd}
|
|
263
|
+
onScroll={scrollHandlers.handleScroll}
|
|
264
|
+
onScrollEndDrag={scrollHandlers.handleScrollEnd}
|
|
265
|
+
onMomentumScrollEnd={scrollHandlers.handleMomentumScrollEnd}
|
|
265
266
|
scrollEventThrottle={16}
|
|
266
267
|
style={[
|
|
267
268
|
Styles.flex,
|
package/Layout/Section.tsx
CHANGED
|
@@ -15,8 +15,8 @@ export interface SectionProps extends ViewProps {
|
|
|
15
15
|
expanded?: boolean;
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* Optional. If `true`,
|
|
19
|
-
* Defaults to `
|
|
18
|
+
* Optional. If `true`, 12pt side margins are applied to the Section component.
|
|
19
|
+
* Defaults to `true`.
|
|
20
20
|
*/
|
|
21
21
|
useMargin?: boolean;
|
|
22
22
|
|
|
@@ -26,6 +26,10 @@ export interface SectionProps extends ViewProps {
|
|
|
26
26
|
backgroundImage?: string;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Content-wide grid row (12 or 24 columns) with optional side margins; child Items size
|
|
31
|
+
* themselves from its GridContext.
|
|
32
|
+
*/
|
|
29
33
|
const Section: React.FC<SectionProps> = ({
|
|
30
34
|
children,
|
|
31
35
|
useMargin = true,
|
|
@@ -43,9 +47,8 @@ const Section: React.FC<SectionProps> = ({
|
|
|
43
47
|
}
|
|
44
48
|
const widthSection = contentWidth - margin * 2;
|
|
45
49
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
1 / numberOfColumns;
|
|
50
|
+
const columnsWidth = widthSection - gutterSize * (numberOfColumns - 1);
|
|
51
|
+
const sizePerSpan = columnsWidth / numberOfColumns - 1 / numberOfColumns;
|
|
49
52
|
|
|
50
53
|
const gridContext: GridContextProps = {
|
|
51
54
|
numberOfColumns,
|
package/Layout/TrackingScope.tsx
CHANGED
package/Layout/screenContent.tsx
CHANGED
|
@@ -9,7 +9,8 @@ import { AnimatedHeader } from '../Application/types';
|
|
|
9
9
|
type ContentInset = { insetLeft: number; insetRight: number };
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* Wraps each screen child (Fragments flattened) in a view with the screen's top spacing
|
|
13
|
+
* and side insets; a child with `useMargin: false` gets no top spacing.
|
|
13
14
|
*/
|
|
14
15
|
export const renderContent = (content: any, layout: ContentInset): any => {
|
|
15
16
|
const results = validateChildren(content, [undefined]);
|
|
@@ -64,7 +65,8 @@ export const renderContent = (content: any, layout: ContentInset): any => {
|
|
|
64
65
|
};
|
|
65
66
|
|
|
66
67
|
/**
|
|
67
|
-
*
|
|
68
|
+
* Animated banner from `animatedHeader.component`, clipped to the banner height plus
|
|
69
|
+
* `layoutOffset`. Nothing without a component.
|
|
68
70
|
*/
|
|
69
71
|
export const renderAnimatedHeader = (
|
|
70
72
|
animatedHeader: AnimatedHeader | undefined,
|
package/Layout/screenFooter.tsx
CHANGED
|
@@ -16,6 +16,10 @@ type ScreenFooterProps = {
|
|
|
16
16
|
surfaceColor: string;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Screen footer on the surface color with a top shadow, padded above the home indicator,
|
|
21
|
+
* or above the floating tab bar on a tab screen.
|
|
22
|
+
*/
|
|
19
23
|
export const ScreenFooter = ({
|
|
20
24
|
footer,
|
|
21
25
|
marginFooter,
|
|
@@ -26,28 +30,34 @@ export const ScreenFooter = ({
|
|
|
26
30
|
duoTabInset,
|
|
27
31
|
bottomInset,
|
|
28
32
|
surfaceColor,
|
|
29
|
-
}: ScreenFooterProps) =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
marginRight: insetRight,
|
|
37
|
-
},
|
|
38
|
-
]}
|
|
39
|
-
>
|
|
33
|
+
}: ScreenFooterProps) => {
|
|
34
|
+
let bottomSpace = bottomInset;
|
|
35
|
+
if (isTab && duoTabInset) {
|
|
36
|
+
bottomSpace = duoTabInset;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
40
|
<View
|
|
41
|
+
pointerEvents={'box-none'}
|
|
41
42
|
style={[
|
|
42
|
-
styles.
|
|
43
|
+
hasContentInset && styles.footerClip,
|
|
43
44
|
{
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
backgroundColor: surfaceColor,
|
|
45
|
+
marginLeft: insetLeft,
|
|
46
|
+
marginRight: insetRight,
|
|
47
47
|
},
|
|
48
48
|
]}
|
|
49
49
|
>
|
|
50
|
-
<
|
|
50
|
+
<View
|
|
51
|
+
style={[
|
|
52
|
+
styles.shadow,
|
|
53
|
+
{
|
|
54
|
+
paddingBottom: bottomSpace + Spacing.S,
|
|
55
|
+
backgroundColor: surfaceColor,
|
|
56
|
+
},
|
|
57
|
+
]}
|
|
58
|
+
>
|
|
59
|
+
<Section useMargin={marginFooter}>{footer}</Section>
|
|
60
|
+
</View>
|
|
51
61
|
</View>
|
|
52
|
-
|
|
53
|
-
|
|
62
|
+
);
|
|
63
|
+
};
|
package/Layout/screenHeader.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
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';
|
|
4
5
|
import Navigation from '../Application/Navigation';
|
|
5
6
|
import { AnimatedHeader, SearchHeaderProps } from '../Application/types';
|
|
6
7
|
import { exportHeaderTitle } from '../Application/navigationOptions';
|
|
@@ -12,6 +13,11 @@ import {
|
|
|
12
13
|
SearchHeader,
|
|
13
14
|
} from '../Application';
|
|
14
15
|
import { DuoGlassBackground } from '../Application/Components/DuoGlassBackground';
|
|
16
|
+
import {
|
|
17
|
+
type HeaderContentLayout,
|
|
18
|
+
useHeaderFrameOptions,
|
|
19
|
+
useHeaderLayout,
|
|
20
|
+
} from '../Application/headerLayout';
|
|
15
21
|
import { getHeaderMargin } from './utils';
|
|
16
22
|
import { ANIMATED_BANNER_HEIGHT } from './screenTypes';
|
|
17
23
|
import { HeaderType } from './types';
|
|
@@ -29,8 +35,37 @@ type ScreenHeaderParams = {
|
|
|
29
35
|
gradientColor?: string;
|
|
30
36
|
headerBackground?: string;
|
|
31
37
|
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
|
+
};
|
|
32
63
|
};
|
|
33
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Applies the Screen's navigation header (plain, extended, animated banner or search) and
|
|
67
|
+
* re-applies it when those props change. Returns the search header setter and the tint.
|
|
68
|
+
*/
|
|
34
69
|
export const useScreenHeader = ({
|
|
35
70
|
navigation,
|
|
36
71
|
layout,
|
|
@@ -44,14 +79,14 @@ export const useScreenHeader = ({
|
|
|
44
79
|
gradientColor,
|
|
45
80
|
headerBackground,
|
|
46
81
|
layoutOffset,
|
|
82
|
+
contentLayout,
|
|
47
83
|
}: ScreenHeaderParams) => {
|
|
48
84
|
const currentTint = useRef<string | undefined>(undefined);
|
|
49
85
|
const appliedHeaderMode = useRef<string | undefined>(undefined);
|
|
86
|
+
const headerLayout = useHeaderLayout(contentLayout);
|
|
87
|
+
const frameOptions = useHeaderFrameOptions(contentLayout);
|
|
50
88
|
|
|
51
|
-
|
|
52
|
-
* export options for screen
|
|
53
|
-
* @param type
|
|
54
|
-
*/
|
|
89
|
+
// keepTitle leaves a title the screen set itself when the same type is re-applied
|
|
55
90
|
const setHeaderType = useCallback(
|
|
56
91
|
(type: HeaderType, keepTitle = false) => {
|
|
57
92
|
let options: StackNavigationOptions;
|
|
@@ -69,28 +104,16 @@ export const useScreenHeader = ({
|
|
|
69
104
|
...quickReturnOptions,
|
|
70
105
|
headerShown: true,
|
|
71
106
|
headerTransparent: true,
|
|
72
|
-
headerBackground: () =>
|
|
73
|
-
hasSideBar
|
|
74
|
-
|
|
75
|
-
|
|
107
|
+
headerBackground: () => {
|
|
108
|
+
if (!hasSideBar) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
return <DuoGlassBackground animatedValue={sharedValue} />;
|
|
112
|
+
},
|
|
76
113
|
headerTitle: (props: any) => <HeaderTitle {...props} />,
|
|
77
114
|
};
|
|
78
115
|
if (inputSearchProps) {
|
|
79
|
-
options =
|
|
80
|
-
headerShown: true,
|
|
81
|
-
headerTransparent: true,
|
|
82
|
-
headerBackground: () => null,
|
|
83
|
-
headerTitle: (props: any) => (
|
|
84
|
-
<HeaderTitle
|
|
85
|
-
{...props}
|
|
86
|
-
interpolate={{
|
|
87
|
-
inputRange: [0, 50],
|
|
88
|
-
outputRange: [1, 0],
|
|
89
|
-
}}
|
|
90
|
-
animatedValue={sharedValue}
|
|
91
|
-
/>
|
|
92
|
-
),
|
|
93
|
-
};
|
|
116
|
+
options = getSearchTitleOptions(sharedValue);
|
|
94
117
|
}
|
|
95
118
|
break;
|
|
96
119
|
|
|
@@ -124,21 +147,7 @@ export const useScreenHeader = ({
|
|
|
124
147
|
headerTitle: (props: any) => <HeaderTitle {...props} />,
|
|
125
148
|
};
|
|
126
149
|
if (inputSearchProps) {
|
|
127
|
-
options =
|
|
128
|
-
headerShown: true,
|
|
129
|
-
headerTransparent: true,
|
|
130
|
-
headerBackground: () => null,
|
|
131
|
-
headerTitle: (props: any) => (
|
|
132
|
-
<HeaderTitle
|
|
133
|
-
{...props}
|
|
134
|
-
interpolate={{
|
|
135
|
-
inputRange: [0, 50],
|
|
136
|
-
outputRange: [1, 0],
|
|
137
|
-
}}
|
|
138
|
-
animatedValue={sharedValue}
|
|
139
|
-
/>
|
|
140
|
-
),
|
|
141
|
-
};
|
|
150
|
+
options = getSearchTitleOptions(sharedValue);
|
|
142
151
|
}
|
|
143
152
|
}
|
|
144
153
|
|
|
@@ -146,7 +155,11 @@ export const useScreenHeader = ({
|
|
|
146
155
|
delete options.headerTitle;
|
|
147
156
|
}
|
|
148
157
|
|
|
149
|
-
navigation?.instance?.setOptions({
|
|
158
|
+
navigation?.instance?.setOptions({
|
|
159
|
+
header: undefined,
|
|
160
|
+
...frameOptions,
|
|
161
|
+
...options,
|
|
162
|
+
});
|
|
150
163
|
},
|
|
151
164
|
[
|
|
152
165
|
gradientColor,
|
|
@@ -157,13 +170,11 @@ export const useScreenHeader = ({
|
|
|
157
170
|
useShadowHeader,
|
|
158
171
|
hasSideBar,
|
|
159
172
|
quickReturnOptions,
|
|
173
|
+
frameOptions,
|
|
160
174
|
],
|
|
161
175
|
);
|
|
162
176
|
|
|
163
|
-
|
|
164
|
-
* export animatedHeader options for screen
|
|
165
|
-
* @param nextAnimatedHeader
|
|
166
|
-
*/
|
|
177
|
+
// the first tint the animated header sets is kept for later scroll updates
|
|
167
178
|
const setAnimatedHeader = useCallback(
|
|
168
179
|
(nextAnimatedHeader: AnimatedHeader) => {
|
|
169
180
|
let options: StackNavigationOptions;
|
|
@@ -175,13 +186,16 @@ export const useScreenHeader = ({
|
|
|
175
186
|
...quickReturnOptions,
|
|
176
187
|
headerTintColor: currentTint.current ?? Colors.black_17,
|
|
177
188
|
headerTransparent: true,
|
|
178
|
-
headerBackground: (props: any) =>
|
|
179
|
-
hasSideBar
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
189
|
+
headerBackground: (props: any) => {
|
|
190
|
+
if (hasSideBar) {
|
|
191
|
+
return (
|
|
192
|
+
<DuoGlassBackground
|
|
193
|
+
animatedValue={sharedValue}
|
|
194
|
+
bannerBottom={ANIMATED_BANNER_HEIGHT + layoutOffset}
|
|
195
|
+
/>
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
return (
|
|
185
199
|
<HeaderBackground
|
|
186
200
|
{...props}
|
|
187
201
|
animatedValue={sharedValue}
|
|
@@ -190,7 +204,8 @@ export const useScreenHeader = ({
|
|
|
190
204
|
headerBackground={headerBackground}
|
|
191
205
|
gradientColor={gradientColor}
|
|
192
206
|
/>
|
|
193
|
-
)
|
|
207
|
+
);
|
|
208
|
+
},
|
|
194
209
|
headerTitle: (props: any) => {
|
|
195
210
|
return <HeaderTitle {...props} />;
|
|
196
211
|
},
|
|
@@ -203,7 +218,7 @@ export const useScreenHeader = ({
|
|
|
203
218
|
};
|
|
204
219
|
}
|
|
205
220
|
|
|
206
|
-
navigation?.instance?.setOptions(options);
|
|
221
|
+
navigation?.instance?.setOptions({ ...frameOptions, ...options });
|
|
207
222
|
},
|
|
208
223
|
[
|
|
209
224
|
gradientColor,
|
|
@@ -214,47 +229,34 @@ export const useScreenHeader = ({
|
|
|
214
229
|
hasSideBar,
|
|
215
230
|
layoutOffset,
|
|
216
231
|
quickReturnOptions,
|
|
232
|
+
frameOptions,
|
|
217
233
|
],
|
|
218
234
|
);
|
|
219
235
|
|
|
220
|
-
/**
|
|
221
|
-
* export animatedHeader options for screen
|
|
222
|
-
*/
|
|
223
236
|
const setAnimatedSearch = useCallback(() => {
|
|
224
|
-
const options
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
interpolate={{
|
|
232
|
-
inputRange: [0, 50],
|
|
233
|
-
outputRange: [1, 0],
|
|
234
|
-
}}
|
|
235
|
-
animatedValue={sharedValue}
|
|
236
|
-
/>
|
|
237
|
-
),
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
navigation?.instance?.setOptions({ header: undefined, ...options });
|
|
241
|
-
}, [navigation?.instance, sharedValue]);
|
|
237
|
+
const options = getSearchTitleOptions(sharedValue);
|
|
238
|
+
navigation?.instance?.setOptions({
|
|
239
|
+
header: undefined,
|
|
240
|
+
...frameOptions,
|
|
241
|
+
...options,
|
|
242
|
+
});
|
|
243
|
+
}, [navigation?.instance, sharedValue, frameOptions]);
|
|
242
244
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
*/
|
|
245
|
+
// the search field spans the content (or the stretch frame), clear of the side bar
|
|
246
|
+
// and status bar clusters
|
|
246
247
|
const setSearchHeader = (params: SearchHeaderProps) => {
|
|
247
|
-
let searchWidth =
|
|
248
|
+
let searchWidth = headerLayout.frameWidth;
|
|
248
249
|
let searchLeft = Spacing.M;
|
|
249
250
|
if (layout.sideBar) {
|
|
250
251
|
searchWidth = layout.contentWidth - Spacing.M * 2;
|
|
251
252
|
searchLeft = Spacing.M - getHeaderMargin(layout.width);
|
|
252
253
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
254
|
+
const clearance = layout.statusBarClearance;
|
|
255
|
+
if (clearance) {
|
|
256
|
+
searchWidth -= clearance.left + clearance.right;
|
|
256
257
|
}
|
|
257
258
|
const options: StackNavigationOptions = {
|
|
259
|
+
...frameOptions,
|
|
258
260
|
headerRight: undefined,
|
|
259
261
|
headerTitleContainerStyle: {
|
|
260
262
|
width: searchWidth,
|
|
@@ -267,8 +269,12 @@ export const useScreenHeader = ({
|
|
|
267
269
|
margin: 0,
|
|
268
270
|
left: searchLeft,
|
|
269
271
|
},
|
|
270
|
-
headerLeft: (props: any) =>
|
|
271
|
-
params?.hiddenBack
|
|
272
|
+
headerLeft: (props: any) => {
|
|
273
|
+
if (params?.hiddenBack) {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
return <HeaderLeft {...props} floating />;
|
|
277
|
+
},
|
|
272
278
|
headerTitle: () => (
|
|
273
279
|
<SearchHeader {...params} animatedValue={sharedValue} />
|
|
274
280
|
),
|
|
@@ -8,6 +8,10 @@ import {
|
|
|
8
8
|
} from 'react-native-reanimated';
|
|
9
9
|
import { DuoQuickReturnHeader } from '../Application/Components/DuoQuickReturnHeader';
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* iPhone Duo quick return header: it slides out while the content scrolls down and back
|
|
13
|
+
* on scroll up. Returns the header options and a snap to call when scrolling ends.
|
|
14
|
+
*/
|
|
11
15
|
export const useScreenQuickReturn = (
|
|
12
16
|
sharedValue: SharedValue<number>,
|
|
13
17
|
useQuickReturn: boolean,
|
|
@@ -33,29 +37,22 @@ export const useScreenQuickReturn = (
|
|
|
33
37
|
[useQuickReturn, heightHeader],
|
|
34
38
|
);
|
|
35
39
|
|
|
36
|
-
const quickReturnOptions: StackNavigationOptions = useMemo(
|
|
37
|
-
()
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
);
|
|
40
|
+
const quickReturnOptions: StackNavigationOptions = useMemo(() => {
|
|
41
|
+
if (!useQuickReturn) {
|
|
42
|
+
return { header: undefined };
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
header: (props: any) => (
|
|
46
|
+
<DuoQuickReturnHeader {...props} offset={headerHide} />
|
|
47
|
+
),
|
|
48
|
+
};
|
|
49
|
+
}, [useQuickReturn, headerHide]);
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
* a half-shown quick return header settles fully in or out
|
|
50
|
-
*/
|
|
51
|
+
// a half-shown quick return header settles fully in or out
|
|
51
52
|
const snapQuickReturnHeader = (offsetY: number) => {
|
|
52
53
|
const hide = headerHide.value;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
offsetY < heightHeader ||
|
|
56
|
-
hide <= 0 ||
|
|
57
|
-
hide >= heightHeader
|
|
58
|
-
) {
|
|
54
|
+
const isSettled = hide <= 0 || hide >= heightHeader;
|
|
55
|
+
if (!useQuickReturn || offsetY < heightHeader || isSettled) {
|
|
59
56
|
return;
|
|
60
57
|
}
|
|
61
58
|
headerHide.value = withTiming(hide > heightHeader / 2 ? heightHeader : 0, {
|
package/Layout/screenScroll.ts
CHANGED
|
@@ -25,6 +25,10 @@ type ScrollHandlerParams = {
|
|
|
25
25
|
ref: any;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Scroll handlers for Screen: feed the header animated values, retint an animated header
|
|
30
|
+
* past 50pt, snap the quick return header and reset a search screen scrolled under 100pt.
|
|
31
|
+
*/
|
|
28
32
|
export const createScrollHandlers = ({
|
|
29
33
|
scrollable,
|
|
30
34
|
animatedValue,
|
|
@@ -39,9 +43,6 @@ export const createScrollHandlers = ({
|
|
|
39
43
|
}: ScrollHandlerParams) => {
|
|
40
44
|
let handleScroll;
|
|
41
45
|
|
|
42
|
-
/**
|
|
43
|
-
* animated when use scroll && animated value
|
|
44
|
-
*/
|
|
45
46
|
if (scrollable) {
|
|
46
47
|
handleScroll = Animated.event(
|
|
47
48
|
[
|
|
@@ -80,10 +81,6 @@ export const createScrollHandlers = ({
|
|
|
80
81
|
);
|
|
81
82
|
}
|
|
82
83
|
|
|
83
|
-
/**
|
|
84
|
-
* handle scroll end
|
|
85
|
-
* @param e
|
|
86
|
-
*/
|
|
87
84
|
const handleMomentumScrollEnd = (
|
|
88
85
|
e: NativeSyntheticEvent<NativeScrollEvent>,
|
|
89
86
|
) => {
|