@momo-kits/foundation 0.169.5-beta.1 → 0.169.6-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.
@@ -18,7 +18,6 @@ import Animated, {
18
18
  } from 'react-native-reanimated';
19
19
  import { scheduleOnRN } from 'react-native-worklets';
20
20
  import { DUO_ORIENTATIONS, styles } from './BottomSheet.styles';
21
- import { AdoptionProbe } from './KitAdoption';
22
21
  import {
23
22
  useBottomSheetLayout,
24
23
  useDuoKeyboardLift,
@@ -174,16 +173,11 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
174
173
  );
175
174
 
176
175
  const screen = (
177
- <AdoptionProbe
178
- screenName={Screen?.name || 'Invalid'}
179
- navigation={props.navigation}
180
- >
181
- <Screen
182
- {...props}
183
- {...props.route.params}
184
- onRequestClose={onRequestClose}
185
- />
186
- </AdoptionProbe>
176
+ <Screen
177
+ {...props}
178
+ {...props.route.params}
179
+ onRequestClose={onRequestClose}
180
+ />
187
181
  );
188
182
 
189
183
  return (
@@ -2,6 +2,20 @@ 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
+
5
19
  export const styles = StyleSheet.create({
6
20
  bar: {
7
21
  position: 'absolute',
@@ -37,7 +51,7 @@ export const styles = StyleSheet.create({
37
51
  position: 'absolute',
38
52
  left: 0,
39
53
  right: 0,
40
- top: -TabBarMetrics.ctaLift - TabBarMetrics.paddingVertical,
54
+ top: CTA_TOP,
41
55
  alignItems: 'center',
42
56
  gap: TabBarMetrics.ctaLabelGap,
43
57
  },
@@ -46,6 +60,9 @@ export const styles = StyleSheet.create({
46
60
  width: TabBarMetrics.ctaSize,
47
61
  height: TabBarMetrics.ctaSize,
48
62
  borderRadius: TabBarMetrics.ctaSize / 2,
63
+ // Figma Icon Button border: white 60% hairline
64
+ borderWidth: 1,
65
+ borderColor: `rgba(255, 255, 255, ${TabBarMetrics.ctaBorderOpacity})`,
49
66
  alignItems: 'center',
50
67
  justifyContent: 'center',
51
68
  },
@@ -17,7 +17,6 @@ import { CurvedContainer } from './CurvedContainer';
17
17
  import { ActiveIndicator } from './ActiveIndicator';
18
18
  import { getHorizontalBarWidth, TabBarMetrics, TabBarMotion } from './metrics';
19
19
  import { getTabItems, TabItem } from './tabItems';
20
- import { FixedScaleText } from './TabBarIcon';
21
20
  import { styles } from './BottomTabBar.styles';
22
21
 
23
22
  type Props = BottomTabBarProps & {
@@ -68,8 +67,7 @@ const useCenterActionPress = () => {
68
67
  */
69
68
  const CenterAction: React.FC<{
70
69
  floatingButton: FloatingButtonProps;
71
- fixedFontScale?: boolean;
72
- }> = ({ floatingButton, fixedFontScale }) => {
70
+ }> = ({ floatingButton }) => {
73
71
  const { theme } = useContext(ApplicationContext);
74
72
  const context = useContext<any>(MiniAppContext);
75
73
  const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
@@ -113,11 +111,7 @@ const CenterAction: React.FC<{
113
111
  )}
114
112
  </Animated.View>
115
113
  <View style={styles.ctaLabel}>
116
- {fixedFontScale ? (
117
- <FixedScaleText>{labelText}</FixedScaleText>
118
- ) : (
119
- labelText
120
- )}
114
+ {labelText}
121
115
  {labelContent && (
122
116
  <View pointerEvents={'none'} style={styles.ctaLabelOverlay}>
123
117
  {labelContent}
@@ -139,14 +133,12 @@ const HorizontalTabBar: React.FC<{
139
133
  activeTintColor: string;
140
134
  inactiveTintColor: string;
141
135
  floatingButton?: FloatingButtonProps;
142
- fixedFontScale?: boolean;
143
136
  }> = ({
144
137
  items,
145
138
  width,
146
139
  activeTintColor,
147
140
  inactiveTintColor,
148
141
  floatingButton,
149
- fixedFontScale,
150
142
  }) => {
151
143
  const withCta = hasCenterAction(floatingButton, items.length);
152
144
  const [layouts, setLayouts] = useState<
@@ -173,7 +165,6 @@ const HorizontalTabBar: React.FC<{
173
165
  onLongPress={item.onLongPress}
174
166
  activeTintColor={activeTintColor}
175
167
  inactiveTintColor={inactiveTintColor}
176
- fixedFontScale={fixedFontScale}
177
168
  />
178
169
  ));
179
170
 
@@ -183,10 +174,7 @@ const HorizontalTabBar: React.FC<{
183
174
  return (
184
175
  <>
185
176
  {renderItems(items.slice(0, middle))}
186
- <CenterAction
187
- floatingButton={floatingButton}
188
- fixedFontScale={fixedFontScale}
189
- />
177
+ <CenterAction floatingButton={floatingButton} />
190
178
  {renderItems(items.slice(middle))}
191
179
  </>
192
180
  );
@@ -194,21 +182,17 @@ const HorizontalTabBar: React.FC<{
194
182
  return renderItems(items);
195
183
  };
196
184
 
197
- const customContainer = withCta && floatingButton?.container;
198
-
199
185
  return (
200
186
  <View
201
187
  style={[styles.container, { width }]}
202
188
  accessibilityLabel={'bottom_tab_bar'}
203
189
  >
204
- {customContainer || (
205
- <CurvedContainer
206
- width={width}
207
- height={TabBarMetrics.height}
208
- radius={TabBarMetrics.height / 2}
209
- notchCenterX={withCta ? width / 2 : undefined}
210
- />
211
- )}
190
+ <CurvedContainer
191
+ width={width}
192
+ height={TabBarMetrics.height}
193
+ radius={TabBarMetrics.height / 2}
194
+ notchCenterX={withCta ? width / 2 : undefined}
195
+ />
212
196
  <View style={styles.content}>
213
197
  <ActiveIndicator
214
198
  axis={'x'}
@@ -241,6 +225,8 @@ export default function BottomTabBar(props: Props) {
241
225
  window.height,
242
226
  insets.left,
243
227
  insets.right,
228
+ state.routes.length,
229
+ withCta,
244
230
  );
245
231
 
246
232
  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 } 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 d={path} fill={theme.colors.background.surface} />
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
  };
@@ -10,10 +10,10 @@ import Animated, {
10
10
  useSharedValue,
11
11
  withTiming,
12
12
  } from 'react-native-reanimated';
13
- import { FixedScaleText, TabBarIcon } from './TabBarIcon';
13
+ import { TabBarIcon } from './TabBarIcon';
14
14
  import { Text } from '../../Text';
15
15
  import { MiniAppContext } from '../../Context';
16
- import { Colors, Spacing } from '../../Consts';
16
+ import { Colors } from '../../Consts';
17
17
  import { TabBarMetrics, TabBarMotion } from './metrics';
18
18
 
19
19
  type IconRenderer = (props: {
@@ -31,8 +31,6 @@ type TabItemContentProps = {
31
31
  badge?: string | number;
32
32
  // rail item (.Nav/Duo/Item) instead of the horizontal one (.Nav/itemTab)
33
33
  vertical?: boolean;
34
- // keep the label at its design size, the Duo displays otherwise scale it up
35
- fixedFontScale?: boolean;
36
34
  hideLabel?: boolean;
37
35
  };
38
36
 
@@ -48,7 +46,6 @@ const TabItemContent: React.FC<TabItemContentProps> = ({
48
46
  icon,
49
47
  badge,
50
48
  vertical,
51
- fixedFontScale,
52
49
  hideLabel,
53
50
  }) => {
54
51
  const progress = useSharedValue(focused ? 1 : 0);
@@ -97,8 +94,7 @@ const TabItemContent: React.FC<TabItemContentProps> = ({
97
94
  renderIcon={icon}
98
95
  />
99
96
  </View>
100
- {!hideLabel &&
101
- (fixedFontScale ? <FixedScaleText>{text}</FixedScaleText> : text)}
97
+ {!hideLabel && text}
102
98
  </>
103
99
  );
104
100
  };
@@ -147,7 +143,7 @@ const styles = StyleSheet.create({
147
143
  minWidth: 1,
148
144
  alignItems: 'center',
149
145
  justifyContent: 'center',
150
- gap: Spacing.XXS,
146
+ gap: TabBarMetrics.itemIconLabelGap,
151
147
  },
152
148
  slot: {
153
149
  height: TabBarMetrics.indicatorHeight,
@@ -166,6 +162,11 @@ const styles = StyleSheet.create({
166
162
  },
167
163
  labelBox: {
168
164
  alignSelf: 'stretch',
165
+ // fixed to the design line height so a capped-scale label overflows downward and the
166
+ // icon above it stays put
167
+ height: TabBarMetrics.labelHeight,
168
+ justifyContent: 'flex-start',
169
+ overflow: 'visible',
169
170
  },
170
171
  label: {
171
172
  textAlign: 'center',
@@ -13,7 +13,6 @@ import { TabItemContent } from './CustomBottomTabItem';
13
13
  import { CurvedContainer } from './CurvedContainer';
14
14
  import { TabBarMetrics } from './metrics';
15
15
  import { getTabItems, TabItem } from './tabItems';
16
- import { FixedScaleText } from './TabBarIcon';
17
16
  import { usePressLift } from './usePressLift';
18
17
  import { ActiveIndicator } from './ActiveIndicator';
19
18
  import {
@@ -76,7 +75,6 @@ const Rail: React.FC<{
76
75
  >
77
76
  <TabItemContent
78
77
  vertical
79
- fixedFontScale
80
78
  label={item.label}
81
79
  focused={item.focused}
82
80
  icon={item.icon}
@@ -116,7 +114,6 @@ const RailCenterAction: React.FC<{ floatingButton: FloatingButtonProps }> = ({
116
114
  <CtaIcon icon={floatingButton.icon} />
117
115
  </Animated.View>
118
116
  <View style={styles.railCtaLabel}>
119
- <FixedScaleText>
120
117
  <Text
121
118
  numberOfLines={1}
122
119
  typography={'label_xs_medium'}
@@ -124,7 +121,6 @@ const RailCenterAction: React.FC<{ floatingButton: FloatingButtonProps }> = ({
124
121
  >
125
122
  {floatingButton.label}
126
123
  </Text>
127
- </FixedScaleText>
128
124
  {floatingButton.labelContent && (
129
125
  <View pointerEvents={'none'} style={styles.railCtaLabelOverlay}>
130
126
  {floatingButton.labelContent}
@@ -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 { getSystemIndicatorHeight, HorizontalTabBar } from './BottomTabBar';
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
@@ -44,9 +49,15 @@ const DuoFloatingTabBar: React.FC<DuoTabBarProps> = props => {
44
49
  ]}
45
50
  >
46
51
  <HorizontalTabBar
47
- fixedFontScale
48
- items={getTabItems(props)}
49
- width={getHorizontalBarWidth(width, height, insets.left, insets.right)}
52
+ items={tabItems}
53
+ width={getHorizontalBarWidth(
54
+ width,
55
+ height,
56
+ insets.left,
57
+ insets.right,
58
+ tabItems.length,
59
+ hasCenterAction(floatingButton, tabItems.length),
60
+ )}
50
61
  floatingButton={floatingButton}
51
62
  activeTintColor={activeTintColor}
52
63
  inactiveTintColor={inactiveTintColor}
@@ -9,23 +9,36 @@ 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: 68,
12
+ height: 60,
13
13
  margin: Spacing.S,
14
- paddingVertical: Spacing.S,
14
+ paddingVertical: Spacing.XS,
15
15
  paddingHorizontal: Spacing.M,
16
- itemGap: Spacing.XS,
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,
20
27
  indicatorPaddingHorizontal: Spacing.M,
21
28
  indicatorRadius: Radius.XL,
22
29
  indicatorHeight: 32,
30
+ // label_s_medium line height: the label box keeps this height so a scaled label grows
31
+ // downward instead of pushing the icon up
32
+ labelHeight: 18,
23
33
  // home indicator / gesture bar area under the container
24
34
  systemIndicatorHeight: 24,
25
35
  // unfolded foldables (short side from 600, the smallest in the spec) use 65% of the short
26
36
  // side, centered; phones and folded outer displays fill the window
27
37
  foldableMinShortSide: 600,
28
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,
29
42
  ctaSlotWidth: 92,
30
43
  ctaSize: 48,
31
44
  // the icon sits 10 inside the 48 button (prototype .cta: 28 icon), 12 inside the 52 rail one
@@ -136,7 +149,17 @@ const getHorizontalBarWidth = (
136
149
  height: number,
137
150
  insetLeft: number,
138
151
  insetRight: number,
152
+ itemCount: number,
153
+ hasCta: boolean,
139
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
+ }
140
163
  const shortSide = Math.min(width, height);
141
164
  if (shortSide >= TabBarMetrics.foldableMinShortSide) {
142
165
  return shortSide * TabBarMetrics.foldableWidthRatio;
@@ -24,7 +24,6 @@ import Navigation from './Navigation';
24
24
  import { ModalParams } from './types';
25
25
  import BottomSheet from './BottomSheet';
26
26
  import { isIPhoneDuo } from './utils';
27
- import { AdoptionProbe } from './KitAdoption';
28
27
  import { useModalLayout } from './modalLayout';
29
28
  import { scheduleOnRN } from 'react-native-worklets';
30
29
 
@@ -183,12 +182,7 @@ const Modal: React.FC<ModalParams> = props => {
183
182
  modalStyle,
184
183
  ]}
185
184
  >
186
- <AdoptionProbe
187
- screenName={Component?.name || Component?.type?.name || 'Invalid'}
188
- navigation={props.navigation}
189
- >
190
- <Component {...params} onRequestClose={onDismiss} />
191
- </AdoptionProbe>
185
+ <Component {...params} onRequestClose={onDismiss} />
192
186
  </Animated.View>
193
187
  </KeyboardAvoidingView>
194
188
  </Container>
@@ -30,7 +30,6 @@ import { HeaderBackground } from './Components/HeaderBackground';
30
30
  import { useScreenLayout } from '../Layout';
31
31
  import { getHeaderRowOptions } from '../Layout/utils';
32
32
  import { ReservedRegionsProvider } from '../Layout/ReservedRegions';
33
- import { AdoptionBadge } from './KitAdoption';
34
33
 
35
34
  const Stack = createStackNavigator();
36
35
 
@@ -87,7 +86,6 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
87
86
  initialParams={initialParams}
88
87
  localize={localize}
89
88
  />
90
- <AdoptionBadge />
91
89
  </MiniAppContext.Provider>
92
90
  </ReservedRegionsProvider>
93
91
  </SafeAreaProvider>
@@ -8,7 +8,6 @@ import { SwipeBackHaptic } from './Components/SwipeBackHaptic';
8
8
  import { useAppState } from './hooks';
9
9
  import { createScreenTracking } from './StackScreen.tracking';
10
10
  import { TooltipPortalHost, TooltipPortalProvider } from './TooltipPortal';
11
- import { AdoptionProbe } from './KitAdoption';
12
11
 
13
12
  const runAfterInteractions = InteractionManager.runAfterInteractions;
14
13
 
@@ -284,9 +283,7 @@ const StackScreen: React.FC<any> = props => {
284
283
  }}
285
284
  >
286
285
  <TooltipPortalProvider>
287
- <AdoptionProbe screenName={screenName} navigation={props.navigation}>
288
- <Component heightHeader={heightHeader} {...data} />
289
- </AdoptionProbe>
286
+ <Component heightHeader={heightHeader} {...data} />
290
287
  <TooltipPortalHost />
291
288
  <SwipeBackHaptic />
292
289
  </TooltipPortalProvider>
@@ -36,7 +36,6 @@ export type BottomTabProps = {
36
36
  };
37
37
 
38
38
  export type FloatingButtonProps = {
39
- container?: React.ReactNode;
40
39
  icon: string | React.ReactNode;
41
40
  label: string;
42
41
  onPress: () => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.169.5-beta.1",
3
+ "version": "0.169.6-beta.1",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {},
@@ -1,119 +0,0 @@
1
- import React, { useState, useSyncExternalStore } from 'react';
2
- import { Share, TouchableOpacity, View } from 'react-native';
3
- import { useSafeAreaInsets } from 'react-native-safe-area-context';
4
-
5
- import { Colors, Spacing } from '../../Consts';
6
- import { Text } from '../../Text';
7
- import { adoptionStore } from './AdoptionStore';
8
- import { styles } from './styles';
9
- import type { ScreenSnapshot } from './types';
10
-
11
- /** Subscribes a React listener to the adoption store. Stable identity for useSyncExternalStore. */
12
- const subscribeToStore = (listener: () => void): (() => void) =>
13
- adoptionStore.subscribe(listener);
14
-
15
- const getLatestSnapshot = (): ScreenSnapshot | undefined =>
16
- adoptionStore.getLatest();
17
-
18
- const getScreenCount = (): number => adoptionStore.getAll().length;
19
-
20
- /** Share of classified nodes that are app-authored kit: K / (K + R + O). */
21
- const getAdoptionRate = (snapshot: ScreenSnapshot): number => {
22
- const { K, R, O } = snapshot.counts;
23
- const total = K + R + O;
24
- return total === 0 ? 0 : K / total;
25
- };
26
-
27
- const formatSummary = (snapshot: ScreenSnapshot | undefined): string => {
28
- if (!snapshot) return 'Kit adoption: chưa có dữ liệu';
29
- const { K, R, O } = snapshot.counts;
30
- const percent = Math.round(getAdoptionRate(snapshot) * 100);
31
- return `Kit ${percent}% · K${K} R${R} O${O}`;
32
- };
33
-
34
- const handleRemeasure = (): void => {
35
- adoptionStore.remeasureActive();
36
- };
37
-
38
- const handleShare = (): void => {
39
- Share.share({ message: JSON.stringify(adoptionStore.getAll()) }).catch(
40
- () => undefined,
41
- );
42
- };
43
-
44
- const handleClear = (): void => {
45
- adoptionStore.clear();
46
- };
47
-
48
- /**
49
- * Dev-only floating badge showing the latest screen's kit adoption. Tap to
50
- * expand actions (re-measure, share JSON, clear). Renders nothing in release builds.
51
- */
52
- const AdoptionBadge: React.FC = () => {
53
- const insets = useSafeAreaInsets();
54
- const [isExpanded, setExpanded] = useState(false);
55
- const latest = useSyncExternalStore(subscribeToStore, getLatestSnapshot);
56
- const screenCount = useSyncExternalStore(subscribeToStore, getScreenCount);
57
-
58
- if (!__DEV__) return null;
59
-
60
- const handleToggle = (): void => setExpanded(prev => !prev);
61
-
62
- return (
63
- <View
64
- pointerEvents="box-none"
65
- style={[styles.wrapper, { top: insets.top + Spacing.S }]}
66
- >
67
- <TouchableOpacity
68
- accessibilityRole="button"
69
- onPress={handleToggle}
70
- style={styles.badge}
71
- >
72
- <Text typography="label_xs_medium" color={Colors.black_01}>
73
- {formatSummary(latest)}
74
- </Text>
75
- {latest ? (
76
- <Text typography="description_xs_regular" color={Colors.black_01}>
77
- {latest.screen_name}
78
- </Text>
79
- ) : null}
80
- </TouchableOpacity>
81
- {isExpanded ? (
82
- <View style={styles.panel}>
83
- <Text typography="label_xs_medium" color={Colors.black_17}>
84
- {`Đã đo ${screenCount} màn hình`}
85
- </Text>
86
- <TouchableOpacity
87
- accessibilityRole="button"
88
- onPress={handleRemeasure}
89
- style={styles.action}
90
- >
91
- <Text typography="label_xs_medium" color={Colors.blue_03}>
92
- Đo lại
93
- </Text>
94
- </TouchableOpacity>
95
- <TouchableOpacity
96
- accessibilityRole="button"
97
- onPress={handleShare}
98
- style={styles.action}
99
- >
100
- <Text typography="label_xs_medium" color={Colors.blue_03}>
101
- Share JSON
102
- </Text>
103
- </TouchableOpacity>
104
- <TouchableOpacity
105
- accessibilityRole="button"
106
- onPress={handleClear}
107
- style={styles.actionOutline}
108
- >
109
- <Text typography="label_xs_medium" color={Colors.black_17}>
110
- Xoá
111
- </Text>
112
- </TouchableOpacity>
113
- </View>
114
- ) : null}
115
- </View>
116
- );
117
- };
118
-
119
- export { AdoptionBadge };