@momo-kits/foundation 0.167.2-beta.1 → 0.168.1-beta.10
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 +113 -14
- package/Application/BottomTab/BottomTabBar.tsx +6 -3
- package/Application/BottomTab/CustomBottomTabItem.tsx +3 -5
- package/Application/BottomTab/DuoBarCompression.tsx +135 -0
- package/Application/BottomTab/DuoTabBar.tsx +537 -0
- package/Application/BottomTab/index.tsx +145 -134
- package/Application/Components/DuoGlassBackground.tsx +158 -0
- package/Application/Components/DuoQuickReturnHeader.tsx +42 -0
- package/Application/Components/HeaderAnimated.tsx +9 -3
- package/Application/Components/HeaderExtendHeader.tsx +70 -28
- package/Application/Components/HeaderLeft.tsx +38 -0
- package/Application/Components/HeaderRight.tsx +144 -9
- package/Application/Components/HeaderTitle.tsx +43 -7
- package/Application/Components/SearchHeader.tsx +20 -15
- package/Application/Components/SideBarButton.tsx +134 -0
- package/Application/ModalScreen.tsx +16 -2
- package/Application/NavigationContainer.tsx +22 -38
- package/Application/Navigator.ts +1 -3
- package/Application/StackScreen.tsx +2 -5
- package/Application/device.ts +29 -0
- package/Application/types.ts +10 -1
- package/Application/utils.tsx +10 -7
- package/Badge/Badge.tsx +2 -3
- package/Badge/BadgeDotAnimation.tsx +3 -3
- package/Button/index.tsx +11 -11
- package/Consts/theme.ts +3 -4
- package/Input/Input.tsx +3 -4
- package/Input/InputMoney.tsx +134 -196
- package/Input/InputOTP.tsx +9 -12
- package/Input/InputPhoneNumber.tsx +3 -4
- package/Input/InputSearch.tsx +17 -14
- package/Input/InputTextArea.tsx +3 -4
- package/Input/SystemTextInput.tsx +2 -3
- package/Input/TextTyping.tsx +11 -6
- package/Input/styles.ts +10 -0
- package/Input/utils.ts +2 -3
- package/Layout/Card.tsx +8 -26
- package/Layout/FloatingButton.tsx +3 -3
- package/Layout/Item.tsx +1 -10
- package/Layout/ReservedRegions.tsx +78 -0
- package/Layout/Screen.tsx +242 -48
- package/Layout/Section.tsx +5 -18
- package/Layout/index.ts +4 -4
- package/Layout/styles.ts +5 -0
- package/Layout/utils.ts +477 -5
- package/Pagination/Dot.tsx +3 -6
- package/Popup/PopupNotify.tsx +33 -22
- package/Popup/PopupPromotion.tsx +21 -8
- package/Popup/utils.ts +32 -0
- package/Radio/index.tsx +2 -3
- package/Text/utils.ts +1 -2
- package/Title/index.tsx +8 -11
- package/package.json +5 -2
- package/Layout/GridSystem.tsx +0 -137
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import React, { ReactNode, useContext } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
StyleProp,
|
|
4
|
+
StyleSheet,
|
|
5
|
+
TouchableOpacity,
|
|
6
|
+
View,
|
|
7
|
+
ViewStyle,
|
|
8
|
+
} from 'react-native';
|
|
9
|
+
import { NavigationButtonProps } from '../types';
|
|
10
|
+
import { ApplicationContext } from '../../Context';
|
|
11
|
+
import { Colors, Radius, Shadow, Spacing } from '../../Consts';
|
|
12
|
+
import { Icon } from '../../Icon';
|
|
13
|
+
import { BadgeDot } from '../../Badge';
|
|
14
|
+
import { DuoMetrics } from '../../Layout/utils';
|
|
15
|
+
|
|
16
|
+
const SIDE_BAR_ICON_SIZE = 24;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* glass material for side bar controls: dark glass under light icons (banner headers),
|
|
20
|
+
* light glass otherwise
|
|
21
|
+
*/
|
|
22
|
+
const getGlassStyle = (tintColor?: string) => {
|
|
23
|
+
const isLightTint = tintColor === Colors.black_01 || tintColor === 'white';
|
|
24
|
+
return isLightTint ? styles.glassDark : styles.glassLight;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 48pt glass circle used for a single control in the iPhone Duo side bar
|
|
29
|
+
*/
|
|
30
|
+
const SideBarButton: React.FC<NavigationButtonProps> = ({
|
|
31
|
+
icon,
|
|
32
|
+
tintColor,
|
|
33
|
+
showBadge = false,
|
|
34
|
+
style,
|
|
35
|
+
...props
|
|
36
|
+
}) => {
|
|
37
|
+
const { theme } = useContext(ApplicationContext);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<View>
|
|
41
|
+
<TouchableOpacity
|
|
42
|
+
{...props}
|
|
43
|
+
style={[styles.control, getGlassStyle(tintColor), style]}
|
|
44
|
+
>
|
|
45
|
+
<Icon
|
|
46
|
+
source={icon}
|
|
47
|
+
color={tintColor ?? theme.colors.text.default}
|
|
48
|
+
size={SIDE_BAR_ICON_SIZE}
|
|
49
|
+
/>
|
|
50
|
+
</TouchableOpacity>
|
|
51
|
+
{showBadge && <BadgeDot size={'small'} style={styles.badgeDot} />}
|
|
52
|
+
</View>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 48pt glass capsule grouping related controls, one item per 50pt, laid out vertically
|
|
58
|
+
* in the side bar or horizontally on a header row
|
|
59
|
+
*/
|
|
60
|
+
const SideBarGroup: React.FC<{
|
|
61
|
+
tintColor?: string;
|
|
62
|
+
horizontal?: boolean;
|
|
63
|
+
style?: StyleProp<ViewStyle>;
|
|
64
|
+
children: ReactNode;
|
|
65
|
+
}> = ({ tintColor, horizontal = false, style, children }) => {
|
|
66
|
+
const count = React.Children.toArray(children).length;
|
|
67
|
+
const { itemPitch, controlSize } = DuoMetrics;
|
|
68
|
+
const length = count > 1 ? count * itemPitch : controlSize;
|
|
69
|
+
let sizeStyle: ViewStyle = { height: length };
|
|
70
|
+
if (horizontal) {
|
|
71
|
+
sizeStyle = { width: length, flexDirection: 'row' };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<View style={[styles.control, getGlassStyle(tintColor), sizeStyle, style]}>
|
|
76
|
+
{children}
|
|
77
|
+
</View>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* icon item inside a SideBarGroup
|
|
83
|
+
*/
|
|
84
|
+
const SideBarGroupItem: React.FC<NavigationButtonProps> = ({
|
|
85
|
+
icon,
|
|
86
|
+
tintColor,
|
|
87
|
+
...props
|
|
88
|
+
}) => {
|
|
89
|
+
const { theme } = useContext(ApplicationContext);
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<TouchableOpacity {...props} style={styles.groupItem}>
|
|
93
|
+
<Icon
|
|
94
|
+
source={icon}
|
|
95
|
+
color={tintColor ?? theme.colors.text.default}
|
|
96
|
+
size={SIDE_BAR_ICON_SIZE}
|
|
97
|
+
/>
|
|
98
|
+
</TouchableOpacity>
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const styles = StyleSheet.create({
|
|
103
|
+
control: {
|
|
104
|
+
width: DuoMetrics.controlSize,
|
|
105
|
+
height: DuoMetrics.controlSize,
|
|
106
|
+
borderRadius: Radius.XL,
|
|
107
|
+
justifyContent: 'center',
|
|
108
|
+
alignItems: 'center',
|
|
109
|
+
},
|
|
110
|
+
glassLight: {
|
|
111
|
+
backgroundColor: Colors.black_01 + 'D9',
|
|
112
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
113
|
+
borderColor: Colors.black_20 + '14',
|
|
114
|
+
...Shadow.Light,
|
|
115
|
+
},
|
|
116
|
+
glassDark: {
|
|
117
|
+
backgroundColor: Colors.black_20 + '80',
|
|
118
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
119
|
+
borderColor: Colors.black_01 + '33',
|
|
120
|
+
},
|
|
121
|
+
groupItem: {
|
|
122
|
+
flex: 1,
|
|
123
|
+
alignSelf: 'stretch',
|
|
124
|
+
justifyContent: 'center',
|
|
125
|
+
alignItems: 'center',
|
|
126
|
+
},
|
|
127
|
+
badgeDot: {
|
|
128
|
+
position: 'absolute',
|
|
129
|
+
top: Spacing.XXS,
|
|
130
|
+
right: Spacing.XXS,
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
export { SideBarButton, SideBarGroup, SideBarGroupItem };
|
|
@@ -8,15 +8,18 @@ import {
|
|
|
8
8
|
Platform,
|
|
9
9
|
Pressable,
|
|
10
10
|
StyleSheet,
|
|
11
|
+
useWindowDimensions,
|
|
11
12
|
View,
|
|
12
13
|
} from 'react-native';
|
|
14
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
13
15
|
|
|
14
16
|
import { ApplicationContext, MiniAppContext } from '../Context';
|
|
15
17
|
import { Styles } from '../Consts';
|
|
16
18
|
import Navigation from './Navigation';
|
|
17
19
|
import { ModalParams } from './types';
|
|
18
20
|
import BottomSheet from './BottomSheet';
|
|
19
|
-
import {
|
|
21
|
+
import { getDuoTopInset, isIPhoneDuo } from './device';
|
|
22
|
+
import { scheduleOnRN } from 'react-native-worklets';
|
|
20
23
|
|
|
21
24
|
const ModalScreen: React.FC<any> = props => {
|
|
22
25
|
if (props.route?.params?.isBottomSheet) {
|
|
@@ -37,6 +40,8 @@ const Modal: React.FC<ModalParams> = props => {
|
|
|
37
40
|
title,
|
|
38
41
|
} = props.route.params;
|
|
39
42
|
const Component = useRef(screen).current;
|
|
43
|
+
const insets = useSafeAreaInsets();
|
|
44
|
+
const windowSize = useWindowDimensions();
|
|
40
45
|
|
|
41
46
|
/**
|
|
42
47
|
* Fire auto_popup_displayed tracking event on mount
|
|
@@ -106,7 +111,7 @@ const Modal: React.FC<ModalParams> = props => {
|
|
|
106
111
|
}),
|
|
107
112
|
]).start(() => {
|
|
108
113
|
navigator?.pop();
|
|
109
|
-
|
|
114
|
+
scheduleOnRN(callback);
|
|
110
115
|
});
|
|
111
116
|
},
|
|
112
117
|
[navigator, opacity, scale],
|
|
@@ -147,6 +152,15 @@ const Modal: React.FC<ModalParams> = props => {
|
|
|
147
152
|
opacity,
|
|
148
153
|
transform: [{ scale }],
|
|
149
154
|
},
|
|
155
|
+
// center below the side status bar and above the home indicator
|
|
156
|
+
isIPhoneDuo() && {
|
|
157
|
+
marginTop: getDuoTopInset(
|
|
158
|
+
insets,
|
|
159
|
+
windowSize.width,
|
|
160
|
+
windowSize.height,
|
|
161
|
+
),
|
|
162
|
+
marginBottom: insets.bottom,
|
|
163
|
+
},
|
|
150
164
|
modalStyle,
|
|
151
165
|
]}
|
|
152
166
|
>
|
|
@@ -2,7 +2,6 @@ import React, { useContext, useEffect, useRef, useState } from 'react';
|
|
|
2
2
|
import {
|
|
3
3
|
SafeAreaInsetsContext,
|
|
4
4
|
SafeAreaProvider,
|
|
5
|
-
useSafeAreaInsets,
|
|
6
5
|
} from 'react-native-safe-area-context';
|
|
7
6
|
import {
|
|
8
7
|
NavigationContainer as ReactNavigationContainer,
|
|
@@ -13,7 +12,6 @@ import {
|
|
|
13
12
|
StackNavigationOptions,
|
|
14
13
|
TransitionPresets,
|
|
15
14
|
} from '@react-navigation/stack';
|
|
16
|
-
import { DeviceEventEmitter } from 'react-native';
|
|
17
15
|
import StackScreen from './StackScreen';
|
|
18
16
|
import ModalScreen from './ModalScreen';
|
|
19
17
|
import Navigator from './Navigator';
|
|
@@ -32,6 +30,9 @@ import { HeaderRight } from './Components/HeaderRight';
|
|
|
32
30
|
import { HeaderTitle } from './Components/HeaderTitle';
|
|
33
31
|
import { HeaderBackground } from './Components/HeaderBackground';
|
|
34
32
|
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';
|
|
35
36
|
|
|
36
37
|
const Stack = createStackNavigator();
|
|
37
38
|
|
|
@@ -77,17 +78,19 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
|
|
|
77
78
|
frame: { x: 0, y: 0, width: 0, height: 0 },
|
|
78
79
|
}}
|
|
79
80
|
>
|
|
80
|
-
<
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
81
|
+
<ReservedRegionsProvider>
|
|
82
|
+
<MiniAppContext.Provider value={mergedContext}>
|
|
83
|
+
<Navigation
|
|
84
|
+
screen={screen}
|
|
85
|
+
theme={theme}
|
|
86
|
+
options={options}
|
|
87
|
+
maxApi={maxApi}
|
|
88
|
+
setCurrentContext={setCurrentContext}
|
|
89
|
+
initialParams={initialParams}
|
|
90
|
+
localize={localize}
|
|
91
|
+
/>
|
|
92
|
+
</MiniAppContext.Provider>
|
|
93
|
+
</ReservedRegionsProvider>
|
|
91
94
|
</SafeAreaProvider>
|
|
92
95
|
);
|
|
93
96
|
};
|
|
@@ -105,8 +108,7 @@ const Navigation: React.FC<any> = ({
|
|
|
105
108
|
const navigationRef = useRef<any>(null);
|
|
106
109
|
const isReady = useRef(false);
|
|
107
110
|
const navigator = useRef(new Navigator(navigationRef, isReady));
|
|
108
|
-
const
|
|
109
|
-
const insets = useSafeAreaInsets();
|
|
111
|
+
const headerRowOptions = getHeaderRowOptions(useScreenLayout());
|
|
110
112
|
const syncCanGoBack = useNativeCanGoBack();
|
|
111
113
|
const isWhiteList = isWhiteListDesignSystem(context);
|
|
112
114
|
const fontFamily = isWhiteList ? 'MomoTrustSans' : 'SFProText';
|
|
@@ -126,23 +128,6 @@ const Navigation: React.FC<any> = ({
|
|
|
126
128
|
*/
|
|
127
129
|
navigator.current.maxApi = maxApi;
|
|
128
130
|
|
|
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
|
-
|
|
146
131
|
/**
|
|
147
132
|
* translate context method
|
|
148
133
|
* @param data
|
|
@@ -172,7 +157,6 @@ const Navigation: React.FC<any> = ({
|
|
|
172
157
|
headerBackground,
|
|
173
158
|
},
|
|
174
159
|
},
|
|
175
|
-
showGrid,
|
|
176
160
|
translate,
|
|
177
161
|
}}
|
|
178
162
|
>
|
|
@@ -221,9 +205,7 @@ const Navigation: React.FC<any> = ({
|
|
|
221
205
|
gestureEnabled: false,
|
|
222
206
|
headerTitleAlign: 'center',
|
|
223
207
|
headerTintColor: theme.colors.text.default,
|
|
224
|
-
|
|
225
|
-
height: 52 + insets.top,
|
|
226
|
-
},
|
|
208
|
+
...headerRowOptions,
|
|
227
209
|
}}
|
|
228
210
|
>
|
|
229
211
|
<Stack.Screen
|
|
@@ -246,11 +228,13 @@ const Navigation: React.FC<any> = ({
|
|
|
246
228
|
cardStyle: {
|
|
247
229
|
backgroundColor: theme.colors.background.default,
|
|
248
230
|
},
|
|
249
|
-
headerLeft: (props: any) => <HeaderLeft {...props} />,
|
|
231
|
+
headerLeft: (props: any) => <HeaderLeft {...props} floating />,
|
|
250
232
|
headerBackground: (props: any) => (
|
|
251
233
|
<HeaderBackground {...props} />
|
|
252
234
|
),
|
|
253
|
-
headerRight: (props: any) =>
|
|
235
|
+
headerRight: (props: any) => (
|
|
236
|
+
<HeaderRight {...props} floating />
|
|
237
|
+
),
|
|
254
238
|
headerTintColor: Colors.black_17,
|
|
255
239
|
...TransitionPresets.ModalTransition,
|
|
256
240
|
}}
|
package/Application/Navigator.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { useHeaderHeight } from '@react-navigation/elements';
|
|
|
4
4
|
import { ScreenTrackingParams } from './types';
|
|
5
5
|
import Navigation from './Navigation';
|
|
6
6
|
import { ApplicationContext, MiniAppContext, ScreenContext } from '../Context';
|
|
7
|
-
import { GridSystem } from '../Layout';
|
|
8
7
|
import { version } from '../package.json';
|
|
9
8
|
import { SwipeBackHaptic, useAppState } from './utils';
|
|
10
9
|
import { TooltipPortalHost, TooltipPortalProvider } from './TooltipPortal';
|
|
@@ -17,7 +16,7 @@ const runAfterInteractions = InteractionManager.runAfterInteractions;
|
|
|
17
16
|
* @constructor
|
|
18
17
|
*/
|
|
19
18
|
const StackScreen: React.FC<any> = props => {
|
|
20
|
-
const {
|
|
19
|
+
const { navigator } = useContext(ApplicationContext);
|
|
21
20
|
const tracking = useRef<any>({
|
|
22
21
|
mounted: false,
|
|
23
22
|
timeoutLoad: undefined,
|
|
@@ -42,6 +41,7 @@ const StackScreen: React.FC<any> = props => {
|
|
|
42
41
|
});
|
|
43
42
|
const widgets = useRef<any>([]);
|
|
44
43
|
const context = useContext<any>(MiniAppContext);
|
|
44
|
+
|
|
45
45
|
const {
|
|
46
46
|
screen: Component,
|
|
47
47
|
options,
|
|
@@ -411,10 +411,7 @@ const StackScreen: React.FC<any> = props => {
|
|
|
411
411
|
>
|
|
412
412
|
<TooltipPortalProvider>
|
|
413
413
|
<Component heightHeader={heightHeader} {...data} />
|
|
414
|
-
{showGrid && <GridSystem />}
|
|
415
414
|
<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 */}
|
|
418
415
|
<SwipeBackHaptic />
|
|
419
416
|
</TooltipPortalProvider>
|
|
420
417
|
</ScreenContext.Provider>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Dimensions, Platform, ScaledSize } from 'react-native';
|
|
2
|
+
import type { EdgeInsets } from 'react-native-safe-area-context';
|
|
3
|
+
|
|
4
|
+
// widest short side of any single-display iPhone
|
|
5
|
+
const IPHONE_MAX_SHORT_SIDE = 440;
|
|
6
|
+
|
|
7
|
+
// iPhone Duo reports idiom "phone"; 'screen' stays on the outer display, so it
|
|
8
|
+
// still matches when Split View narrows the window
|
|
9
|
+
const isIPhoneDuo = () => {
|
|
10
|
+
if (Platform.OS !== 'ios' || Platform.isPad) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
const shortSide = (size: ScaledSize) => Math.min(size.width, size.height);
|
|
14
|
+
return (
|
|
15
|
+
Math.max(
|
|
16
|
+
shortSide(Dimensions.get('screen')),
|
|
17
|
+
shortSide(Dimensions.get('window')),
|
|
18
|
+
) > IPHONE_MAX_SHORT_SIDE
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// portrait side status bar is about twice as tall as its inset is wide
|
|
23
|
+
const getDuoTopInset = (insets: EdgeInsets, width: number, height: number) =>
|
|
24
|
+
Math.max(
|
|
25
|
+
insets.top,
|
|
26
|
+
height > width ? Math.max(insets.left, insets.right) * 2 : 0,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export { isIPhoneDuo, getDuoTopInset };
|
package/Application/types.ts
CHANGED
|
@@ -117,7 +117,6 @@ export type Context = {
|
|
|
117
117
|
[key: string]: any;
|
|
118
118
|
theme: Theme;
|
|
119
119
|
navigator?: NavigatorProps;
|
|
120
|
-
showGrid?: boolean;
|
|
121
120
|
translate?: (data: string | { vi: string; en: string }) => string;
|
|
122
121
|
};
|
|
123
122
|
|
|
@@ -258,6 +257,11 @@ export interface HeaderBackProps extends NavigationButtonProps {
|
|
|
258
257
|
preventBack?: PopupNotifyProps;
|
|
259
258
|
onPressLeftHeader?: () => void;
|
|
260
259
|
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;
|
|
261
265
|
}
|
|
262
266
|
|
|
263
267
|
export type HeaderBackgroundProps = {
|
|
@@ -329,6 +333,11 @@ export type BottomTabProps = {
|
|
|
329
333
|
blur?: (e: EventArg<'blur', false, unknown>) => void;
|
|
330
334
|
};
|
|
331
335
|
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';
|
|
332
341
|
};
|
|
333
342
|
|
|
334
343
|
export type FloatingButtonProps = {
|
package/Application/utils.tsx
CHANGED
|
@@ -73,8 +73,8 @@ const getStackOptions = (): StackNavigationOptions => {
|
|
|
73
73
|
left: Spacing.S,
|
|
74
74
|
},
|
|
75
75
|
headerBackground: (props: any) => <HeaderBackground {...props} />,
|
|
76
|
-
headerLeft: (props: any) => <HeaderLeft {...props} />,
|
|
77
|
-
headerRight: (props: any) => <HeaderRight {...props} />,
|
|
76
|
+
headerLeft: (props: any) => <HeaderLeft {...props} floating />,
|
|
77
|
+
headerRight: (props: any) => <HeaderRight {...props} floating />,
|
|
78
78
|
headerTintColor: Colors.black_17,
|
|
79
79
|
gestureEnabled: Platform.OS === 'ios',
|
|
80
80
|
...TransitionPresets.SlideFromRightIOS,
|
|
@@ -129,6 +129,7 @@ const getOptions = (
|
|
|
129
129
|
preventBack={params.preventBack}
|
|
130
130
|
onPressLeftHeader={params.onPressLeftHeader}
|
|
131
131
|
onBackHandler={params.onBackHandler}
|
|
132
|
+
floating
|
|
132
133
|
/>
|
|
133
134
|
);
|
|
134
135
|
if (params.hiddenBack) {
|
|
@@ -167,7 +168,9 @@ const getOptions = (
|
|
|
167
168
|
...options,
|
|
168
169
|
...{
|
|
169
170
|
headerRight: (props: any) => {
|
|
170
|
-
return
|
|
171
|
+
return (
|
|
172
|
+
<HeaderRight {...props} headerRight={params.headerRight} floating />
|
|
173
|
+
);
|
|
171
174
|
},
|
|
172
175
|
},
|
|
173
176
|
};
|
|
@@ -394,10 +397,10 @@ const getSwipeGestureValue = (
|
|
|
394
397
|
| Animated.Value
|
|
395
398
|
| undefined;
|
|
396
399
|
|
|
397
|
-
|
|
398
|
-
typeof parent?.
|
|
399
|
-
|
|
400
|
-
|
|
400
|
+
const isListenable =
|
|
401
|
+
typeof parent?.addListener === 'function' &&
|
|
402
|
+
typeof parent?.removeListener === 'function';
|
|
403
|
+
return isListenable ? parent : undefined;
|
|
401
404
|
};
|
|
402
405
|
|
|
403
406
|
const readAnimatedValue = (node: unknown, fallback: number): number => {
|
package/Badge/Badge.tsx
CHANGED
|
@@ -75,9 +75,8 @@ const Badge: FC<BadgeProps> = ({
|
|
|
75
75
|
return label.toString();
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
: theme.colors.warning.primary;
|
|
78
|
+
const { error, warning } = theme.colors;
|
|
79
|
+
let badgeColor = isNumber() ? error.primary : warning.primary;
|
|
81
80
|
|
|
82
81
|
if (backgroundColor && isValidatedColor()) {
|
|
83
82
|
badgeColor = backgroundColor;
|
|
@@ -19,9 +19,9 @@ const BadgeDotAnimation = ({ size, style }: BadgeDotProps) => {
|
|
|
19
19
|
const waveScaleAnim = useSharedValue(1);
|
|
20
20
|
const waveOpacityAnim = useSharedValue(0);
|
|
21
21
|
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
const waveStyle =
|
|
22
|
+
const isSmall = size === 'small';
|
|
23
|
+
const dotStyle = isSmall ? styles.dotAnimationSmall : styles.dotAnimation;
|
|
24
|
+
const waveStyle = isSmall ? styles.waveSmall : styles.wave;
|
|
25
25
|
|
|
26
26
|
useEffect(() => {
|
|
27
27
|
const springCfg = { damping: 5, stiffness: 30, mass: 1 };
|
package/Button/index.tsx
CHANGED
|
@@ -272,6 +272,16 @@ const Button: FC<ButtonProps> = ({
|
|
|
272
272
|
const showLoading = shouldShowLoading(iconLeft, iconRight, isLeft);
|
|
273
273
|
|
|
274
274
|
if (loading && showLoading) {
|
|
275
|
+
let webStyle;
|
|
276
|
+
if (Platform.OS === 'web') {
|
|
277
|
+
webStyle = {
|
|
278
|
+
width: iconSize,
|
|
279
|
+
height: iconSize,
|
|
280
|
+
marginRight: isLeft ? space : 0,
|
|
281
|
+
marginLeft: isLeft ? 0 : space,
|
|
282
|
+
borderRadius: Spacing.M,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
275
285
|
return (
|
|
276
286
|
<LottieView
|
|
277
287
|
ref={animationRef}
|
|
@@ -284,17 +294,7 @@ const Button: FC<ButtonProps> = ({
|
|
|
284
294
|
{ keypath: 'base pink 2.Ellipse 1.Stroke 1', color: textColor },
|
|
285
295
|
]}
|
|
286
296
|
style={[style, { borderRadius: Spacing.M }]}
|
|
287
|
-
webStyle={
|
|
288
|
-
Platform.OS === 'web'
|
|
289
|
-
? {
|
|
290
|
-
width: iconSize,
|
|
291
|
-
height: iconSize,
|
|
292
|
-
marginRight: isLeft ? space : 0,
|
|
293
|
-
marginLeft: isLeft ? 0 : space,
|
|
294
|
-
borderRadius: Spacing.M,
|
|
295
|
-
}
|
|
296
|
-
: undefined
|
|
297
|
-
}
|
|
297
|
+
webStyle={webStyle}
|
|
298
298
|
/>
|
|
299
299
|
);
|
|
300
300
|
}
|
package/Consts/theme.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {Context, Theme} from '../Application/types';
|
|
2
|
-
import {Colors} from './colors+spacing+radius';
|
|
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,10 +112,9 @@ const defaultDarkTheme: Theme = {
|
|
|
112
112
|
const defaultContext: Context = {
|
|
113
113
|
theme: defaultTheme,
|
|
114
114
|
navigator: undefined,
|
|
115
|
-
showGrid: false,
|
|
116
115
|
translate: () => {
|
|
117
116
|
return '';
|
|
118
117
|
},
|
|
119
118
|
};
|
|
120
119
|
|
|
121
|
-
export {defaultContext, defaultTheme, defaultDarkTheme};
|
|
120
|
+
export { defaultContext, defaultTheme, defaultDarkTheme };
|
package/Input/Input.tsx
CHANGED
|
@@ -6,9 +6,8 @@ import React, {
|
|
|
6
6
|
useState,
|
|
7
7
|
} from 'react';
|
|
8
8
|
import {
|
|
9
|
-
NativeSyntheticEvent,
|
|
10
9
|
TextInput,
|
|
11
|
-
|
|
10
|
+
TextInputFocusEvent,
|
|
12
11
|
TouchableOpacity,
|
|
13
12
|
View,
|
|
14
13
|
} from 'react-native';
|
|
@@ -102,12 +101,12 @@ const Input = forwardRef(
|
|
|
102
101
|
onChangeText?.(text);
|
|
103
102
|
};
|
|
104
103
|
|
|
105
|
-
const _onFocus = (e:
|
|
104
|
+
const _onFocus = (e: TextInputFocusEvent) => {
|
|
106
105
|
setFocused(true);
|
|
107
106
|
onFocus?.(e);
|
|
108
107
|
};
|
|
109
108
|
|
|
110
|
-
const _onBlur = (e:
|
|
109
|
+
const _onBlur = (e: TextInputFocusEvent) => {
|
|
111
110
|
setFocused(false);
|
|
112
111
|
onBlur?.(e);
|
|
113
112
|
};
|