@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
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import React, { useContext, useState } from 'react';
|
|
2
|
-
import { StyleSheet, View } from 'react-native';
|
|
3
|
-
import LinearGradient from 'react-native-linear-gradient';
|
|
4
|
-
import Animated, {
|
|
5
|
-
Extrapolation,
|
|
6
|
-
interpolate,
|
|
7
|
-
runOnJS,
|
|
8
|
-
useAnimatedReaction,
|
|
9
|
-
useAnimatedStyle,
|
|
10
|
-
} from 'react-native-reanimated';
|
|
11
|
-
import { ApplicationContext } from '../../Context';
|
|
12
|
-
import { Shadow } from '../../Consts';
|
|
13
|
-
import { Image } from '../../Image';
|
|
14
|
-
import { AnimatedCompatValue, useNormalizedSharedValue } from '../utils';
|
|
15
|
-
import { GlassView } from './OptionalGlassView';
|
|
16
|
-
|
|
17
|
-
// extended headers run their gradient this far below the header, as off Duo
|
|
18
|
-
const EXTENDED_GRADIENT_EXTRA = 52;
|
|
19
|
-
// scroll distance over which the extended gradient collapses to the header
|
|
20
|
-
const EXTENDED_COLLAPSE_DISTANCE = 100;
|
|
21
|
-
// scroll distance over which the bar material fades in
|
|
22
|
-
const FADE_DISTANCE = 16;
|
|
23
|
-
const TRANSLUCENT_ALPHA = 'CC';
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* iPhone Duo header background: glass running edge to edge, behind the status bar
|
|
27
|
-
* column too, shown once content scrolls under it
|
|
28
|
-
*/
|
|
29
|
-
const DuoGlassBackground: React.FC<{
|
|
30
|
-
animatedValue?: AnimatedCompatValue;
|
|
31
|
-
// scroll offset where the bar starts to show, e.g. below an animated banner
|
|
32
|
-
fadeStart?: number;
|
|
33
|
-
}> = ({ animatedValue, fadeStart = 0 }) => {
|
|
34
|
-
const { theme } = useContext(ApplicationContext);
|
|
35
|
-
const sharedValue = useNormalizedSharedValue(animatedValue);
|
|
36
|
-
const [scrolled, setScrolled] = useState(false);
|
|
37
|
-
|
|
38
|
-
useAnimatedReaction(
|
|
39
|
-
() => sharedValue.value > fadeStart,
|
|
40
|
-
(isScrolled, wasScrolled) => {
|
|
41
|
-
if (GlassView && isScrolled !== wasScrolled) {
|
|
42
|
-
runOnJS(setScrolled)(isScrolled);
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
[fadeStart],
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
const fadeStyle = useAnimatedStyle(() => ({
|
|
49
|
-
opacity: interpolate(
|
|
50
|
-
sharedValue.value,
|
|
51
|
-
[fadeStart, fadeStart + FADE_DISTANCE],
|
|
52
|
-
[0, 1],
|
|
53
|
-
Extrapolation.CLAMP,
|
|
54
|
-
),
|
|
55
|
-
}));
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<View pointerEvents={'none'} style={StyleSheet.absoluteFill}>
|
|
59
|
-
{GlassView ? (
|
|
60
|
-
// UIVisualEffectView breaks under alpha, so glass toggles its effect instead
|
|
61
|
-
<GlassView
|
|
62
|
-
effect={scrolled ? 'glass' : 'none'}
|
|
63
|
-
useShadow
|
|
64
|
-
style={StyleSheet.absoluteFill}
|
|
65
|
-
/>
|
|
66
|
-
) : (
|
|
67
|
-
<Animated.View
|
|
68
|
-
style={[
|
|
69
|
-
StyleSheet.absoluteFill,
|
|
70
|
-
styles.translucentBar,
|
|
71
|
-
{
|
|
72
|
-
backgroundColor:
|
|
73
|
-
theme.colors.background.surface + TRANSLUCENT_ALPHA,
|
|
74
|
-
borderBottomColor: theme.colors.border.default,
|
|
75
|
-
},
|
|
76
|
-
fadeStyle,
|
|
77
|
-
]}
|
|
78
|
-
/>
|
|
79
|
-
)}
|
|
80
|
-
</View>
|
|
81
|
-
);
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* pink header gradient drawn under the content, fading out on scroll as main's extended
|
|
86
|
-
* header does: header-high for default headers, 52 taller (collapsing) for extended
|
|
87
|
-
*/
|
|
88
|
-
const DuoScrollGradient: React.FC<{
|
|
89
|
-
animatedValue?: AnimatedCompatValue;
|
|
90
|
-
gradientColor?: string;
|
|
91
|
-
headerBackground?: string;
|
|
92
|
-
heightHeader: number;
|
|
93
|
-
extended?: boolean;
|
|
94
|
-
// quick return header: the gradient leaves with the content instead of fading
|
|
95
|
-
followScroll?: boolean;
|
|
96
|
-
}> = ({
|
|
97
|
-
animatedValue,
|
|
98
|
-
gradientColor,
|
|
99
|
-
headerBackground,
|
|
100
|
-
heightHeader,
|
|
101
|
-
extended,
|
|
102
|
-
followScroll,
|
|
103
|
-
}) => {
|
|
104
|
-
const { theme } = useContext(ApplicationContext);
|
|
105
|
-
const sharedValue = useNormalizedSharedValue(animatedValue);
|
|
106
|
-
const color = gradientColor ?? theme.colors.gradient;
|
|
107
|
-
const image = headerBackground ?? theme.assets?.headerBackground;
|
|
108
|
-
|
|
109
|
-
const scrollStyle = useAnimatedStyle(() => {
|
|
110
|
-
if (followScroll) {
|
|
111
|
-
return {
|
|
112
|
-
height: heightHeader + (extended ? EXTENDED_GRADIENT_EXTRA : 0),
|
|
113
|
-
transform: [{ translateY: -Math.max(sharedValue.value, 0) }],
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
return {
|
|
117
|
-
height: extended
|
|
118
|
-
? interpolate(
|
|
119
|
-
sharedValue.value,
|
|
120
|
-
[0, EXTENDED_COLLAPSE_DISTANCE],
|
|
121
|
-
[heightHeader + EXTENDED_GRADIENT_EXTRA, heightHeader],
|
|
122
|
-
Extrapolation.CLAMP,
|
|
123
|
-
)
|
|
124
|
-
: heightHeader,
|
|
125
|
-
opacity: interpolate(
|
|
126
|
-
sharedValue.value,
|
|
127
|
-
[0, EXTENDED_GRADIENT_EXTRA],
|
|
128
|
-
[1, 0],
|
|
129
|
-
Extrapolation.CLAMP,
|
|
130
|
-
),
|
|
131
|
-
};
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
if (!color) {
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return (
|
|
139
|
-
<Animated.View
|
|
140
|
-
pointerEvents={'none'}
|
|
141
|
-
style={[styles.gradient, scrollStyle]}
|
|
142
|
-
>
|
|
143
|
-
<LinearGradient
|
|
144
|
-
colors={[color, color + '00']}
|
|
145
|
-
style={StyleSheet.absoluteFill}
|
|
146
|
-
>
|
|
147
|
-
{!!image && (
|
|
148
|
-
<Image
|
|
149
|
-
style={styles.gradientFill}
|
|
150
|
-
source={{ uri: image }}
|
|
151
|
-
loading={false}
|
|
152
|
-
/>
|
|
153
|
-
)}
|
|
154
|
-
</LinearGradient>
|
|
155
|
-
</Animated.View>
|
|
156
|
-
);
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
const styles = StyleSheet.create({
|
|
160
|
-
translucentBar: {
|
|
161
|
-
borderBottomWidth: StyleSheet.hairlineWidth,
|
|
162
|
-
...Shadow.Light,
|
|
163
|
-
},
|
|
164
|
-
gradient: {
|
|
165
|
-
position: 'absolute',
|
|
166
|
-
top: 0,
|
|
167
|
-
left: 0,
|
|
168
|
-
right: 0,
|
|
169
|
-
overflow: 'hidden',
|
|
170
|
-
},
|
|
171
|
-
// banner image keeps its 375:154 shape, the gradient box clips it
|
|
172
|
-
gradientFill: {
|
|
173
|
-
width: '100%',
|
|
174
|
-
position: 'absolute',
|
|
175
|
-
aspectRatio: 375 / 154,
|
|
176
|
-
},
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
export { DuoGlassBackground, DuoScrollGradient };
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import React, { createContext, useContext } from 'react';
|
|
2
|
-
import { StackHeaderProps, Header } from '@react-navigation/stack';
|
|
3
|
-
import Animated, {
|
|
4
|
-
SharedValue,
|
|
5
|
-
useAnimatedStyle,
|
|
6
|
-
} from 'react-native-reanimated';
|
|
7
|
-
|
|
8
|
-
// how far the header is pushed above the top edge
|
|
9
|
-
const DuoHeaderOffsetContext = createContext<SharedValue<number> | undefined>(
|
|
10
|
-
undefined,
|
|
11
|
-
);
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* iPhone Duo header that leaves with the content and comes back when scrolling back
|
|
15
|
-
*/
|
|
16
|
-
const DuoQuickReturnHeader: React.FC<
|
|
17
|
-
StackHeaderProps & { offset: SharedValue<number> }
|
|
18
|
-
> = ({ offset, ...props }) => {
|
|
19
|
-
const style = useAnimatedStyle(() => ({
|
|
20
|
-
transform: [{ translateY: -offset.value }],
|
|
21
|
-
}));
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<DuoHeaderOffsetContext.Provider value={offset}>
|
|
25
|
-
<Animated.View pointerEvents={'box-none'} style={style}>
|
|
26
|
-
<Header {...props} />
|
|
27
|
-
</Animated.View>
|
|
28
|
-
</DuoHeaderOffsetContext.Provider>
|
|
29
|
-
);
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* side bar controls render inside the header; this cancels its offset so they stay put
|
|
34
|
-
*/
|
|
35
|
-
const useSideBarCounterStyle = () => {
|
|
36
|
-
const offset = useContext(DuoHeaderOffsetContext);
|
|
37
|
-
return useAnimatedStyle(() => ({
|
|
38
|
-
transform: [{ translateY: offset ? offset.value : 0 }],
|
|
39
|
-
}));
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export { DuoQuickReturnHeader, useSideBarCounterStyle };
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type React from 'react';
|
|
2
|
-
|
|
3
|
-
// native glass is optional so apps without @momo-kits/glass-view still bundle
|
|
4
|
-
let GlassView: React.ComponentType<any> | undefined;
|
|
5
|
-
try {
|
|
6
|
-
GlassView = require('@momo-kits/glass-view').GlassView;
|
|
7
|
-
} catch {
|
|
8
|
-
GlassView = undefined;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export { GlassView };
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type React from 'react';
|
|
2
|
-
|
|
3
|
-
// native observer is optional so apps without it in @momo-kits/reserved-regions still bundle
|
|
4
|
-
let ScrollObserverView: React.ComponentType<any> | undefined;
|
|
5
|
-
try {
|
|
6
|
-
ScrollObserverView =
|
|
7
|
-
require('@momo-kits/reserved-regions').ScrollObserverView;
|
|
8
|
-
} catch {
|
|
9
|
-
ScrollObserverView = undefined;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export { ScrollObserverView };
|
|
@@ -1,139 +0,0 @@
|
|
|
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
|
-
tintColor === Colors.black_01 || tintColor === 'white'
|
|
24
|
-
? styles.glassDark
|
|
25
|
-
: styles.glassLight;
|
|
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 length =
|
|
68
|
-
count > 1 ? count * DuoMetrics.itemPitch : DuoMetrics.controlSize;
|
|
69
|
-
|
|
70
|
-
return (
|
|
71
|
-
<View
|
|
72
|
-
style={[
|
|
73
|
-
styles.control,
|
|
74
|
-
getGlassStyle(tintColor),
|
|
75
|
-
horizontal
|
|
76
|
-
? { width: length, flexDirection: 'row' }
|
|
77
|
-
: { height: length },
|
|
78
|
-
style,
|
|
79
|
-
]}
|
|
80
|
-
>
|
|
81
|
-
{children}
|
|
82
|
-
</View>
|
|
83
|
-
);
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* icon item inside a SideBarGroup
|
|
88
|
-
*/
|
|
89
|
-
const SideBarGroupItem: React.FC<NavigationButtonProps> = ({
|
|
90
|
-
icon,
|
|
91
|
-
tintColor,
|
|
92
|
-
...props
|
|
93
|
-
}) => {
|
|
94
|
-
const { theme } = useContext(ApplicationContext);
|
|
95
|
-
|
|
96
|
-
return (
|
|
97
|
-
<TouchableOpacity {...props} style={styles.groupItem}>
|
|
98
|
-
<Icon
|
|
99
|
-
source={icon}
|
|
100
|
-
color={tintColor ?? theme.colors.text.default}
|
|
101
|
-
size={SIDE_BAR_ICON_SIZE}
|
|
102
|
-
/>
|
|
103
|
-
</TouchableOpacity>
|
|
104
|
-
);
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const styles = StyleSheet.create({
|
|
108
|
-
control: {
|
|
109
|
-
width: DuoMetrics.controlSize,
|
|
110
|
-
height: DuoMetrics.controlSize,
|
|
111
|
-
borderRadius: Radius.XL,
|
|
112
|
-
justifyContent: 'center',
|
|
113
|
-
alignItems: 'center',
|
|
114
|
-
},
|
|
115
|
-
glassLight: {
|
|
116
|
-
backgroundColor: Colors.black_01 + 'D9',
|
|
117
|
-
borderWidth: StyleSheet.hairlineWidth,
|
|
118
|
-
borderColor: Colors.black_20 + '14',
|
|
119
|
-
...Shadow.Light,
|
|
120
|
-
},
|
|
121
|
-
glassDark: {
|
|
122
|
-
backgroundColor: Colors.black_20 + '80',
|
|
123
|
-
borderWidth: StyleSheet.hairlineWidth,
|
|
124
|
-
borderColor: Colors.black_01 + '33',
|
|
125
|
-
},
|
|
126
|
-
groupItem: {
|
|
127
|
-
flex: 1,
|
|
128
|
-
alignSelf: 'stretch',
|
|
129
|
-
justifyContent: 'center',
|
|
130
|
-
alignItems: 'center',
|
|
131
|
-
},
|
|
132
|
-
badgeDot: {
|
|
133
|
-
position: 'absolute',
|
|
134
|
-
top: Spacing.XXS,
|
|
135
|
-
right: Spacing.XXS,
|
|
136
|
-
},
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
export { SideBarButton, SideBarGroup, SideBarGroupItem };
|
package/Application/device.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
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 };
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import React, { createContext, ReactNode, useState } from 'react';
|
|
2
|
-
import { Platform, StyleSheet } from 'react-native';
|
|
3
|
-
|
|
4
|
-
export type ReservedRegion = {
|
|
5
|
-
x: number;
|
|
6
|
-
y: number;
|
|
7
|
-
width: number;
|
|
8
|
-
height: number;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
// native probe is optional so apps without @momo-kits/reserved-regions still bundle
|
|
12
|
-
let ReservedRegionsView: React.ComponentType<any> | undefined;
|
|
13
|
-
try {
|
|
14
|
-
ReservedRegionsView =
|
|
15
|
-
require('@momo-kits/reserved-regions').ReservedRegionsView;
|
|
16
|
-
} catch {
|
|
17
|
-
ReservedRegionsView = undefined;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* screen regions the system currently occludes, in window coordinates
|
|
22
|
-
*/
|
|
23
|
-
const ReservedRegionsContext = createContext<ReservedRegion[]>([]);
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* tracks the system occlusion regions (iOS 27.1+), e.g. the iPhone Duo status bar
|
|
27
|
-
* cluster growing for a call or a Live Activity
|
|
28
|
-
*/
|
|
29
|
-
const ReservedRegionsProvider: React.FC<{ children: ReactNode }> = ({
|
|
30
|
-
children,
|
|
31
|
-
}) => {
|
|
32
|
-
const [regions, setRegions] = useState<ReservedRegion[]>([]);
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<ReservedRegionsContext.Provider value={regions}>
|
|
36
|
-
{children}
|
|
37
|
-
{Platform.OS === 'ios' && !!ReservedRegionsView && (
|
|
38
|
-
<ReservedRegionsView
|
|
39
|
-
style={StyleSheet.absoluteFill}
|
|
40
|
-
onRegionsChange={setRegions}
|
|
41
|
-
/>
|
|
42
|
-
)}
|
|
43
|
-
</ReservedRegionsContext.Provider>
|
|
44
|
-
);
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export { ReservedRegionsContext, ReservedRegionsProvider };
|
package/Popup/utils.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { Dimensions, useWindowDimensions } from 'react-native';
|
|
2
|
-
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
3
|
-
import { Spacing } from '../Consts';
|
|
4
|
-
import { getDuoTopInset, isIPhoneDuo } from '../Application/device';
|
|
5
|
-
|
|
6
|
-
// width of a system alert on the iPhone Duo inner display, in both orientations
|
|
7
|
-
const DUO_POPUP_MAX_WIDTH = 440;
|
|
8
|
-
|
|
9
|
-
const usePopupWidth = () => {
|
|
10
|
-
const windowSize = useWindowDimensions();
|
|
11
|
-
if (!isIPhoneDuo()) {
|
|
12
|
-
return Dimensions.get('window').width - Spacing.XL * 2;
|
|
13
|
-
}
|
|
14
|
-
return Math.min(windowSize.width - Spacing.XL * 2, DUO_POPUP_MAX_WIDTH);
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
// room left for a popup on iPhone Duo, where landscape is too short for it
|
|
18
|
-
const usePopupMaxHeight = () => {
|
|
19
|
-
const insets = useSafeAreaInsets();
|
|
20
|
-
const { width, height } = useWindowDimensions();
|
|
21
|
-
if (!isIPhoneDuo()) {
|
|
22
|
-
return undefined;
|
|
23
|
-
}
|
|
24
|
-
return (
|
|
25
|
-
height -
|
|
26
|
-
getDuoTopInset(insets, width, height) -
|
|
27
|
-
insets.bottom -
|
|
28
|
-
Spacing.XL * 2
|
|
29
|
-
);
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export { usePopupWidth, usePopupMaxHeight };
|