@momo-kits/foundation 0.167.1-duotest.2 → 0.167.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/Application/BottomSheet.tsx +14 -115
- package/Application/BottomTab/BottomTabBar.tsx +3 -6
- package/Application/BottomTab/index.tsx +135 -162
- package/Application/Components/HeaderExtendHeader.tsx +28 -75
- package/Application/Components/HeaderLeft.tsx +0 -38
- package/Application/Components/HeaderRight.tsx +9 -142
- package/Application/Components/HeaderTitle.tsx +7 -43
- package/Application/Components/SearchHeader.tsx +15 -22
- package/Application/ModalScreen.tsx +2 -16
- package/Application/NavigationContainer.tsx +38 -22
- package/Application/Navigator.ts +3 -1
- package/Application/StackScreen.tsx +9 -63
- package/Application/types.ts +1 -27
- package/Application/utils.tsx +6 -242
- package/Consts/theme.ts +4 -3
- package/Input/Input.tsx +4 -3
- package/Input/InputMoney.tsx +8 -5
- package/Input/InputPhoneNumber.tsx +4 -3
- package/Input/InputSearch.tsx +4 -3
- package/Input/InputTextArea.tsx +4 -3
- package/Layout/Card.tsx +26 -8
- package/Layout/FloatingButton.tsx +3 -3
- package/Layout/GridSystem.tsx +137 -0
- package/Layout/Item.tsx +10 -1
- package/Layout/Screen.tsx +52 -199
- package/Layout/Section.tsx +18 -5
- package/Layout/index.ts +4 -4
- package/Layout/styles.ts +0 -5
- package/Layout/utils.ts +5 -465
- package/Popup/PopupNotify.tsx +22 -33
- package/Popup/PopupPromotion.tsx +8 -20
- package/Text/utils.ts +2 -1
- package/package.json +2 -3
- package/Application/BottomTab/DuoBarCompression.tsx +0 -135
- package/Application/BottomTab/DuoTabBar.tsx +0 -462
- package/Application/Components/DuoGlassBackground.tsx +0 -179
- package/Application/Components/DuoQuickReturnHeader.tsx +0 -42
- package/Application/Components/OptionalGlassView.ts +0 -11
- package/Application/Components/OptionalScrollObserver.ts +0 -12
- package/Application/Components/SideBarButton.tsx +0 -139
- package/Application/device.ts +0 -29
- package/Layout/ReservedRegions.tsx +0 -47
- package/Popup/utils.ts +0 -32
|
@@ -2,6 +2,7 @@ import React, { useContext, useEffect, useRef, useState } from 'react';
|
|
|
2
2
|
import {
|
|
3
3
|
SafeAreaInsetsContext,
|
|
4
4
|
SafeAreaProvider,
|
|
5
|
+
useSafeAreaInsets,
|
|
5
6
|
} from 'react-native-safe-area-context';
|
|
6
7
|
import {
|
|
7
8
|
NavigationContainer as ReactNavigationContainer,
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
StackNavigationOptions,
|
|
13
14
|
TransitionPresets,
|
|
14
15
|
} from '@react-navigation/stack';
|
|
16
|
+
import { DeviceEventEmitter } from 'react-native';
|
|
15
17
|
import StackScreen from './StackScreen';
|
|
16
18
|
import ModalScreen from './ModalScreen';
|
|
17
19
|
import Navigator from './Navigator';
|
|
@@ -30,9 +32,6 @@ import { HeaderRight } from './Components/HeaderRight';
|
|
|
30
32
|
import { HeaderTitle } from './Components/HeaderTitle';
|
|
31
33
|
import { HeaderBackground } from './Components/HeaderBackground';
|
|
32
34
|
import { type EdgeInsets } from 'react-native-safe-area-context';
|
|
33
|
-
import { useScreenLayout } from '../Layout';
|
|
34
|
-
import { getHeaderRowOptions } from '../Layout/utils';
|
|
35
|
-
import { ReservedRegionsProvider } from '../Layout/ReservedRegions';
|
|
36
35
|
|
|
37
36
|
const Stack = createStackNavigator();
|
|
38
37
|
|
|
@@ -78,19 +77,17 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
|
|
|
78
77
|
frame: { x: 0, y: 0, width: 0, height: 0 },
|
|
79
78
|
}}
|
|
80
79
|
>
|
|
81
|
-
<
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
</MiniAppContext.Provider>
|
|
93
|
-
</ReservedRegionsProvider>
|
|
80
|
+
<MiniAppContext.Provider value={mergedContext}>
|
|
81
|
+
<Navigation
|
|
82
|
+
screen={screen}
|
|
83
|
+
theme={theme}
|
|
84
|
+
options={options}
|
|
85
|
+
maxApi={maxApi}
|
|
86
|
+
setCurrentContext={setCurrentContext}
|
|
87
|
+
initialParams={initialParams}
|
|
88
|
+
localize={localize}
|
|
89
|
+
/>
|
|
90
|
+
</MiniAppContext.Provider>
|
|
94
91
|
</SafeAreaProvider>
|
|
95
92
|
);
|
|
96
93
|
};
|
|
@@ -108,7 +105,8 @@ const Navigation: React.FC<any> = ({
|
|
|
108
105
|
const navigationRef = useRef<any>(null);
|
|
109
106
|
const isReady = useRef(false);
|
|
110
107
|
const navigator = useRef(new Navigator(navigationRef, isReady));
|
|
111
|
-
const
|
|
108
|
+
const [showGrid, setShowGrid] = useState(false);
|
|
109
|
+
const insets = useSafeAreaInsets();
|
|
112
110
|
const syncCanGoBack = useNativeCanGoBack();
|
|
113
111
|
const isWhiteList = isWhiteListDesignSystem(context);
|
|
114
112
|
const fontFamily = isWhiteList ? 'MomoTrustSans' : 'SFProText';
|
|
@@ -128,6 +126,23 @@ const Navigation: React.FC<any> = ({
|
|
|
128
126
|
*/
|
|
129
127
|
navigator.current.maxApi = maxApi;
|
|
130
128
|
|
|
129
|
+
/**
|
|
130
|
+
* handle mini language & listen change
|
|
131
|
+
* engine only shake to enable grid view
|
|
132
|
+
*/
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
const subscription = DeviceEventEmitter.addListener(
|
|
135
|
+
'onChangeGrid',
|
|
136
|
+
enable => {
|
|
137
|
+
setShowGrid(!!enable);
|
|
138
|
+
},
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
return () => {
|
|
142
|
+
subscription?.remove?.();
|
|
143
|
+
};
|
|
144
|
+
}, []);
|
|
145
|
+
|
|
131
146
|
/**
|
|
132
147
|
* translate context method
|
|
133
148
|
* @param data
|
|
@@ -157,6 +172,7 @@ const Navigation: React.FC<any> = ({
|
|
|
157
172
|
headerBackground,
|
|
158
173
|
},
|
|
159
174
|
},
|
|
175
|
+
showGrid,
|
|
160
176
|
translate,
|
|
161
177
|
}}
|
|
162
178
|
>
|
|
@@ -205,7 +221,9 @@ const Navigation: React.FC<any> = ({
|
|
|
205
221
|
gestureEnabled: false,
|
|
206
222
|
headerTitleAlign: 'center',
|
|
207
223
|
headerTintColor: theme.colors.text.default,
|
|
208
|
-
|
|
224
|
+
headerStyle: {
|
|
225
|
+
height: 52 + insets.top,
|
|
226
|
+
},
|
|
209
227
|
}}
|
|
210
228
|
>
|
|
211
229
|
<Stack.Screen
|
|
@@ -228,13 +246,11 @@ const Navigation: React.FC<any> = ({
|
|
|
228
246
|
cardStyle: {
|
|
229
247
|
backgroundColor: theme.colors.background.default,
|
|
230
248
|
},
|
|
231
|
-
headerLeft: (props: any) => <HeaderLeft {...props}
|
|
249
|
+
headerLeft: (props: any) => <HeaderLeft {...props} />,
|
|
232
250
|
headerBackground: (props: any) => (
|
|
233
251
|
<HeaderBackground {...props} />
|
|
234
252
|
),
|
|
235
|
-
headerRight: (props: any) =>
|
|
236
|
-
<HeaderRight {...props} floating />
|
|
237
|
-
),
|
|
253
|
+
headerRight: (props: any) => <HeaderRight {...props} />,
|
|
238
254
|
headerTintColor: Colors.black_17,
|
|
239
255
|
...TransitionPresets.ModalTransition,
|
|
240
256
|
}}
|
package/Application/Navigator.ts
CHANGED
|
@@ -1,27 +1,12 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
useContext,
|
|
4
|
-
useEffect,
|
|
5
|
-
useLayoutEffect,
|
|
6
|
-
useRef,
|
|
7
|
-
useState,
|
|
8
|
-
} from 'react';
|
|
9
|
-
import {
|
|
10
|
-
Alert,
|
|
11
|
-
InteractionManager,
|
|
12
|
-
Platform,
|
|
13
|
-
StyleSheet,
|
|
14
|
-
View,
|
|
15
|
-
} from 'react-native';
|
|
16
|
-
import Animated from 'react-native-reanimated';
|
|
1
|
+
import React, { useContext, useEffect, useLayoutEffect, useRef } from 'react';
|
|
2
|
+
import { Alert, InteractionManager } from 'react-native';
|
|
17
3
|
import { useHeaderHeight } from '@react-navigation/elements';
|
|
18
4
|
import { ScreenTrackingParams } from './types';
|
|
19
5
|
import Navigation from './Navigation';
|
|
20
6
|
import { ApplicationContext, MiniAppContext, ScreenContext } from '../Context';
|
|
7
|
+
import { GridSystem } from '../Layout';
|
|
21
8
|
import { version } from '../package.json';
|
|
22
|
-
import { SwipeBackHaptic, useAppState
|
|
23
|
-
import { ScrollObserverView } from './Components/OptionalScrollObserver';
|
|
24
|
-
import { useScreenLayout } from '../Layout/utils';
|
|
9
|
+
import { SwipeBackHaptic, useAppState } from './utils';
|
|
25
10
|
import { TooltipPortalHost, TooltipPortalProvider } from './TooltipPortal';
|
|
26
11
|
|
|
27
12
|
const runAfterInteractions = InteractionManager.runAfterInteractions;
|
|
@@ -32,7 +17,7 @@ const runAfterInteractions = InteractionManager.runAfterInteractions;
|
|
|
32
17
|
* @constructor
|
|
33
18
|
*/
|
|
34
19
|
const StackScreen: React.FC<any> = props => {
|
|
35
|
-
const { navigator } = useContext(ApplicationContext);
|
|
20
|
+
const { showGrid, navigator } = useContext(ApplicationContext);
|
|
36
21
|
const tracking = useRef<any>({
|
|
37
22
|
mounted: false,
|
|
38
23
|
timeoutLoad: undefined,
|
|
@@ -57,7 +42,6 @@ const StackScreen: React.FC<any> = props => {
|
|
|
57
42
|
});
|
|
58
43
|
const widgets = useRef<any>([]);
|
|
59
44
|
const context = useContext<any>(MiniAppContext);
|
|
60
|
-
|
|
61
45
|
const {
|
|
62
46
|
screen: Component,
|
|
63
47
|
options,
|
|
@@ -67,24 +51,6 @@ const StackScreen: React.FC<any> = props => {
|
|
|
67
51
|
const navigation = useRef(new Navigation(props.navigation, context)).current;
|
|
68
52
|
const heightHeader = useHeaderHeight();
|
|
69
53
|
const { isBackgroundToForeground } = useAppState();
|
|
70
|
-
const layout = useScreenLayout();
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* iPhone Duo: a screen without <Screen> keeps clear of the side bar and, with the
|
|
74
|
-
* native scroll observer, gets the quick return header, so mini apps need no change
|
|
75
|
-
*/
|
|
76
|
-
const canAutoLayout = Platform.OS === 'ios' && !bottomTab;
|
|
77
|
-
const Observer: React.ComponentType<any> = ScrollObserverView ?? View;
|
|
78
|
-
const headerClaimed = useRef(false);
|
|
79
|
-
const [autoHeader, setAutoHeader] = useState(false);
|
|
80
|
-
const syncHeader = useCallback(() => {
|
|
81
|
-
setAutoHeader(
|
|
82
|
-
canAutoLayout && layout.isIPhoneDuo && !headerClaimed.current,
|
|
83
|
-
);
|
|
84
|
-
}, [canAutoLayout, layout.isIPhoneDuo]);
|
|
85
|
-
// parent effects run after the screen's, so a claim made on mount is already in
|
|
86
|
-
useEffect(syncHeader, [syncHeader]);
|
|
87
|
-
const headerScroll = useHeaderScrollState({ navigation }, autoHeader);
|
|
88
54
|
|
|
89
55
|
const data = {
|
|
90
56
|
...initialParams,
|
|
@@ -441,38 +407,18 @@ const StackScreen: React.FC<any> = props => {
|
|
|
441
407
|
onSetParams: (item: ScreenTrackingParams) => {
|
|
442
408
|
tracking.current.params = item;
|
|
443
409
|
},
|
|
444
|
-
claimHeader: () => {
|
|
445
|
-
headerClaimed.current = true;
|
|
446
|
-
},
|
|
447
|
-
syncHeader,
|
|
448
410
|
}}
|
|
449
411
|
>
|
|
450
412
|
<TooltipPortalProvider>
|
|
451
|
-
{
|
|
452
|
-
|
|
453
|
-
<Observer
|
|
454
|
-
enabled={autoHeader}
|
|
455
|
-
pointerEvents={'box-none'}
|
|
456
|
-
style={styles.flex}
|
|
457
|
-
onScrollChange={headerScroll.onScrollChange}
|
|
458
|
-
>
|
|
459
|
-
{headerScroll.background}
|
|
460
|
-
<Animated.View style={[styles.flex, headerScroll.contentStyle]}>
|
|
461
|
-
<Component heightHeader={heightHeader} {...data} />
|
|
462
|
-
</Animated.View>
|
|
463
|
-
</Observer>
|
|
464
|
-
) : (
|
|
465
|
-
<Component heightHeader={heightHeader} {...data} />
|
|
466
|
-
)}
|
|
413
|
+
<Component heightHeader={heightHeader} {...data} />
|
|
414
|
+
{showGrid && <GridSystem />}
|
|
467
415
|
<TooltipPortalHost />
|
|
416
|
+
{/* a leaf on purpose: it subscribes to CardAnimationContext, which changes on every
|
|
417
|
+
Card render, and must not pull this screen into those renders */}
|
|
468
418
|
<SwipeBackHaptic />
|
|
469
419
|
</TooltipPortalProvider>
|
|
470
420
|
</ScreenContext.Provider>
|
|
471
421
|
);
|
|
472
422
|
};
|
|
473
423
|
|
|
474
|
-
const styles = StyleSheet.create({
|
|
475
|
-
flex: { flex: 1 },
|
|
476
|
-
});
|
|
477
|
-
|
|
478
424
|
export default StackScreen;
|
package/Application/types.ts
CHANGED
|
@@ -117,6 +117,7 @@ export type Context = {
|
|
|
117
117
|
[key: string]: any;
|
|
118
118
|
theme: Theme;
|
|
119
119
|
navigator?: NavigatorProps;
|
|
120
|
+
showGrid?: boolean;
|
|
120
121
|
translate?: (data: string | { vi: string; en: string }) => string;
|
|
121
122
|
};
|
|
122
123
|
|
|
@@ -257,11 +258,6 @@ export interface HeaderBackProps extends NavigationButtonProps {
|
|
|
257
258
|
preventBack?: PopupNotifyProps;
|
|
258
259
|
onPressLeftHeader?: () => void;
|
|
259
260
|
onBackHandler?: (goBack: () => void) => void;
|
|
260
|
-
/**
|
|
261
|
-
* Optional. If `true`, the button floats into the iPhone Duo side bar while the
|
|
262
|
-
* device shows one. Set when the button is rendered by the navigation header.
|
|
263
|
-
*/
|
|
264
|
-
floating?: boolean;
|
|
265
261
|
}
|
|
266
262
|
|
|
267
263
|
export type HeaderBackgroundProps = {
|
|
@@ -333,11 +329,6 @@ export type BottomTabProps = {
|
|
|
333
329
|
blur?: (e: EventArg<'blur', false, unknown>) => void;
|
|
334
330
|
};
|
|
335
331
|
floatingButton?: FloatingButtonProps;
|
|
336
|
-
/**
|
|
337
|
-
* iPhone Duo: when the side bar can't hold both bars, which one starts compressed;
|
|
338
|
-
* tapping the compressed one swaps them. Defaults to 'toolbar'
|
|
339
|
-
*/
|
|
340
|
-
compressionBehavior?: 'toolbar' | 'tabBar';
|
|
341
332
|
};
|
|
342
333
|
|
|
343
334
|
export type FloatingButtonProps = {
|
|
@@ -361,20 +352,3 @@ export interface SearchHeaderProps extends InputSearchProps {
|
|
|
361
352
|
renderButtons?: () => ReactNode;
|
|
362
353
|
hiddenBack?: boolean;
|
|
363
354
|
}
|
|
364
|
-
|
|
365
|
-
export type HeaderScrollOptions = {
|
|
366
|
-
/**
|
|
367
|
-
* Navigation of the screen whose header follows the scroll.
|
|
368
|
-
*/
|
|
369
|
-
navigation?: Navigation;
|
|
370
|
-
useShadowHeader?: boolean;
|
|
371
|
-
gradientColor?: string;
|
|
372
|
-
headerBackground?: string;
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
export type ScrollChange = {
|
|
376
|
-
y: number;
|
|
377
|
-
contentHeight: number;
|
|
378
|
-
viewportHeight: number;
|
|
379
|
-
phase: 'scroll' | 'dragEnd' | 'momentumEnd' | 'takeOver';
|
|
380
|
-
};
|
package/Application/utils.tsx
CHANGED
|
@@ -16,23 +16,12 @@ import type {
|
|
|
16
16
|
StackCardInterpolationProps,
|
|
17
17
|
} from '@react-navigation/stack';
|
|
18
18
|
import type { NavigationState, PartialState } from '@react-navigation/native';
|
|
19
|
-
import type {
|
|
20
|
-
HeaderScrollOptions,
|
|
21
|
-
ScrollChange,
|
|
22
|
-
HeaderTitleProps,
|
|
23
|
-
NavigationOptions,
|
|
24
|
-
} from './types';
|
|
19
|
+
import type { HeaderTitleProps, NavigationOptions } from './types';
|
|
25
20
|
import { ApplicationContext } from '../Context';
|
|
26
21
|
import { Colors, Spacing } from '../Consts';
|
|
27
22
|
import { Animated, AppState, NativeModules, Platform } from 'react-native';
|
|
28
|
-
import { useHeaderHeight } from '@react-navigation/elements';
|
|
29
23
|
import type { SharedValue } from 'react-native-reanimated';
|
|
30
|
-
import {
|
|
31
|
-
useAnimatedReaction,
|
|
32
|
-
useAnimatedStyle,
|
|
33
|
-
useSharedValue,
|
|
34
|
-
withTiming,
|
|
35
|
-
} from 'react-native-reanimated';
|
|
24
|
+
import { useSharedValue } from 'react-native-reanimated';
|
|
36
25
|
import {
|
|
37
26
|
MiniAppContext,
|
|
38
27
|
ScreenContext,
|
|
@@ -42,12 +31,6 @@ import { HeaderTitle, TitleCustom } from './Components/HeaderTitle';
|
|
|
42
31
|
import { HeaderBackground } from './Components/HeaderBackground';
|
|
43
32
|
import { HeaderLeft } from './Components/HeaderLeft';
|
|
44
33
|
import { HeaderRight } from './Components/HeaderRight';
|
|
45
|
-
import {
|
|
46
|
-
DuoGlassBackground,
|
|
47
|
-
DuoScrollGradient,
|
|
48
|
-
} from './Components/DuoGlassBackground';
|
|
49
|
-
import { DuoQuickReturnHeader } from './Components/DuoQuickReturnHeader';
|
|
50
|
-
import { useScreenLayout } from '../Layout/utils';
|
|
51
34
|
|
|
52
35
|
const forStackTransitionWithOverlay = (
|
|
53
36
|
props: StackCardInterpolationProps,
|
|
@@ -90,8 +73,8 @@ const getStackOptions = (): StackNavigationOptions => {
|
|
|
90
73
|
left: Spacing.S,
|
|
91
74
|
},
|
|
92
75
|
headerBackground: (props: any) => <HeaderBackground {...props} />,
|
|
93
|
-
headerLeft: (props: any) => <HeaderLeft {...props}
|
|
94
|
-
headerRight: (props: any) => <HeaderRight {...props}
|
|
76
|
+
headerLeft: (props: any) => <HeaderLeft {...props} />,
|
|
77
|
+
headerRight: (props: any) => <HeaderRight {...props} />,
|
|
95
78
|
headerTintColor: Colors.black_17,
|
|
96
79
|
gestureEnabled: Platform.OS === 'ios',
|
|
97
80
|
...TransitionPresets.SlideFromRightIOS,
|
|
@@ -146,7 +129,6 @@ const getOptions = (
|
|
|
146
129
|
preventBack={params.preventBack}
|
|
147
130
|
onPressLeftHeader={params.onPressLeftHeader}
|
|
148
131
|
onBackHandler={params.onBackHandler}
|
|
149
|
-
floating
|
|
150
132
|
/>
|
|
151
133
|
);
|
|
152
134
|
if (params.hiddenBack) {
|
|
@@ -185,9 +167,7 @@ const getOptions = (
|
|
|
185
167
|
...options,
|
|
186
168
|
...{
|
|
187
169
|
headerRight: (props: any) => {
|
|
188
|
-
return
|
|
189
|
-
<HeaderRight {...props} headerRight={params.headerRight} floating />
|
|
190
|
-
);
|
|
170
|
+
return <HeaderRight {...props} headerRight={params.headerRight} />;
|
|
191
171
|
},
|
|
192
172
|
},
|
|
193
173
|
};
|
|
@@ -421,9 +401,7 @@ const getSwipeGestureValue = (
|
|
|
421
401
|
};
|
|
422
402
|
|
|
423
403
|
const readAnimatedValue = (node: unknown, fallback: number): number => {
|
|
424
|
-
const value = (
|
|
425
|
-
node as { __getValue?: () => unknown } | undefined
|
|
426
|
-
)?.__getValue?.();
|
|
404
|
+
const value = (node as { __getValue?: () => unknown } | undefined)?.__getValue?.();
|
|
427
405
|
return typeof value === 'number' ? value : fallback;
|
|
428
406
|
};
|
|
429
407
|
|
|
@@ -500,218 +478,6 @@ const SwipeBackHaptic = () => {
|
|
|
500
478
|
const isWhiteListDesignSystem = (context: any): boolean =>
|
|
501
479
|
context?.designSystemConfig?.isWhiteListDesignSystem === true;
|
|
502
480
|
|
|
503
|
-
/**
|
|
504
|
-
* iPhone Duo: the header leaves with the content and returns on a reverse scroll
|
|
505
|
-
*/
|
|
506
|
-
const useDuoQuickReturn = (
|
|
507
|
-
scrollY: SharedValue<number>,
|
|
508
|
-
enabled: boolean,
|
|
509
|
-
heightHeader: number,
|
|
510
|
-
) => {
|
|
511
|
-
const headerHide = useSharedValue(0);
|
|
512
|
-
const lastScrollY = useSharedValue(0);
|
|
513
|
-
|
|
514
|
-
useAnimatedReaction(
|
|
515
|
-
() => scrollY.value,
|
|
516
|
-
y => {
|
|
517
|
-
const delta = y - lastScrollY.value;
|
|
518
|
-
lastScrollY.value = y;
|
|
519
|
-
if (!enabled || y <= 0) {
|
|
520
|
-
headerHide.value = 0;
|
|
521
|
-
return;
|
|
522
|
-
}
|
|
523
|
-
headerHide.value = Math.min(
|
|
524
|
-
Math.max(headerHide.value + delta, 0),
|
|
525
|
-
heightHeader,
|
|
526
|
-
);
|
|
527
|
-
},
|
|
528
|
-
[enabled, heightHeader],
|
|
529
|
-
);
|
|
530
|
-
|
|
531
|
-
const quickReturnOptions: StackNavigationOptions = useMemo(
|
|
532
|
-
() =>
|
|
533
|
-
enabled
|
|
534
|
-
? {
|
|
535
|
-
header: (props: any) => (
|
|
536
|
-
<DuoQuickReturnHeader {...props} offset={headerHide} />
|
|
537
|
-
),
|
|
538
|
-
}
|
|
539
|
-
: { header: undefined },
|
|
540
|
-
[enabled, headerHide],
|
|
541
|
-
);
|
|
542
|
-
|
|
543
|
-
/**
|
|
544
|
-
* a half-shown quick return header settles fully in or out
|
|
545
|
-
*/
|
|
546
|
-
const snap = useCallback(
|
|
547
|
-
(offsetY: number) => {
|
|
548
|
-
const hide = headerHide.value;
|
|
549
|
-
// above heightHeader the header still sits on the content
|
|
550
|
-
if (
|
|
551
|
-
!enabled ||
|
|
552
|
-
offsetY < heightHeader ||
|
|
553
|
-
hide <= 0 ||
|
|
554
|
-
hide >= heightHeader
|
|
555
|
-
) {
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
|
-
headerHide.value = withTiming(
|
|
559
|
-
hide > heightHeader / 2 ? heightHeader : 0,
|
|
560
|
-
{ duration: 200 },
|
|
561
|
-
);
|
|
562
|
-
},
|
|
563
|
-
[enabled, heightHeader, headerHide],
|
|
564
|
-
);
|
|
565
|
-
|
|
566
|
-
/**
|
|
567
|
-
* moves the reference point without counting it as a scroll
|
|
568
|
-
*/
|
|
569
|
-
const resync = useCallback(
|
|
570
|
-
(y: number) => {
|
|
571
|
-
lastScrollY.value = y;
|
|
572
|
-
},
|
|
573
|
-
[lastScrollY],
|
|
574
|
-
);
|
|
575
|
-
|
|
576
|
-
return { headerHide, quickReturnOptions, snap, resync };
|
|
577
|
-
};
|
|
578
|
-
|
|
579
|
-
/**
|
|
580
|
-
* Header scroll state for screens that render their own scroll views instead of
|
|
581
|
-
* `<Screen scrollable>`, such as one ScrollView per TabView page.
|
|
582
|
-
*/
|
|
583
|
-
/**
|
|
584
|
-
* header scroll state fed by any scroll source; off, it leaves the header and content alone
|
|
585
|
-
*/
|
|
586
|
-
const useHeaderScrollState = (
|
|
587
|
-
{
|
|
588
|
-
navigation,
|
|
589
|
-
useShadowHeader = true,
|
|
590
|
-
gradientColor,
|
|
591
|
-
headerBackground,
|
|
592
|
-
}: HeaderScrollOptions,
|
|
593
|
-
enabled: boolean,
|
|
594
|
-
) => {
|
|
595
|
-
const layout = useScreenLayout();
|
|
596
|
-
const heightHeader = useHeaderHeight();
|
|
597
|
-
const scrollY = useSharedValue(0);
|
|
598
|
-
const hasSideBar = !!layout.sideBar;
|
|
599
|
-
const duo = enabled && hasSideBar;
|
|
600
|
-
|
|
601
|
-
const viewportHeight = useRef<number | undefined>(undefined);
|
|
602
|
-
const { headerHide, quickReturnOptions, snap, resync } = useDuoQuickReturn(
|
|
603
|
-
scrollY,
|
|
604
|
-
duo,
|
|
605
|
-
heightHeader,
|
|
606
|
-
);
|
|
607
|
-
|
|
608
|
-
useEffect(() => {
|
|
609
|
-
if (!enabled) {
|
|
610
|
-
return;
|
|
611
|
-
}
|
|
612
|
-
const options: StackNavigationOptions = hasSideBar
|
|
613
|
-
? {
|
|
614
|
-
...quickReturnOptions,
|
|
615
|
-
headerTransparent: true,
|
|
616
|
-
headerTintColor: Colors.black_17,
|
|
617
|
-
headerBackground: () => (
|
|
618
|
-
<DuoGlassBackground animatedValue={scrollY} />
|
|
619
|
-
),
|
|
620
|
-
headerTitle: (props: any) => <HeaderTitle {...props} />,
|
|
621
|
-
}
|
|
622
|
-
: {
|
|
623
|
-
header: undefined,
|
|
624
|
-
headerTransparent: false,
|
|
625
|
-
headerTintColor: Colors.black_17,
|
|
626
|
-
headerBackground: (props: any) => (
|
|
627
|
-
<HeaderBackground
|
|
628
|
-
{...props}
|
|
629
|
-
animatedValue={scrollY}
|
|
630
|
-
useShadowHeader={useShadowHeader}
|
|
631
|
-
headerBackground={headerBackground}
|
|
632
|
-
gradientColor={gradientColor}
|
|
633
|
-
/>
|
|
634
|
-
),
|
|
635
|
-
headerTitle: (props: any) => <HeaderTitle {...props} />,
|
|
636
|
-
};
|
|
637
|
-
|
|
638
|
-
navigation?.instance?.setOptions(options);
|
|
639
|
-
}, [
|
|
640
|
-
enabled,
|
|
641
|
-
navigation?.instance,
|
|
642
|
-
hasSideBar,
|
|
643
|
-
quickReturnOptions,
|
|
644
|
-
scrollY,
|
|
645
|
-
useShadowHeader,
|
|
646
|
-
headerBackground,
|
|
647
|
-
gradientColor,
|
|
648
|
-
]);
|
|
649
|
-
|
|
650
|
-
const setScrollOffset = useCallback(
|
|
651
|
-
(y: number) => {
|
|
652
|
-
resync(y);
|
|
653
|
-
scrollY.value = y;
|
|
654
|
-
},
|
|
655
|
-
[scrollY, resync],
|
|
656
|
-
);
|
|
657
|
-
|
|
658
|
-
const onScrollChange = useCallback(
|
|
659
|
-
({
|
|
660
|
-
y: offsetY,
|
|
661
|
-
contentHeight,
|
|
662
|
-
viewportHeight: height,
|
|
663
|
-
phase,
|
|
664
|
-
}: ScrollChange) => {
|
|
665
|
-
// the bottom bounce is not a reverse scroll
|
|
666
|
-
const maxY = Math.max(contentHeight - height, 0);
|
|
667
|
-
const y = Math.min(offsetY, maxY);
|
|
668
|
-
if (phase === 'takeOver') {
|
|
669
|
-
viewportHeight.current = height;
|
|
670
|
-
setScrollOffset(y);
|
|
671
|
-
return;
|
|
672
|
-
}
|
|
673
|
-
if (phase !== 'scroll') {
|
|
674
|
-
snap(offsetY);
|
|
675
|
-
return;
|
|
676
|
-
}
|
|
677
|
-
// the quick return resizes the viewport; pinned at the bottom, the offset
|
|
678
|
-
// iOS clamps to the new size is not a scroll
|
|
679
|
-
const resized = height !== viewportHeight.current;
|
|
680
|
-
viewportHeight.current = height;
|
|
681
|
-
if (resized && offsetY >= maxY - 1) {
|
|
682
|
-
resync(y);
|
|
683
|
-
}
|
|
684
|
-
scrollY.value = y;
|
|
685
|
-
},
|
|
686
|
-
[scrollY, snap, resync, setScrollOffset],
|
|
687
|
-
);
|
|
688
|
-
|
|
689
|
-
const { insetLeft, insetRight } = layout;
|
|
690
|
-
const contentStyle = useAnimatedStyle(
|
|
691
|
-
() =>
|
|
692
|
-
enabled
|
|
693
|
-
? {
|
|
694
|
-
paddingLeft: insetLeft,
|
|
695
|
-
paddingRight: insetRight,
|
|
696
|
-
paddingTop: hasSideBar ? heightHeader - headerHide.value : 0,
|
|
697
|
-
}
|
|
698
|
-
: { paddingLeft: 0, paddingRight: 0, paddingTop: 0 },
|
|
699
|
-
[enabled, hasSideBar, heightHeader, insetLeft, insetRight],
|
|
700
|
-
);
|
|
701
|
-
|
|
702
|
-
const background = duo ? (
|
|
703
|
-
<DuoScrollGradient
|
|
704
|
-
animatedValue={scrollY}
|
|
705
|
-
gradientColor={gradientColor}
|
|
706
|
-
headerBackground={headerBackground}
|
|
707
|
-
heightHeader={heightHeader}
|
|
708
|
-
followScroll
|
|
709
|
-
/>
|
|
710
|
-
) : null;
|
|
711
|
-
|
|
712
|
-
return { scrollY, onScrollChange, setScrollOffset, background, contentStyle };
|
|
713
|
-
};
|
|
714
|
-
|
|
715
481
|
export {
|
|
716
482
|
getStackOptions,
|
|
717
483
|
getModalOptions,
|
|
@@ -723,8 +489,6 @@ export {
|
|
|
723
489
|
useAppState,
|
|
724
490
|
useNativeCanGoBack,
|
|
725
491
|
useNormalizedSharedValue,
|
|
726
|
-
useDuoQuickReturn,
|
|
727
|
-
useHeaderScrollState,
|
|
728
492
|
SwipeBackHaptic,
|
|
729
493
|
isWhiteListDesignSystem,
|
|
730
494
|
};
|
package/Consts/theme.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type {Context, Theme} from '../Application/types';
|
|
2
|
+
import {Colors} from './colors+spacing+radius';
|
|
3
3
|
|
|
4
4
|
const defaultTheme: Theme = {
|
|
5
5
|
dark: false,
|
|
@@ -112,9 +112,10 @@ const defaultDarkTheme: Theme = {
|
|
|
112
112
|
const defaultContext: Context = {
|
|
113
113
|
theme: defaultTheme,
|
|
114
114
|
navigator: undefined,
|
|
115
|
+
showGrid: false,
|
|
115
116
|
translate: () => {
|
|
116
117
|
return '';
|
|
117
118
|
},
|
|
118
119
|
};
|
|
119
120
|
|
|
120
|
-
export {
|
|
121
|
+
export {defaultContext, defaultTheme, defaultDarkTheme};
|
package/Input/Input.tsx
CHANGED
|
@@ -6,8 +6,9 @@ import React, {
|
|
|
6
6
|
useState,
|
|
7
7
|
} from 'react';
|
|
8
8
|
import {
|
|
9
|
+
NativeSyntheticEvent,
|
|
9
10
|
TextInput,
|
|
10
|
-
|
|
11
|
+
TextInputFocusEventData,
|
|
11
12
|
TouchableOpacity,
|
|
12
13
|
View,
|
|
13
14
|
} from 'react-native';
|
|
@@ -101,12 +102,12 @@ const Input = forwardRef(
|
|
|
101
102
|
onChangeText?.(text);
|
|
102
103
|
};
|
|
103
104
|
|
|
104
|
-
const _onFocus = (e:
|
|
105
|
+
const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
105
106
|
setFocused(true);
|
|
106
107
|
onFocus?.(e);
|
|
107
108
|
};
|
|
108
109
|
|
|
109
|
-
const _onBlur = (e:
|
|
110
|
+
const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
110
111
|
setFocused(false);
|
|
111
112
|
onBlur?.(e);
|
|
112
113
|
};
|
package/Input/InputMoney.tsx
CHANGED
|
@@ -9,9 +9,10 @@ import React, {
|
|
|
9
9
|
useState,
|
|
10
10
|
} from 'react';
|
|
11
11
|
import {
|
|
12
|
+
NativeSyntheticEvent,
|
|
12
13
|
TextInput,
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
TextInputFocusEventData,
|
|
15
|
+
TextInputSelectionChangeEventData,
|
|
15
16
|
TouchableOpacity,
|
|
16
17
|
View,
|
|
17
18
|
} from 'react-native';
|
|
@@ -258,7 +259,9 @@ const InputMoney = forwardRef(
|
|
|
258
259
|
};
|
|
259
260
|
|
|
260
261
|
// Keeps the caret out of the currency suffix.
|
|
261
|
-
const _onSelectionChange = (
|
|
262
|
+
const _onSelectionChange = (
|
|
263
|
+
e: NativeSyntheticEvent<TextInputSelectionChangeEventData>,
|
|
264
|
+
) => {
|
|
262
265
|
props.onSelectionChange?.(e);
|
|
263
266
|
if (editingRef.current) return;
|
|
264
267
|
const selection = e.nativeEvent.selection;
|
|
@@ -280,12 +283,12 @@ const InputMoney = forwardRef(
|
|
|
280
283
|
});
|
|
281
284
|
};
|
|
282
285
|
|
|
283
|
-
const _onFocus = (e:
|
|
286
|
+
const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
284
287
|
setFocused(true);
|
|
285
288
|
onFocus?.(e);
|
|
286
289
|
};
|
|
287
290
|
|
|
288
|
-
const _onBlur = (e:
|
|
291
|
+
const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
289
292
|
setFocused(false);
|
|
290
293
|
onBlur?.(e);
|
|
291
294
|
};
|