@momo-kits/foundation 0.169.4-beta.5 → 0.169.4-beta.7
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/BottomTab/BottomTabBar.styles.ts +3 -0
- package/Application/BottomTab/BottomTabBar.tsx +2 -0
- package/Application/BottomTab/CurvedContainer.tsx +8 -2
- package/Application/BottomTab/CustomBottomTabItem.tsx +2 -2
- package/Application/BottomTab/DuoTabBar.tsx +15 -3
- package/Application/BottomTab/metrics.ts +23 -3
- package/Application/__tests__/modalLayout.test.ts +3 -3
- package/Application/modalLayout.ts +2 -2
- package/Popup/PopupNotify.tsx +9 -5
- package/package.json +1 -1
|
@@ -46,6 +46,9 @@ export const styles = StyleSheet.create({
|
|
|
46
46
|
width: TabBarMetrics.ctaSize,
|
|
47
47
|
height: TabBarMetrics.ctaSize,
|
|
48
48
|
borderRadius: TabBarMetrics.ctaSize / 2,
|
|
49
|
+
// Figma Icon Button border: white 60% hairline
|
|
50
|
+
borderWidth: 1,
|
|
51
|
+
borderColor: `rgba(255, 255, 255, ${TabBarMetrics.ctaBorderOpacity})`,
|
|
49
52
|
alignItems: 'center',
|
|
50
53
|
justifyContent: 'center',
|
|
51
54
|
},
|
|
@@ -3,7 +3,7 @@ import { StyleSheet } from 'react-native';
|
|
|
3
3
|
import Svg, { Defs, FeGaussianBlur, Filter, Path } from 'react-native-svg';
|
|
4
4
|
import { Colors } from '../../Consts';
|
|
5
5
|
import { ApplicationContext } from '../../Context';
|
|
6
|
-
import { NOTCH_CURVES, NOTCH_HALF_WIDTH } from './metrics';
|
|
6
|
+
import { NOTCH_CURVES, NOTCH_HALF_WIDTH, TabBarMetrics } from './metrics';
|
|
7
7
|
|
|
8
8
|
type Props = {
|
|
9
9
|
width: number;
|
|
@@ -137,7 +137,13 @@ const CurvedContainer: React.FC<Props> = ({
|
|
|
137
137
|
filter={'url(#keyShadow)'}
|
|
138
138
|
/>
|
|
139
139
|
)}
|
|
140
|
-
<Path
|
|
140
|
+
<Path
|
|
141
|
+
d={path}
|
|
142
|
+
fill={theme.colors.background.surface}
|
|
143
|
+
fillOpacity={TabBarMetrics.backgroundOpacity}
|
|
144
|
+
stroke={theme.colors.border.default}
|
|
145
|
+
strokeWidth={1}
|
|
146
|
+
/>
|
|
141
147
|
</Svg>
|
|
142
148
|
);
|
|
143
149
|
};
|
|
@@ -13,7 +13,7 @@ import Animated, {
|
|
|
13
13
|
import { CappedScaleText, TabBarIcon } from './TabBarIcon';
|
|
14
14
|
import { Text } from '../../Text';
|
|
15
15
|
import { MiniAppContext } from '../../Context';
|
|
16
|
-
import { Colors
|
|
16
|
+
import { Colors } from '../../Consts';
|
|
17
17
|
import { TabBarMetrics, TabBarMotion } from './metrics';
|
|
18
18
|
|
|
19
19
|
type IconRenderer = (props: {
|
|
@@ -147,7 +147,7 @@ const styles = StyleSheet.create({
|
|
|
147
147
|
minWidth: 1,
|
|
148
148
|
alignItems: 'center',
|
|
149
149
|
justifyContent: 'center',
|
|
150
|
-
gap:
|
|
150
|
+
gap: TabBarMetrics.itemIconLabelGap,
|
|
151
151
|
},
|
|
152
152
|
slot: {
|
|
153
153
|
height: TabBarMetrics.indicatorHeight,
|
|
@@ -3,7 +3,11 @@ import React from 'react';
|
|
|
3
3
|
import { useWindowDimensions, View } from 'react-native';
|
|
4
4
|
import { useScreenLayout } from '../../Layout/utils';
|
|
5
5
|
import { FloatingButtonProps } from '../types';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
getSystemIndicatorHeight,
|
|
8
|
+
hasCenterAction,
|
|
9
|
+
HorizontalTabBar,
|
|
10
|
+
} from './BottomTabBar';
|
|
7
11
|
import { getHorizontalBarWidth, TabBarMetrics } from './metrics';
|
|
8
12
|
import { getTabItems } from './tabItems';
|
|
9
13
|
import { DuoRailTabBar } from './DuoRailTabBar';
|
|
@@ -34,6 +38,7 @@ const DuoFloatingTabBar: React.FC<DuoTabBarProps> = props => {
|
|
|
34
38
|
const { insets } = useScreenLayout();
|
|
35
39
|
const { width, height } = useWindowDimensions();
|
|
36
40
|
const { floatingButton, activeTintColor, inactiveTintColor } = props;
|
|
41
|
+
const tabItems = getTabItems(props);
|
|
37
42
|
|
|
38
43
|
return (
|
|
39
44
|
<View
|
|
@@ -45,8 +50,15 @@ const DuoFloatingTabBar: React.FC<DuoTabBarProps> = props => {
|
|
|
45
50
|
>
|
|
46
51
|
<HorizontalTabBar
|
|
47
52
|
fixedFontScale
|
|
48
|
-
items={
|
|
49
|
-
width={getHorizontalBarWidth(
|
|
53
|
+
items={tabItems}
|
|
54
|
+
width={getHorizontalBarWidth(
|
|
55
|
+
width,
|
|
56
|
+
height,
|
|
57
|
+
insets.left,
|
|
58
|
+
insets.right,
|
|
59
|
+
tabItems.length,
|
|
60
|
+
hasCenterAction(floatingButton, tabItems.length),
|
|
61
|
+
)}
|
|
50
62
|
floatingButton={floatingButton}
|
|
51
63
|
activeTintColor={activeTintColor}
|
|
52
64
|
inactiveTintColor={inactiveTintColor}
|
|
@@ -9,11 +9,18 @@ import { Colors, Radius, Spacing } from '../../Consts';
|
|
|
9
9
|
* - vertical: iPhone Duo rail, center action under the container
|
|
10
10
|
*/
|
|
11
11
|
const TabBarMetrics = {
|
|
12
|
-
height:
|
|
12
|
+
height: 60,
|
|
13
13
|
margin: Spacing.S,
|
|
14
|
-
paddingVertical: Spacing.
|
|
14
|
+
paddingVertical: Spacing.XS,
|
|
15
15
|
paddingHorizontal: Spacing.M,
|
|
16
|
-
itemGap:
|
|
16
|
+
itemGap: 1,
|
|
17
|
+
// gap between the icon slot and the label inside a tab (Figma: none)
|
|
18
|
+
itemIconLabelGap: 0,
|
|
19
|
+
// .Nav/Background: no backdrop blur, so use the Figma Blur=Off spec (opacity 95%, no blur) plus the 1px
|
|
20
|
+
// border — nearly solid, matching the frosted sample; surface keeps dark-mode support
|
|
21
|
+
backgroundOpacity: 0.95,
|
|
22
|
+
// white 60% hairline around the center action button (Figma Icon Button border)
|
|
23
|
+
ctaBorderOpacity: 0.6,
|
|
17
24
|
iconSize: 24,
|
|
18
25
|
// active indicator behind the icon: 24 icon + XS·M padding
|
|
19
26
|
indicatorPaddingVertical: Spacing.XS,
|
|
@@ -29,6 +36,9 @@ const TabBarMetrics = {
|
|
|
29
36
|
// side, centered; phones and folded outer displays fill the window
|
|
30
37
|
foldableMinShortSide: 600,
|
|
31
38
|
foldableWidthRatio: 0.65,
|
|
39
|
+
// a 2-tab bar doesn't stretch to the full width: each item is this fixed width and the bar is
|
|
40
|
+
// sized to its content, centered (Figma Navigation · 2 Tab: item 100, bar ~225)
|
|
41
|
+
twoTabItemWidth: 100,
|
|
32
42
|
ctaSlotWidth: 92,
|
|
33
43
|
ctaSize: 48,
|
|
34
44
|
// the icon sits 10 inside the 48 button (prototype .cta: 28 icon), 12 inside the 52 rail one
|
|
@@ -139,7 +149,17 @@ const getHorizontalBarWidth = (
|
|
|
139
149
|
height: number,
|
|
140
150
|
insetLeft: number,
|
|
141
151
|
insetRight: number,
|
|
152
|
+
itemCount: number,
|
|
153
|
+
hasCta: boolean,
|
|
142
154
|
) => {
|
|
155
|
+
// 2 tabs (no center action) stay content-sized and centered instead of filling the window
|
|
156
|
+
if (itemCount === 2 && !hasCta) {
|
|
157
|
+
return (
|
|
158
|
+
TabBarMetrics.twoTabItemWidth * 2 +
|
|
159
|
+
TabBarMetrics.paddingHorizontal * 2 +
|
|
160
|
+
TabBarMetrics.itemGap
|
|
161
|
+
);
|
|
162
|
+
}
|
|
143
163
|
const shortSide = Math.min(width, height);
|
|
144
164
|
if (shortSide >= TabBarMetrics.foldableMinShortSide) {
|
|
145
165
|
return shortSide * TabBarMetrics.foldableWidthRatio;
|
|
@@ -16,10 +16,10 @@ describe('getModalLayout', () => {
|
|
|
16
16
|
expect(layout.isFoldable).toBe(false);
|
|
17
17
|
expect(layout.popup.width).toBe(342);
|
|
18
18
|
expect(layout.popup.maxHeight).toBeUndefined();
|
|
19
|
-
expect(layout.popup.radius).toBe(
|
|
19
|
+
expect(layout.popup.radius).toBe(16);
|
|
20
20
|
expect(layout.sheet.width).toBeUndefined();
|
|
21
21
|
expect(layout.sheet.maxHeight).toBeUndefined();
|
|
22
|
-
expect(layout.sheet.radius).toBe(
|
|
22
|
+
expect(layout.sheet.radius).toBe(12);
|
|
23
23
|
expect(layout.scrimOpacity).toBe(0.6);
|
|
24
24
|
});
|
|
25
25
|
|
|
@@ -33,7 +33,7 @@ describe('getModalLayout', () => {
|
|
|
33
33
|
expect(layout.isFoldable).toBe(false);
|
|
34
34
|
expect(layout.popup.width).toBe(844 - 48);
|
|
35
35
|
expect(layout.popup.maxHeight).toBeUndefined();
|
|
36
|
-
expect(layout.popup.radius).toBe(
|
|
36
|
+
expect(layout.popup.radius).toBe(16);
|
|
37
37
|
expect(layout.sheet.width).toBeUndefined();
|
|
38
38
|
expect(layout.scrimOpacity).toBe(0.6);
|
|
39
39
|
});
|
|
@@ -112,9 +112,9 @@ const getModalLayout = ({
|
|
|
112
112
|
minWidth: popupWidth,
|
|
113
113
|
maxWidth: popupWidth,
|
|
114
114
|
margin: Spacing.XL,
|
|
115
|
-
radius: Radius.
|
|
115
|
+
radius: Radius.L,
|
|
116
116
|
},
|
|
117
|
-
sheet: { margin: 0, radius: Radius.
|
|
117
|
+
sheet: { margin: 0, radius: Radius.M },
|
|
118
118
|
scrimOpacity: SCRIM_OPACITY,
|
|
119
119
|
};
|
|
120
120
|
}
|
package/Popup/PopupNotify.tsx
CHANGED
|
@@ -183,12 +183,18 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
|
|
|
183
183
|
const body = (
|
|
184
184
|
<>
|
|
185
185
|
{!!image && (
|
|
186
|
-
<Image
|
|
186
|
+
<Image
|
|
187
|
+
source={{ uri: image }}
|
|
188
|
+
style={[
|
|
189
|
+
styles.image,
|
|
190
|
+
{ borderTopLeftRadius: radius, borderTopRightRadius: radius },
|
|
191
|
+
]}
|
|
192
|
+
/>
|
|
187
193
|
)}
|
|
188
194
|
<View style={[styles.content, isFoldable && styles.shrink]}>
|
|
189
195
|
<Text
|
|
190
196
|
typography={'header_default_bold'}
|
|
191
|
-
numberOfLines={
|
|
197
|
+
numberOfLines={3}
|
|
192
198
|
accessibilityLabel={'title_popup_notify'}
|
|
193
199
|
// keeps the title clear of the close button on a text only popup
|
|
194
200
|
style={
|
|
@@ -244,7 +250,6 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
|
|
|
244
250
|
width: popupWidth,
|
|
245
251
|
maxHeight,
|
|
246
252
|
},
|
|
247
|
-
styles.card,
|
|
248
253
|
showBaseLineDebug && styles.debugBaseLine,
|
|
249
254
|
]}
|
|
250
255
|
>
|
|
@@ -257,10 +262,9 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
|
|
|
257
262
|
|
|
258
263
|
const styles = StyleSheet.create({
|
|
259
264
|
debugBaseLine: { borderWidth: 1, borderColor: Colors.green_06 },
|
|
260
|
-
// clips the image and content to the card radius
|
|
261
|
-
card: { overflow: 'hidden' },
|
|
262
265
|
image: {
|
|
263
266
|
aspectRatio: 1.7777,
|
|
267
|
+
overflow: 'hidden',
|
|
264
268
|
},
|
|
265
269
|
shrink: { flexShrink: 1 },
|
|
266
270
|
content: { padding: Spacing.XL },
|