@momo-kits/foundation 0.169.7-beta.1 → 0.169.7-beta.3
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 +1 -18
- package/Application/BottomTab/BottomTabBar.tsx +10 -8
- package/Application/BottomTab/CurvedContainer.tsx +2 -8
- package/Application/BottomTab/CustomBottomTabItem.tsx +2 -2
- package/Application/BottomTab/DuoTabBar.tsx +3 -15
- package/Application/BottomTab/metrics.ts +3 -23
- package/Application/modalLayout.ts +3 -0
- package/Application/types.tabs.ts +1 -0
- package/Popup/PopupNotify.tsx +1 -1
- package/Popup/utils.ts +7 -4
- package/package.json +1 -1
|
@@ -2,20 +2,6 @@ import { StyleSheet } from 'react-native';
|
|
|
2
2
|
import { Colors, Spacing } from '../../Consts';
|
|
3
3
|
import { CTA_SHADOW, TabBarMetrics } from './metrics';
|
|
4
4
|
|
|
5
|
-
const ITEM_HEIGHT =
|
|
6
|
-
TabBarMetrics.indicatorHeight +
|
|
7
|
-
TabBarMetrics.itemIconLabelGap +
|
|
8
|
-
TabBarMetrics.labelHeight;
|
|
9
|
-
const CONTENT_HEIGHT = TabBarMetrics.height - 2 * TabBarMetrics.paddingVertical;
|
|
10
|
-
// the items are centered in the content, so their label starts this far below the content top
|
|
11
|
-
const ITEM_LABEL_TOP =
|
|
12
|
-
(CONTENT_HEIGHT - ITEM_HEIGHT) / 2 +
|
|
13
|
-
TabBarMetrics.indicatorHeight +
|
|
14
|
-
TabBarMetrics.itemIconLabelGap;
|
|
15
|
-
// the center action column is placed so its label starts on the same line as the tab labels
|
|
16
|
-
const CTA_TOP =
|
|
17
|
-
ITEM_LABEL_TOP - TabBarMetrics.ctaLabelGap - TabBarMetrics.ctaSize;
|
|
18
|
-
|
|
19
5
|
export const styles = StyleSheet.create({
|
|
20
6
|
bar: {
|
|
21
7
|
position: 'absolute',
|
|
@@ -51,7 +37,7 @@ export const styles = StyleSheet.create({
|
|
|
51
37
|
position: 'absolute',
|
|
52
38
|
left: 0,
|
|
53
39
|
right: 0,
|
|
54
|
-
top:
|
|
40
|
+
top: -TabBarMetrics.ctaLift - TabBarMetrics.paddingVertical,
|
|
55
41
|
alignItems: 'center',
|
|
56
42
|
gap: TabBarMetrics.ctaLabelGap,
|
|
57
43
|
},
|
|
@@ -60,9 +46,6 @@ export const styles = StyleSheet.create({
|
|
|
60
46
|
width: TabBarMetrics.ctaSize,
|
|
61
47
|
height: TabBarMetrics.ctaSize,
|
|
62
48
|
borderRadius: TabBarMetrics.ctaSize / 2,
|
|
63
|
-
// Figma Icon Button border: white 60% hairline
|
|
64
|
-
borderWidth: 1,
|
|
65
|
-
borderColor: `rgba(255, 255, 255, ${TabBarMetrics.ctaBorderOpacity})`,
|
|
66
49
|
alignItems: 'center',
|
|
67
50
|
justifyContent: 'center',
|
|
68
51
|
},
|
|
@@ -181,17 +181,21 @@ const HorizontalTabBar: React.FC<{
|
|
|
181
181
|
return renderItems(items);
|
|
182
182
|
};
|
|
183
183
|
|
|
184
|
+
const customContainer = withCta && floatingButton?.container;
|
|
185
|
+
|
|
184
186
|
return (
|
|
185
187
|
<View
|
|
186
188
|
style={[styles.container, { width }]}
|
|
187
189
|
accessibilityLabel={'bottom_tab_bar'}
|
|
188
190
|
>
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
191
|
+
{customContainer || (
|
|
192
|
+
<CurvedContainer
|
|
193
|
+
width={width}
|
|
194
|
+
height={TabBarMetrics.height}
|
|
195
|
+
radius={TabBarMetrics.height / 2}
|
|
196
|
+
notchCenterX={withCta ? width / 2 : undefined}
|
|
197
|
+
/>
|
|
198
|
+
)}
|
|
195
199
|
<View style={styles.content}>
|
|
196
200
|
<ActiveIndicator
|
|
197
201
|
axis={'x'}
|
|
@@ -224,8 +228,6 @@ export default function BottomTabBar(props: Props) {
|
|
|
224
228
|
window.height,
|
|
225
229
|
insets.left,
|
|
226
230
|
insets.right,
|
|
227
|
-
state.routes.length,
|
|
228
|
-
withCta,
|
|
229
231
|
);
|
|
230
232
|
|
|
231
233
|
return (
|
|
@@ -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
|
|
6
|
+
import { NOTCH_CURVES, NOTCH_HALF_WIDTH } from './metrics';
|
|
7
7
|
|
|
8
8
|
type Props = {
|
|
9
9
|
width: number;
|
|
@@ -139,13 +139,7 @@ const CurvedContainer: React.FC<Props> = ({
|
|
|
139
139
|
filter={'url(#keyShadow)'}
|
|
140
140
|
/>
|
|
141
141
|
)}
|
|
142
|
-
<Path
|
|
143
|
-
d={path}
|
|
144
|
-
fill={theme.colors.background.surface}
|
|
145
|
-
fillOpacity={TabBarMetrics.backgroundOpacity}
|
|
146
|
-
stroke={theme.colors.border.default}
|
|
147
|
-
strokeWidth={1}
|
|
148
|
-
/>
|
|
142
|
+
<Path d={path} fill={theme.colors.background.surface} />
|
|
149
143
|
</Svg>
|
|
150
144
|
);
|
|
151
145
|
};
|
|
@@ -13,7 +13,7 @@ import Animated, {
|
|
|
13
13
|
import { TabBarIcon } from './TabBarIcon';
|
|
14
14
|
import { Text } from '../../Text';
|
|
15
15
|
import { MiniAppContext } from '../../Context';
|
|
16
|
-
import { Colors } from '../../Consts';
|
|
16
|
+
import { Colors, Spacing } from '../../Consts';
|
|
17
17
|
import { TabBarMetrics, TabBarMotion } from './metrics';
|
|
18
18
|
|
|
19
19
|
type IconRenderer = (props: {
|
|
@@ -143,7 +143,7 @@ const styles = StyleSheet.create({
|
|
|
143
143
|
minWidth: 1,
|
|
144
144
|
alignItems: 'center',
|
|
145
145
|
justifyContent: 'center',
|
|
146
|
-
gap:
|
|
146
|
+
gap: Spacing.XXS,
|
|
147
147
|
},
|
|
148
148
|
slot: {
|
|
149
149
|
height: TabBarMetrics.indicatorHeight,
|
|
@@ -3,11 +3,7 @@ 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 {
|
|
7
|
-
getSystemIndicatorHeight,
|
|
8
|
-
hasCenterAction,
|
|
9
|
-
HorizontalTabBar,
|
|
10
|
-
} from './BottomTabBar';
|
|
6
|
+
import { getSystemIndicatorHeight, HorizontalTabBar } from './BottomTabBar';
|
|
11
7
|
import { getHorizontalBarWidth, TabBarMetrics } from './metrics';
|
|
12
8
|
import { getTabItems } from './tabItems';
|
|
13
9
|
import { DuoRailTabBar } from './DuoRailTabBar';
|
|
@@ -38,7 +34,6 @@ const DuoFloatingTabBar: React.FC<DuoTabBarProps> = props => {
|
|
|
38
34
|
const { insets } = useScreenLayout();
|
|
39
35
|
const { width, height } = useWindowDimensions();
|
|
40
36
|
const { floatingButton, activeTintColor, inactiveTintColor } = props;
|
|
41
|
-
const tabItems = getTabItems(props);
|
|
42
37
|
|
|
43
38
|
return (
|
|
44
39
|
<View
|
|
@@ -49,15 +44,8 @@ const DuoFloatingTabBar: React.FC<DuoTabBarProps> = props => {
|
|
|
49
44
|
]}
|
|
50
45
|
>
|
|
51
46
|
<HorizontalTabBar
|
|
52
|
-
items={
|
|
53
|
-
width={getHorizontalBarWidth(
|
|
54
|
-
width,
|
|
55
|
-
height,
|
|
56
|
-
insets.left,
|
|
57
|
-
insets.right,
|
|
58
|
-
tabItems.length,
|
|
59
|
-
hasCenterAction(floatingButton, tabItems.length),
|
|
60
|
-
)}
|
|
47
|
+
items={getTabItems(props)}
|
|
48
|
+
width={getHorizontalBarWidth(width, height, insets.left, insets.right)}
|
|
61
49
|
floatingButton={floatingButton}
|
|
62
50
|
activeTintColor={activeTintColor}
|
|
63
51
|
inactiveTintColor={inactiveTintColor}
|
|
@@ -8,18 +8,11 @@ import { Colors, Radius, Spacing } from '../../Consts';
|
|
|
8
8
|
* iPhone Duo rail (center action under the container).
|
|
9
9
|
*/
|
|
10
10
|
const TabBarMetrics = {
|
|
11
|
-
height:
|
|
11
|
+
height: 68,
|
|
12
12
|
margin: Spacing.S,
|
|
13
|
-
paddingVertical: Spacing.
|
|
13
|
+
paddingVertical: Spacing.S,
|
|
14
14
|
paddingHorizontal: Spacing.M,
|
|
15
|
-
itemGap:
|
|
16
|
-
// gap between the icon slot and the label inside a tab (Figma: none)
|
|
17
|
-
itemIconLabelGap: 0,
|
|
18
|
-
// .Nav/Background: no backdrop blur, so use the Figma Blur=Off spec (opacity 95%, no blur) plus the 1px
|
|
19
|
-
// border — nearly solid, matching the frosted sample; surface keeps dark-mode support
|
|
20
|
-
backgroundOpacity: 0.95,
|
|
21
|
-
// white 60% hairline around the center action button (Figma Icon Button border)
|
|
22
|
-
ctaBorderOpacity: 0.6,
|
|
15
|
+
itemGap: Spacing.XS,
|
|
23
16
|
iconSize: 24,
|
|
24
17
|
// active indicator behind the icon: 24 icon + XS·M padding
|
|
25
18
|
indicatorPaddingVertical: Spacing.XS,
|
|
@@ -32,9 +25,6 @@ const TabBarMetrics = {
|
|
|
32
25
|
systemIndicatorHeight: 24,
|
|
33
26
|
foldableMinShortSide: 600,
|
|
34
27
|
foldableWidthRatio: 0.65,
|
|
35
|
-
// a 2-tab bar doesn't stretch to the full width: each item is this fixed width and the bar is
|
|
36
|
-
// sized to its content, centered (Figma Navigation · 2 Tab: item 100, bar ~225)
|
|
37
|
-
twoTabItemWidth: 100,
|
|
38
28
|
ctaSlotWidth: 92,
|
|
39
29
|
ctaSize: 48,
|
|
40
30
|
ctaIconSize: 28,
|
|
@@ -142,17 +132,7 @@ const getHorizontalBarWidth = (
|
|
|
142
132
|
height: number,
|
|
143
133
|
insetLeft: number,
|
|
144
134
|
insetRight: number,
|
|
145
|
-
itemCount: number,
|
|
146
|
-
hasCta: boolean,
|
|
147
135
|
) => {
|
|
148
|
-
// 2 tabs (no center action) stay content-sized and centered instead of filling the window
|
|
149
|
-
if (itemCount === 2 && !hasCta) {
|
|
150
|
-
return (
|
|
151
|
-
TabBarMetrics.twoTabItemWidth * 2 +
|
|
152
|
-
TabBarMetrics.paddingHorizontal * 2 +
|
|
153
|
-
TabBarMetrics.itemGap
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
136
|
const shortSide = Math.min(width, height);
|
|
157
137
|
if (shortSide >= TabBarMetrics.foldableMinShortSide) {
|
|
158
138
|
return shortSide * TabBarMetrics.foldableWidthRatio;
|
package/Popup/PopupNotify.tsx
CHANGED
|
@@ -150,7 +150,7 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
|
|
|
150
150
|
return text;
|
|
151
151
|
}
|
|
152
152
|
return segments.map((segment, index) => {
|
|
153
|
-
if (segment.
|
|
153
|
+
if (segment.isHighlighted) {
|
|
154
154
|
return (
|
|
155
155
|
<Text key={index} typography={'header_s_semibold'}>
|
|
156
156
|
{segment.text}
|
package/Popup/utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type HighlightSegment = { text: string;
|
|
1
|
+
type HighlightSegment = { text: string; isHighlighted: boolean };
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* True for cased-script letters, digits and `_`; caseless scripts (CJK, Thai)
|
|
@@ -46,12 +46,15 @@ const splitHighlightText = (
|
|
|
46
46
|
continue;
|
|
47
47
|
}
|
|
48
48
|
if (start > lastIndex) {
|
|
49
|
-
segments.push({
|
|
49
|
+
segments.push({
|
|
50
|
+
text: text.slice(lastIndex, start),
|
|
51
|
+
isHighlighted: false,
|
|
52
|
+
});
|
|
50
53
|
}
|
|
51
|
-
segments.push({ text: match[0],
|
|
54
|
+
segments.push({ text: match[0], isHighlighted: true });
|
|
52
55
|
lastIndex = end;
|
|
53
56
|
}
|
|
54
|
-
segments.push({ text: text.slice(lastIndex),
|
|
57
|
+
segments.push({ text: text.slice(lastIndex), isHighlighted: false });
|
|
55
58
|
return segments;
|
|
56
59
|
};
|
|
57
60
|
|