@momo-kits/foundation 0.169.1 → 0.169.3-beta.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.hooks.ts +17 -37
- package/Application/BottomSheet.parts.tsx +81 -165
- package/Application/BottomSheet.styles.ts +7 -23
- package/Application/BottomSheet.tsx +15 -67
- package/Application/BottomTab/ActiveIndicator.tsx +90 -0
- package/Application/BottomTab/BottomTabBar.styles.ts +48 -43
- package/Application/BottomTab/BottomTabBar.tsx +229 -223
- package/Application/BottomTab/BottomTabInset.tsx +14 -0
- package/Application/BottomTab/CurvedContainer.tsx +153 -0
- package/Application/BottomTab/CustomBottomTabItem.tsx +132 -108
- package/Application/BottomTab/DuoBarCompression.tsx +4 -12
- package/Application/BottomTab/DuoRailTabBar.tsx +174 -96
- package/Application/BottomTab/DuoTabBar.styles.ts +42 -84
- package/Application/BottomTab/DuoTabBar.tsx +35 -115
- package/Application/BottomTab/TabBarIcon.tsx +160 -72
- package/Application/BottomTab/TabScreen.tsx +48 -61
- package/Application/BottomTab/index.tsx +85 -125
- package/Application/BottomTab/metrics.ts +164 -0
- package/Application/BottomTab/tabItems.ts +46 -0
- package/Application/BottomTab/usePressLift.ts +32 -0
- package/Application/ModalIconButton.tsx +66 -0
- package/Application/ModalScreen.tsx +32 -15
- package/Application/__tests__/modalLayout.test.ts +128 -0
- package/Application/index.ts +10 -0
- package/Application/modalLayout.ts +177 -0
- package/Application/types.tabs.ts +5 -0
- package/Application/utils.ts +0 -36
- package/Layout/ReservedRegions.tsx +21 -4
- package/Layout/Screen.tsx +11 -2
- package/Layout/index.ts +2 -0
- package/Popup/PopupNotify.tsx +38 -68
- package/Popup/PopupPromotion.tsx +5 -4
- package/Popup/utils.ts +1 -26
- package/package.json +2 -1
- package/Application/BottomTab/DuoTabBar.parts.tsx +0 -202
- package/Application/BottomTab/badge.ts +0 -41
- package/Application/BottomTab/hooks.ts +0 -358
- package/Application/BottomTab/index.styles.ts +0 -30
|
@@ -16,43 +16,24 @@ import {
|
|
|
16
16
|
} from 'react-native';
|
|
17
17
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
18
18
|
import { useHeaderHeight } from '@react-navigation/elements';
|
|
19
|
-
import { Spacing } from '../Consts';
|
|
20
|
-
import { DuoMetrics, useScreenLayout } from '../Layout/utils';
|
|
21
19
|
import { scheduleOnRN } from 'react-native-worklets';
|
|
22
20
|
import { BottomSheetParams, NavigatorProps } from './types';
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
21
|
+
import { isIPhoneDuo } from './utils';
|
|
22
|
+
import { useModalLayout } from './modalLayout';
|
|
25
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Sheet geometry for the current window: foldable placement and size from
|
|
26
|
+
* `useModalLayout`, plus the insets and offsets the keyboard handling needs.
|
|
27
|
+
*/
|
|
26
28
|
export const useBottomSheetLayout = () => {
|
|
27
29
|
const windowSize = useWindowDimensions();
|
|
28
30
|
const isDuo = isIPhoneDuo();
|
|
29
|
-
const
|
|
30
|
-
isDuo &&
|
|
31
|
-
Math.min(windowSize.width, windowSize.height) >= DUO_REGULAR_MIN_WIDTH;
|
|
32
|
-
const isDuoFloating = isDuo && !isDuoCentered;
|
|
33
|
-
const { sideBar } = useScreenLayout();
|
|
34
|
-
const sideColumnWidth = (sideBar?.width ?? 0) - Spacing.M;
|
|
35
|
-
const sideColumn =
|
|
36
|
-
isDuoFloating &&
|
|
37
|
-
sideColumnWidth >= DuoMetrics.controlSize + Spacing.M &&
|
|
38
|
-
sideBar
|
|
39
|
-
? sideBar
|
|
40
|
-
: undefined;
|
|
41
|
-
const hasSideColumn = !!sideColumn;
|
|
31
|
+
const { isFoldable, placement, sheet, scrimOpacity } = useModalLayout();
|
|
42
32
|
// 'screen' is the outer display on iPhone Duo, even when unfolded
|
|
43
33
|
const screenHeight = Dimensions.get('screen').height;
|
|
44
34
|
const heightDevice = isDuo ? windowSize.height : screenHeight;
|
|
45
35
|
const insets = useSafeAreaInsets();
|
|
46
36
|
const heightHeader = useHeaderHeight();
|
|
47
|
-
const topGap = Math.max(
|
|
48
|
-
sideColumn
|
|
49
|
-
? insets.top
|
|
50
|
-
: getDuoTopInset(insets, windowSize.width, windowSize.height),
|
|
51
|
-
Spacing.XL,
|
|
52
|
-
);
|
|
53
|
-
const sideInsetLeft = isDuoFloating ? getSideInset(insets.left) : 0;
|
|
54
|
-
const sideInsetRight = isDuoFloating ? getSideInset(insets.right) : 0;
|
|
55
|
-
const indicatorShift = (sideInsetRight - sideInsetLeft) / 2;
|
|
56
37
|
const isIOS = Platform.OS === 'ios';
|
|
57
38
|
const bottomInset = isIOS ? Math.min(insets.bottom, 21) : insets.bottom;
|
|
58
39
|
const keyboardOffset = heightHeader - bottomInset;
|
|
@@ -60,17 +41,11 @@ export const useBottomSheetLayout = () => {
|
|
|
60
41
|
return {
|
|
61
42
|
windowSize,
|
|
62
43
|
isDuo,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
hasSideColumn,
|
|
44
|
+
isFoldable,
|
|
45
|
+
placement,
|
|
46
|
+
sheet,
|
|
47
|
+
scrimOpacity,
|
|
68
48
|
heightDevice,
|
|
69
|
-
insets,
|
|
70
|
-
topGap,
|
|
71
|
-
sideInsetLeft,
|
|
72
|
-
sideInsetRight,
|
|
73
|
-
indicatorShift,
|
|
74
49
|
bottomInset,
|
|
75
50
|
keyboardOffset,
|
|
76
51
|
};
|
|
@@ -124,9 +99,14 @@ export const useDuoKeyboardLift = (
|
|
|
124
99
|
return keyboardLift;
|
|
125
100
|
};
|
|
126
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Slide of the sheet and fade of the scrim behind it, up to the
|
|
104
|
+
* `scrimOpacity` of the modal spec (lighter on foldables).
|
|
105
|
+
*/
|
|
127
106
|
export const useSheetAnimatedStyles = (
|
|
128
107
|
translateY: SharedValue<number>,
|
|
129
108
|
heightDevice: number,
|
|
109
|
+
scrimOpacity: number,
|
|
130
110
|
) => {
|
|
131
111
|
const animatedStyle = useAnimatedStyle(() => {
|
|
132
112
|
return {
|
|
@@ -139,7 +119,7 @@ export const useSheetAnimatedStyles = (
|
|
|
139
119
|
opacity: interpolate(
|
|
140
120
|
translateY.value,
|
|
141
121
|
[0, heightDevice],
|
|
142
|
-
[
|
|
122
|
+
[scrimOpacity, 0],
|
|
143
123
|
Extrapolation.CLAMP,
|
|
144
124
|
),
|
|
145
125
|
};
|
|
@@ -1,169 +1,90 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
ScaledSize,
|
|
5
|
-
TouchableOpacity,
|
|
6
|
-
View,
|
|
7
|
-
} from 'react-native';
|
|
8
|
-
import type { EdgeInsets } from 'react-native-safe-area-context';
|
|
9
|
-
import { Radius, Spacing, Styles } from '../Consts';
|
|
2
|
+
import { PanResponderInstance, View, ViewStyle } from 'react-native';
|
|
3
|
+
import { Spacing, Styles } from '../Consts';
|
|
10
4
|
import layoutStyles from '../Layout/styles';
|
|
11
5
|
import { Text } from '../Text';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
INDICATOR_HEIGHT,
|
|
17
|
-
SIDE_COLUMN_OFFSET,
|
|
18
|
-
styles,
|
|
19
|
-
} from './BottomSheet.styles';
|
|
6
|
+
import { INDICATOR_HEIGHT, styles } from './BottomSheet.styles';
|
|
7
|
+
import { ModalIconButton } from './ModalIconButton';
|
|
8
|
+
import { type ModalLayout } from './modalLayout';
|
|
20
9
|
import { BottomSheetParams, Theme } from './types';
|
|
21
10
|
|
|
22
|
-
type
|
|
11
|
+
type SheetHeaderParams = {
|
|
23
12
|
panHandlers: PanResponderInstance['panHandlers'];
|
|
24
|
-
indicatorShift: number;
|
|
25
13
|
useDivider: boolean;
|
|
26
14
|
theme: Theme;
|
|
27
|
-
hasSideColumn: boolean;
|
|
28
15
|
showBack: boolean;
|
|
29
16
|
onPressBack: () => void;
|
|
30
17
|
onPressClose: () => void;
|
|
31
18
|
iconBack: string;
|
|
32
19
|
options: BottomSheetParams['options'];
|
|
33
20
|
leftOptions: BottomSheetParams['leftOptions'];
|
|
34
|
-
sideColumn?: SideBarLayout;
|
|
35
|
-
windowHeight: number;
|
|
36
|
-
sheetTop: number;
|
|
37
|
-
sideColumnHeight: number;
|
|
38
|
-
sideColumnWidth: number;
|
|
39
21
|
};
|
|
40
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Drag handle and header row: back, title (or a custom header) and close, with
|
|
25
|
+
* the 32 modal icon buttons on every device.
|
|
26
|
+
*/
|
|
41
27
|
export const renderSheetHeader = ({
|
|
42
28
|
panHandlers,
|
|
43
|
-
indicatorShift,
|
|
44
29
|
useDivider,
|
|
45
30
|
theme,
|
|
46
|
-
hasSideColumn,
|
|
47
31
|
showBack,
|
|
48
32
|
onPressBack,
|
|
49
33
|
onPressClose,
|
|
50
34
|
iconBack,
|
|
51
35
|
options,
|
|
52
36
|
leftOptions,
|
|
53
|
-
}:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
<View style={{ height: INDICATOR_HEIGHT }}>
|
|
58
|
-
<View
|
|
59
|
-
style={[
|
|
60
|
-
styles.indicator,
|
|
61
|
-
indicatorShift !== 0 && {
|
|
62
|
-
transform: [{ translateX: indicatorShift }],
|
|
63
|
-
},
|
|
64
|
-
]}
|
|
65
|
-
/>
|
|
66
|
-
</View>
|
|
67
|
-
<View
|
|
68
|
-
style={[
|
|
69
|
-
styles.header,
|
|
70
|
-
useDivider && styles.headerDivider,
|
|
71
|
-
useDivider && {
|
|
72
|
-
borderBottomColor: theme.colors.border.default,
|
|
73
|
-
},
|
|
74
|
-
]}
|
|
75
|
-
>
|
|
76
|
-
{showButtons && showBack ? (
|
|
77
|
-
<TouchableOpacity style={styles.iconButton} onPress={onPressBack}>
|
|
78
|
-
<Icon source={iconBack} />
|
|
79
|
-
</TouchableOpacity>
|
|
80
|
-
) : null}
|
|
81
|
-
|
|
82
|
-
{options.header ? (
|
|
83
|
-
<View style={Styles.flex}>{options.header}</View>
|
|
84
|
-
) : (
|
|
85
|
-
<>
|
|
86
|
-
{showButtons && !leftOptions ? (
|
|
87
|
-
<View style={styles.iconButton} />
|
|
88
|
-
) : null}
|
|
89
|
-
<Text
|
|
90
|
-
style={[
|
|
91
|
-
Styles.flex,
|
|
92
|
-
styles.title,
|
|
93
|
-
!showButtons && styles.titleInset,
|
|
94
|
-
]}
|
|
95
|
-
numberOfLines={1}
|
|
96
|
-
typography="header_default_bold"
|
|
97
|
-
>
|
|
98
|
-
{options.title ?? ''}
|
|
99
|
-
</Text>
|
|
100
|
-
</>
|
|
101
|
-
)}
|
|
102
|
-
{showButtons ? (
|
|
103
|
-
<TouchableOpacity style={styles.iconButton} onPress={onPressClose}>
|
|
104
|
-
<Icon source="navigation_close" />
|
|
105
|
-
</TouchableOpacity>
|
|
106
|
-
) : null}
|
|
107
|
-
</View>
|
|
37
|
+
}: SheetHeaderParams) => (
|
|
38
|
+
<View {...panHandlers}>
|
|
39
|
+
<View style={{ height: INDICATOR_HEIGHT }}>
|
|
40
|
+
<View style={styles.indicator} />
|
|
108
41
|
</View>
|
|
109
|
-
);
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* iPhone Duo folded: back and close move to the side bar column, drawn on
|
|
114
|
-
* the part of the sheet under the side safe area. They line up with the
|
|
115
|
-
* header row, stay below the status bar cluster on a tall sheet and above a
|
|
116
|
-
* camera at the bottom end of the strip.
|
|
117
|
-
*/
|
|
118
|
-
export const renderSheetSideColumn = ({
|
|
119
|
-
sideColumn,
|
|
120
|
-
windowHeight,
|
|
121
|
-
sheetTop,
|
|
122
|
-
sideColumnHeight,
|
|
123
|
-
sideColumnWidth,
|
|
124
|
-
showBack,
|
|
125
|
-
iconBack,
|
|
126
|
-
onPressBack,
|
|
127
|
-
onPressClose,
|
|
128
|
-
}: SheetPartsParams) => {
|
|
129
|
-
if (!sideColumn) {
|
|
130
|
-
return null;
|
|
131
|
-
}
|
|
132
|
-
const lowestTop =
|
|
133
|
-
windowHeight - sideColumn.bottom - sideColumnHeight - sheetTop;
|
|
134
|
-
const top = Math.min(
|
|
135
|
-
Math.max(sideColumn.top - sheetTop, SIDE_COLUMN_OFFSET),
|
|
136
|
-
lowestTop,
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
return (
|
|
140
42
|
<View
|
|
141
|
-
pointerEvents={'box-none'}
|
|
142
43
|
style={[
|
|
143
|
-
styles.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
44
|
+
styles.header,
|
|
45
|
+
useDivider && styles.headerDivider,
|
|
46
|
+
useDivider && {
|
|
47
|
+
borderBottomColor: theme.colors.border.default,
|
|
48
|
+
},
|
|
147
49
|
]}
|
|
148
50
|
>
|
|
149
51
|
{showBack ? (
|
|
150
|
-
<
|
|
52
|
+
<ModalIconButton icon={iconBack} onPress={onPressBack} />
|
|
151
53
|
) : null}
|
|
152
|
-
|
|
54
|
+
|
|
55
|
+
{options.header ? (
|
|
56
|
+
<View style={Styles.flex}>{options.header}</View>
|
|
57
|
+
) : (
|
|
58
|
+
<>
|
|
59
|
+
{!leftOptions ? <View style={styles.iconButtonSpace} /> : null}
|
|
60
|
+
<Text
|
|
61
|
+
style={[Styles.flex, styles.title]}
|
|
62
|
+
numberOfLines={1}
|
|
63
|
+
typography="header_default_bold"
|
|
64
|
+
>
|
|
65
|
+
{options.title ?? ''}
|
|
66
|
+
</Text>
|
|
67
|
+
</>
|
|
68
|
+
)}
|
|
69
|
+
<ModalIconButton icon="navigation_close" onPress={onPressClose} />
|
|
153
70
|
</View>
|
|
154
|
-
|
|
155
|
-
|
|
71
|
+
</View>
|
|
72
|
+
);
|
|
156
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Footer pinned under the sheet content, `null` when the sheet has none.
|
|
76
|
+
*/
|
|
157
77
|
export const renderSheetFooter = ({
|
|
158
78
|
footerComponent,
|
|
159
79
|
theme,
|
|
160
|
-
sideInsetStyle,
|
|
161
80
|
}: {
|
|
162
81
|
footerComponent: BottomSheetParams['footerComponent'];
|
|
163
82
|
theme: Theme;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
83
|
+
}) => {
|
|
84
|
+
if (!footerComponent) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
return (
|
|
167
88
|
<View
|
|
168
89
|
style={[
|
|
169
90
|
layoutStyles.shadow,
|
|
@@ -171,61 +92,56 @@ export const renderSheetFooter = ({
|
|
|
171
92
|
paddingBottom: Spacing.S,
|
|
172
93
|
backgroundColor: theme.colors.background.surface,
|
|
173
94
|
},
|
|
174
|
-
sideInsetStyle,
|
|
175
95
|
]}
|
|
176
96
|
>
|
|
177
97
|
{footerComponent}
|
|
178
98
|
</View>
|
|
179
99
|
);
|
|
100
|
+
};
|
|
180
101
|
|
|
181
102
|
type SheetStyleParams = {
|
|
182
103
|
backgroundColor: string;
|
|
183
104
|
isDuo: boolean;
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
topGap: number;
|
|
105
|
+
isFoldable: boolean;
|
|
106
|
+
placement: ModalLayout['placement'];
|
|
107
|
+
sheet: ModalLayout['sheet'];
|
|
188
108
|
keyboardLift: number;
|
|
189
|
-
sideColumn?: SideBarLayout;
|
|
190
|
-
sideColumnHeight: number;
|
|
191
|
-
insets: EdgeInsets;
|
|
192
109
|
showBaseLineDebug: boolean;
|
|
193
110
|
};
|
|
194
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Sheet container style. On foldables the sheet is centered in the placement
|
|
114
|
+
* area, clear of the iPhone Duo control column and on the right half when half
|
|
115
|
+
* folded; the keyboard lift comes off its max height.
|
|
116
|
+
*/
|
|
195
117
|
export const getSheetStyle = ({
|
|
196
118
|
backgroundColor,
|
|
197
119
|
isDuo,
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
topGap,
|
|
120
|
+
isFoldable,
|
|
121
|
+
placement,
|
|
122
|
+
sheet,
|
|
202
123
|
keyboardLift,
|
|
203
|
-
sideColumn,
|
|
204
|
-
sideColumnHeight,
|
|
205
|
-
insets,
|
|
206
124
|
showBaseLineDebug,
|
|
207
|
-
}: SheetStyleParams) =>
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
showBaseLineDebug && styles.debugBaseLine,
|
|
231
|
-
];
|
|
125
|
+
}: SheetStyleParams) => {
|
|
126
|
+
const { width, maxHeight } = sheet;
|
|
127
|
+
let foldableStyle: ViewStyle | undefined;
|
|
128
|
+
if (isFoldable && width !== undefined && maxHeight !== undefined) {
|
|
129
|
+
foldableStyle = {
|
|
130
|
+
width,
|
|
131
|
+
marginLeft: placement.x + (placement.width - width) / 2,
|
|
132
|
+
maxHeight: maxHeight - keyboardLift,
|
|
133
|
+
minHeight: sheet.minHeight,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return [
|
|
137
|
+
styles.sheetContainer,
|
|
138
|
+
{
|
|
139
|
+
backgroundColor,
|
|
140
|
+
borderTopLeftRadius: sheet.radius,
|
|
141
|
+
borderTopRightRadius: sheet.radius,
|
|
142
|
+
},
|
|
143
|
+
isDuo && { marginBottom: keyboardLift },
|
|
144
|
+
foldableStyle,
|
|
145
|
+
showBaseLineDebug && styles.debugBaseLine,
|
|
146
|
+
];
|
|
147
|
+
};
|
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
2
|
import { Colors, Radius, Spacing } from '../Consts';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
// iPhone Duo inner display: center the sheet instead of spanning the width
|
|
6
|
-
export const DUO_REGULAR_MIN_WIDTH = 600;
|
|
3
|
+
import { MODAL_ICON_BUTTON_SIZE } from './ModalIconButton';
|
|
7
4
|
|
|
8
5
|
export const INDICATOR_HEIGHT = 16;
|
|
9
6
|
export const HEADER_HEIGHT = 56;
|
|
10
7
|
export const DUO_ORIENTATIONS = ['portrait', 'landscape'];
|
|
11
|
-
export const SIDE_COLUMN_OFFSET =
|
|
12
|
-
INDICATOR_HEIGHT + (HEADER_HEIGHT - DuoMetrics.controlSize) / 2;
|
|
13
|
-
|
|
14
|
-
export const getSideInset = (inset: number) => Math.max(inset - Spacing.M, 0);
|
|
15
8
|
|
|
16
9
|
export const styles = StyleSheet.create({
|
|
17
10
|
container: {
|
|
@@ -20,7 +13,7 @@ export const styles = StyleSheet.create({
|
|
|
20
13
|
},
|
|
21
14
|
overlay: {
|
|
22
15
|
flex: 1,
|
|
23
|
-
backgroundColor:
|
|
16
|
+
backgroundColor: Colors.black_20,
|
|
24
17
|
},
|
|
25
18
|
indicator: {
|
|
26
19
|
width: 40,
|
|
@@ -35,25 +28,16 @@ export const styles = StyleSheet.create({
|
|
|
35
28
|
height: HEADER_HEIGHT,
|
|
36
29
|
flexDirection: 'row',
|
|
37
30
|
alignItems: 'center',
|
|
31
|
+
paddingHorizontal: Spacing.M,
|
|
32
|
+
gap: Spacing.S,
|
|
38
33
|
},
|
|
39
34
|
title: { textAlign: 'center' },
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
height: 24,
|
|
44
|
-
alignItems: 'center',
|
|
45
|
-
justifyContent: 'center',
|
|
46
|
-
marginHorizontal: Spacing.M,
|
|
35
|
+
iconButtonSpace: {
|
|
36
|
+
width: MODAL_ICON_BUTTON_SIZE,
|
|
37
|
+
height: MODAL_ICON_BUTTON_SIZE,
|
|
47
38
|
},
|
|
48
39
|
shrink: { flexShrink: 1 },
|
|
49
|
-
sideColumn: {
|
|
50
|
-
position: 'absolute',
|
|
51
|
-
gap: Spacing.M,
|
|
52
|
-
},
|
|
53
|
-
alignRight: { right: 0 },
|
|
54
|
-
alignLeft: { left: 0 },
|
|
55
40
|
debugBaseLine: { borderWidth: 1, borderColor: Colors.green_06 },
|
|
56
41
|
headerDivider: { borderBottomWidth: 1 },
|
|
57
42
|
sheetContainer: { overflow: 'hidden' },
|
|
58
|
-
centered: { alignSelf: 'center' },
|
|
59
43
|
});
|
|
@@ -1,23 +1,15 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
useCallback,
|
|
3
|
-
useContext,
|
|
4
|
-
useEffect,
|
|
5
|
-
useRef,
|
|
6
|
-
useState,
|
|
7
|
-
} from 'react';
|
|
1
|
+
import React, { useCallback, useContext, useEffect, useRef } from 'react';
|
|
8
2
|
import {
|
|
9
3
|
KeyboardAvoidingView,
|
|
10
4
|
Modal,
|
|
11
5
|
PanResponder,
|
|
12
6
|
Platform,
|
|
13
7
|
Pressable,
|
|
14
|
-
StatusBar,
|
|
15
8
|
StyleSheet,
|
|
16
9
|
View,
|
|
17
10
|
} from 'react-native';
|
|
18
11
|
import { ApplicationContext, MiniAppContext } from '../Context';
|
|
19
12
|
import { BottomSheetParams } from './types';
|
|
20
|
-
import { Spacing } from '../Consts';
|
|
21
13
|
import Animated, {
|
|
22
14
|
Easing,
|
|
23
15
|
useSharedValue,
|
|
@@ -25,7 +17,6 @@ import Animated, {
|
|
|
25
17
|
withTiming,
|
|
26
18
|
} from 'react-native-reanimated';
|
|
27
19
|
import { scheduleOnRN } from 'react-native-worklets';
|
|
28
|
-
import { DuoMetrics } from '../Layout/utils';
|
|
29
20
|
import { DUO_ORIENTATIONS, styles } from './BottomSheet.styles';
|
|
30
21
|
import {
|
|
31
22
|
useBottomSheetLayout,
|
|
@@ -37,7 +28,6 @@ import {
|
|
|
37
28
|
getSheetStyle,
|
|
38
29
|
renderSheetFooter,
|
|
39
30
|
renderSheetHeader,
|
|
40
|
-
renderSheetSideColumn,
|
|
41
31
|
} from './BottomSheet.parts';
|
|
42
32
|
|
|
43
33
|
const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
@@ -46,17 +36,11 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
|
46
36
|
const {
|
|
47
37
|
windowSize,
|
|
48
38
|
isDuo,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
hasSideColumn,
|
|
39
|
+
isFoldable,
|
|
40
|
+
placement,
|
|
41
|
+
sheet,
|
|
42
|
+
scrimOpacity,
|
|
54
43
|
heightDevice,
|
|
55
|
-
insets,
|
|
56
|
-
topGap,
|
|
57
|
-
sideInsetLeft,
|
|
58
|
-
sideInsetRight,
|
|
59
|
-
indicatorShift,
|
|
60
44
|
bottomInset,
|
|
61
45
|
keyboardOffset,
|
|
62
46
|
} = useBottomSheetLayout();
|
|
@@ -82,7 +66,6 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
|
82
66
|
const translateY = useSharedValue(heightDevice);
|
|
83
67
|
const onDismissRef = useRef(props.route.params?.onDismiss);
|
|
84
68
|
onDismissRef.current = props.route.params?.onDismiss;
|
|
85
|
-
const [sheetTop, setSheetTop] = useState(windowSize.height);
|
|
86
69
|
const keyboardLift = useDuoKeyboardLift(
|
|
87
70
|
isDuo,
|
|
88
71
|
useKeyboardAvoidingView,
|
|
@@ -170,52 +153,25 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
|
170
153
|
|
|
171
154
|
const showBack = !!leftOptions?.onPressIconLeft;
|
|
172
155
|
const iconBack = leftOptions?.iconLeft ?? 'ic_back';
|
|
173
|
-
const sideColumnCount = showBack ? 2 : 1;
|
|
174
|
-
const sideColumnHeight =
|
|
175
|
-
sideColumnCount * DuoMetrics.controlSize +
|
|
176
|
-
(sideColumnCount - 1) * Spacing.M;
|
|
177
|
-
const coversStatusBar = !!sideColumn && sheetTop < sideColumn.top;
|
|
178
156
|
|
|
179
|
-
|
|
180
|
-
if (!coversStatusBar) {
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
const entry = StatusBar.pushStackEntry({
|
|
184
|
-
barStyle: theme.dark ? 'light-content' : 'dark-content',
|
|
185
|
-
animated: true,
|
|
186
|
-
});
|
|
187
|
-
return () => StatusBar.popStackEntry(entry);
|
|
188
|
-
}, [coversStatusBar, theme.dark]);
|
|
189
|
-
|
|
190
|
-
const partsParams = {
|
|
157
|
+
const headerParams = {
|
|
191
158
|
panHandlers: panResponder.panHandlers,
|
|
192
|
-
indicatorShift,
|
|
193
159
|
useDivider,
|
|
194
160
|
theme,
|
|
195
|
-
hasSideColumn,
|
|
196
161
|
showBack,
|
|
197
162
|
onPressBack,
|
|
198
163
|
onPressClose,
|
|
199
164
|
iconBack,
|
|
200
165
|
options,
|
|
201
166
|
leftOptions,
|
|
202
|
-
sideColumn,
|
|
203
|
-
windowHeight: windowSize.height,
|
|
204
|
-
sheetTop,
|
|
205
|
-
sideColumnHeight,
|
|
206
|
-
sideColumnWidth,
|
|
207
167
|
};
|
|
208
168
|
|
|
209
169
|
const { animatedStyle, animatedOverlayStyle } = useSheetAnimatedStyles(
|
|
210
170
|
translateY,
|
|
211
171
|
heightDevice,
|
|
172
|
+
scrimOpacity,
|
|
212
173
|
);
|
|
213
174
|
|
|
214
|
-
const sideInsetStyle = isDuoFloating && {
|
|
215
|
-
paddingLeft: sideInsetLeft,
|
|
216
|
-
paddingRight: sideInsetRight,
|
|
217
|
-
};
|
|
218
|
-
|
|
219
175
|
const screen = (
|
|
220
176
|
<Screen
|
|
221
177
|
{...props}
|
|
@@ -256,39 +212,32 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
|
256
212
|
</Pressable>
|
|
257
213
|
|
|
258
214
|
<Animated.View
|
|
259
|
-
onLayout={
|
|
260
|
-
isDuoFloating ? e => setSheetTop(e.nativeEvent.layout.y) : undefined
|
|
261
|
-
}
|
|
262
215
|
style={[
|
|
263
216
|
animatedStyle,
|
|
264
217
|
getSheetStyle({
|
|
265
218
|
backgroundColor,
|
|
266
219
|
isDuo,
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
topGap,
|
|
220
|
+
isFoldable,
|
|
221
|
+
placement,
|
|
222
|
+
sheet,
|
|
271
223
|
keyboardLift,
|
|
272
|
-
sideColumn,
|
|
273
|
-
sideColumnHeight,
|
|
274
|
-
insets,
|
|
275
224
|
showBaseLineDebug,
|
|
276
225
|
}),
|
|
277
226
|
]}
|
|
278
227
|
>
|
|
279
|
-
{
|
|
228
|
+
{isFoldable ? (
|
|
280
229
|
// content shrinks so a tall sheet keeps its header and footer
|
|
281
|
-
<View style={
|
|
282
|
-
{renderSheetHeader(
|
|
230
|
+
<View style={styles.shrink}>
|
|
231
|
+
{renderSheetHeader(headerParams)}
|
|
283
232
|
<View style={styles.shrink}>{screen}</View>
|
|
284
233
|
</View>
|
|
285
234
|
) : (
|
|
286
235
|
<>
|
|
287
|
-
{renderSheetHeader(
|
|
236
|
+
{renderSheetHeader(headerParams)}
|
|
288
237
|
{screen}
|
|
289
238
|
</>
|
|
290
239
|
)}
|
|
291
|
-
{renderSheetFooter({ footerComponent, theme
|
|
240
|
+
{renderSheetFooter({ footerComponent, theme })}
|
|
292
241
|
{useBottomInset && (
|
|
293
242
|
<View
|
|
294
243
|
style={{
|
|
@@ -297,7 +246,6 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
|
297
246
|
}}
|
|
298
247
|
/>
|
|
299
248
|
)}
|
|
300
|
-
{renderSheetSideColumn(partsParams)}
|
|
301
249
|
</Animated.View>
|
|
302
250
|
</KeyboardAvoidingView>
|
|
303
251
|
</Container>
|