@momo-kits/foundation 0.169.4-beta.6 → 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.
@@ -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 (
@@ -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
  },
@@ -17,7 +17,7 @@ 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';
20
+ import { CappedScaleText } from './TabBarIcon';
21
21
  import { styles } from './BottomTabBar.styles';
22
22
 
23
23
  type Props = BottomTabBarProps & {
@@ -114,7 +114,7 @@ const CenterAction: React.FC<{
114
114
  </Animated.View>
115
115
  <View style={styles.ctaLabel}>
116
116
  {fixedFontScale ? (
117
- <FixedScaleText>{labelText}</FixedScaleText>
117
+ <CappedScaleText>{labelText}</CappedScaleText>
118
118
  ) : (
119
119
  labelText
120
120
  )}
@@ -194,21 +194,17 @@ const HorizontalTabBar: React.FC<{
194
194
  return renderItems(items);
195
195
  };
196
196
 
197
- const customContainer = withCta && floatingButton?.container;
198
-
199
197
  return (
200
198
  <View
201
199
  style={[styles.container, { width }]}
202
200
  accessibilityLabel={'bottom_tab_bar'}
203
201
  >
204
- {customContainer || (
205
- <CurvedContainer
206
- width={width}
207
- height={TabBarMetrics.height}
208
- radius={TabBarMetrics.height / 2}
209
- notchCenterX={withCta ? width / 2 : undefined}
210
- />
211
- )}
202
+ <CurvedContainer
203
+ width={width}
204
+ height={TabBarMetrics.height}
205
+ radius={TabBarMetrics.height / 2}
206
+ notchCenterX={withCta ? width / 2 : undefined}
207
+ />
212
208
  <View style={styles.content}>
213
209
  <ActiveIndicator
214
210
  axis={'x'}
@@ -241,6 +237,8 @@ export default function BottomTabBar(props: Props) {
241
237
  window.height,
242
238
  insets.left,
243
239
  insets.right,
240
+ state.routes.length,
241
+ withCta,
244
242
  );
245
243
 
246
244
  return (
@@ -258,6 +256,7 @@ export default function BottomTabBar(props: Props) {
258
256
  ]}
259
257
  >
260
258
  <HorizontalTabBar
259
+ fixedFontScale
261
260
  items={getTabItems(props)}
262
261
  width={width}
263
262
  floatingButton={floatingButton}
@@ -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 { CappedScaleText, 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: {
@@ -98,7 +98,7 @@ const TabItemContent: React.FC<TabItemContentProps> = ({
98
98
  />
99
99
  </View>
100
100
  {!hideLabel &&
101
- (fixedFontScale ? <FixedScaleText>{text}</FixedScaleText> : text)}
101
+ (fixedFontScale ? <CappedScaleText>{text}</CappedScaleText> : text)}
102
102
  </>
103
103
  );
104
104
  };
@@ -147,7 +147,7 @@ const styles = StyleSheet.create({
147
147
  minWidth: 1,
148
148
  alignItems: 'center',
149
149
  justifyContent: 'center',
150
- gap: Spacing.XXS,
150
+ gap: TabBarMetrics.itemIconLabelGap,
151
151
  },
152
152
  slot: {
153
153
  height: TabBarMetrics.indicatorHeight,
@@ -166,6 +166,11 @@ const styles = StyleSheet.create({
166
166
  },
167
167
  labelBox: {
168
168
  alignSelf: 'stretch',
169
+ // fixed to the design line height so a capped-scale label overflows downward and the
170
+ // icon above it stays put
171
+ height: TabBarMetrics.labelHeight,
172
+ justifyContent: 'flex-start',
173
+ overflow: 'visible',
169
174
  },
170
175
  label: {
171
176
  textAlign: 'center',
@@ -13,7 +13,7 @@ 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';
16
+ import { CappedScaleText } from './TabBarIcon';
17
17
  import { usePressLift } from './usePressLift';
18
18
  import { ActiveIndicator } from './ActiveIndicator';
19
19
  import {
@@ -116,7 +116,7 @@ const RailCenterAction: React.FC<{ floatingButton: FloatingButtonProps }> = ({
116
116
  <CtaIcon icon={floatingButton.icon} />
117
117
  </Animated.View>
118
118
  <View style={styles.railCtaLabel}>
119
- <FixedScaleText>
119
+ <CappedScaleText>
120
120
  <Text
121
121
  numberOfLines={1}
122
122
  typography={'label_xs_medium'}
@@ -124,7 +124,7 @@ const RailCenterAction: React.FC<{ floatingButton: FloatingButtonProps }> = ({
124
124
  >
125
125
  {floatingButton.label}
126
126
  </Text>
127
- </FixedScaleText>
127
+ </CappedScaleText>
128
128
  {floatingButton.labelContent && (
129
129
  <View pointerEvents={'none'} style={styles.railCtaLabelOverlay}>
130
130
  {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
@@ -45,8 +50,15 @@ const DuoFloatingTabBar: React.FC<DuoTabBarProps> = props => {
45
50
  >
46
51
  <HorizontalTabBar
47
52
  fixedFontScale
48
- items={getTabItems(props)}
49
- width={getHorizontalBarWidth(width, height, insets.left, insets.right)}
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}
@@ -71,6 +71,30 @@ export const FixedScaleText: React.FC<{ children: React.ReactNode }> = ({
71
71
  );
72
72
  };
73
73
 
74
+ // the tab labels follow the OS/host font scale but never grow past this, so the fixed-height
75
+ // container and the notch stay aligned
76
+ const TAB_LABEL_MAX_SCALE = 1.2;
77
+
78
+ /**
79
+ * caps the label scale at `TAB_LABEL_MAX_SCALE`: it keeps following the host/OS font scale but
80
+ * stops growing past 1.2× so it fits the fixed bar geometry
81
+ */
82
+ export const CappedScaleText: React.FC<{ children: React.ReactNode }> = ({
83
+ children,
84
+ }) => {
85
+ const context = useContext<any>(MiniAppContext);
86
+ return (
87
+ <MiniAppContext.Provider
88
+ value={{
89
+ ...context,
90
+ fontScale: { ...context?.fontScale, maxScaleRate: TAB_LABEL_MAX_SCALE },
91
+ }}
92
+ >
93
+ {children}
94
+ </MiniAppContext.Provider>
95
+ );
96
+ };
97
+
74
98
  /**
75
99
  * numbers use the error color, text the warning color (Figma Badge round numeric / text)
76
100
  */
@@ -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/Text/utils.ts CHANGED
@@ -9,13 +9,18 @@ const MAX_DEVICE_SCALE = 5;
9
9
  const useScaleSize = (size: number, scaleRate?: number) => {
10
10
  const { width } = useWindowDimensions();
11
11
  const context = useContext<any>(MiniAppContext);
12
+ // opt-in ceiling: when set (arg or context), the final size never exceeds size × capRate,
13
+ // in both the mini-app userScaleRate path and the OS path. Undefined keeps the old behavior.
14
+ const capRate = scaleRate ?? context?.fontScale?.maxScaleRate;
15
+ const cap = (scaled: number) =>
16
+ capRate != null ? Math.min(scaled, size * capRate) : scaled;
12
17
  if (context?.fontScale?.useOSScaleRate === false) {
13
- return size * (context.fontScale.userScaleRate ?? 1);
18
+ return cap(size * (context.fontScale.userScaleRate ?? 1));
14
19
  }
15
20
  const fontScale = PixelRatio.getFontScale();
16
21
  const deviceScale = width / DEFAULT_SCREEN_SIZE;
17
22
 
18
- const maxScaleRate = scaleRate ?? MAX_FONT_SCALE;
23
+ const maxScaleRate = capRate ?? MAX_FONT_SCALE;
19
24
 
20
25
  let fontSizeDeviceScale = size;
21
26
  let fontSizeOSScale = size;
@@ -34,7 +39,7 @@ const useScaleSize = (size: number, scaleRate?: number) => {
34
39
  );
35
40
  }
36
41
 
37
- return Math.max(fontSizeDeviceScale, fontSizeOSScale);
42
+ return cap(Math.max(fontSizeDeviceScale, fontSizeOSScale));
38
43
  };
39
44
 
40
45
  const scaleSize = (size: number) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.169.4-beta.6",
3
+ "version": "0.169.4-beta.7",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {},
@@ -1,123 +0,0 @@
1
- import React, { useContext, 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 { MiniAppContext } from '../../Context';
7
- import { Text } from '../../Text';
8
- import { adoptionStore } from './AdoptionStore';
9
- import { styles } from './styles';
10
- import type { ScreenSnapshot } from './types';
11
- import { isAdoptionEnabled } from './utils';
12
-
13
- /** Subscribes a React listener to the adoption store. Stable identity for useSyncExternalStore. */
14
- const subscribeToStore = (listener: () => void): (() => void) =>
15
- adoptionStore.subscribe(listener);
16
-
17
- const getLatestSnapshot = (): ScreenSnapshot | undefined =>
18
- adoptionStore.getLatest();
19
-
20
- const getScreenCount = (): number => adoptionStore.getAll().length;
21
-
22
- /** Share of classified nodes that are app-authored kit: K / (K + R + O). */
23
- const getAdoptionRate = (snapshot: ScreenSnapshot): number => {
24
- const { K, R, O } = snapshot.counts;
25
- const total = K + R + O;
26
- return total === 0 ? 0 : K / total;
27
- };
28
-
29
- const formatSummary = (snapshot: ScreenSnapshot | undefined): string => {
30
- if (!snapshot) return 'Kit adoption: chưa có dữ liệu';
31
- const { K, R, O } = snapshot.counts;
32
- const percent = Math.round(getAdoptionRate(snapshot) * 100);
33
- return `Kit ${percent}% · K${K} R${R} O${O}`;
34
- };
35
-
36
- const handleRemeasure = (): void => {
37
- adoptionStore.remeasureActive();
38
- };
39
-
40
- const handleShare = (): void => {
41
- Share.share({ message: JSON.stringify(adoptionStore.getAll()) }).catch(
42
- () => undefined,
43
- );
44
- };
45
-
46
- const handleClear = (): void => {
47
- adoptionStore.clear();
48
- };
49
-
50
- /**
51
- * Dev-only floating badge showing the latest screen's kit adoption. Tap to
52
- * expand actions (re-measure, share JSON, clear). Renders nothing in release
53
- * builds or when kit adoption is off.
54
- */
55
- const AdoptionBadge: React.FC = () => {
56
- const context = useContext<unknown>(MiniAppContext);
57
- const insets = useSafeAreaInsets();
58
- const [isExpanded, setExpanded] = useState(false);
59
- const latest = useSyncExternalStore(subscribeToStore, getLatestSnapshot);
60
- const screenCount = useSyncExternalStore(subscribeToStore, getScreenCount);
61
-
62
- if (!__DEV__ || !isAdoptionEnabled(context)) return null;
63
-
64
- const handleToggle = (): void => setExpanded(prev => !prev);
65
-
66
- return (
67
- <View
68
- pointerEvents="box-none"
69
- style={[styles.wrapper, { top: insets.top + Spacing.S }]}
70
- >
71
- <TouchableOpacity
72
- accessibilityRole="button"
73
- onPress={handleToggle}
74
- style={styles.badge}
75
- >
76
- <Text typography="label_xs_medium" color={Colors.black_01}>
77
- {formatSummary(latest)}
78
- </Text>
79
- {latest ? (
80
- <Text typography="description_xs_regular" color={Colors.black_01}>
81
- {latest.screen_name}
82
- </Text>
83
- ) : null}
84
- </TouchableOpacity>
85
- {isExpanded ? (
86
- <View style={styles.panel}>
87
- <Text typography="label_xs_medium" color={Colors.black_17}>
88
- {`Đã đo ${screenCount} màn hình`}
89
- </Text>
90
- <TouchableOpacity
91
- accessibilityRole="button"
92
- onPress={handleRemeasure}
93
- style={styles.action}
94
- >
95
- <Text typography="label_xs_medium" color={Colors.blue_03}>
96
- Đo lại
97
- </Text>
98
- </TouchableOpacity>
99
- <TouchableOpacity
100
- accessibilityRole="button"
101
- onPress={handleShare}
102
- style={styles.action}
103
- >
104
- <Text typography="label_xs_medium" color={Colors.blue_03}>
105
- Share JSON
106
- </Text>
107
- </TouchableOpacity>
108
- <TouchableOpacity
109
- accessibilityRole="button"
110
- onPress={handleClear}
111
- style={styles.actionOutline}
112
- >
113
- <Text typography="label_xs_medium" color={Colors.black_17}>
114
- Xoá
115
- </Text>
116
- </TouchableOpacity>
117
- </View>
118
- ) : null}
119
- </View>
120
- );
121
- };
122
-
123
- export { AdoptionBadge };