@momo-kits/foundation 0.169.4-beta.4 → 0.169.4-beta.6

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,6 +18,7 @@ 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';
21
22
  import {
22
23
  useBottomSheetLayout,
23
24
  useDuoKeyboardLift,
@@ -173,11 +174,16 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
173
174
  );
174
175
 
175
176
  const screen = (
176
- <Screen
177
- {...props}
178
- {...props.route.params}
179
- onRequestClose={onRequestClose}
180
- />
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>
181
187
  );
182
188
 
183
189
  return (
@@ -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 { CappedScaleText } from './TabBarIcon';
20
+ import { FixedScaleText } 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
- <CappedScaleText>{labelText}</CappedScaleText>
117
+ <FixedScaleText>{labelText}</FixedScaleText>
118
118
  ) : (
119
119
  labelText
120
120
  )}
@@ -194,17 +194,21 @@ const HorizontalTabBar: React.FC<{
194
194
  return renderItems(items);
195
195
  };
196
196
 
197
+ const customContainer = withCta && floatingButton?.container;
198
+
197
199
  return (
198
200
  <View
199
201
  style={[styles.container, { width }]}
200
202
  accessibilityLabel={'bottom_tab_bar'}
201
203
  >
202
- <CurvedContainer
203
- width={width}
204
- height={TabBarMetrics.height}
205
- radius={TabBarMetrics.height / 2}
206
- notchCenterX={withCta ? width / 2 : undefined}
207
- />
204
+ {customContainer || (
205
+ <CurvedContainer
206
+ width={width}
207
+ height={TabBarMetrics.height}
208
+ radius={TabBarMetrics.height / 2}
209
+ notchCenterX={withCta ? width / 2 : undefined}
210
+ />
211
+ )}
208
212
  <View style={styles.content}>
209
213
  <ActiveIndicator
210
214
  axis={'x'}
@@ -254,7 +258,6 @@ export default function BottomTabBar(props: Props) {
254
258
  ]}
255
259
  >
256
260
  <HorizontalTabBar
257
- fixedFontScale
258
261
  items={getTabItems(props)}
259
262
  width={width}
260
263
  floatingButton={floatingButton}
@@ -10,7 +10,7 @@ import Animated, {
10
10
  useSharedValue,
11
11
  withTiming,
12
12
  } from 'react-native-reanimated';
13
- import { CappedScaleText, TabBarIcon } from './TabBarIcon';
13
+ import { FixedScaleText, TabBarIcon } from './TabBarIcon';
14
14
  import { Text } from '../../Text';
15
15
  import { MiniAppContext } from '../../Context';
16
16
  import { Colors, Spacing } from '../../Consts';
@@ -98,7 +98,7 @@ const TabItemContent: React.FC<TabItemContentProps> = ({
98
98
  />
99
99
  </View>
100
100
  {!hideLabel &&
101
- (fixedFontScale ? <CappedScaleText>{text}</CappedScaleText> : text)}
101
+ (fixedFontScale ? <FixedScaleText>{text}</FixedScaleText> : text)}
102
102
  </>
103
103
  );
104
104
  };
@@ -166,11 +166,6 @@ 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',
174
169
  },
175
170
  label: {
176
171
  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 { CappedScaleText } from './TabBarIcon';
16
+ import { FixedScaleText } 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
- <CappedScaleText>
119
+ <FixedScaleText>
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
- </CappedScaleText>
127
+ </FixedScaleText>
128
128
  {floatingButton.labelContent && (
129
129
  <View pointerEvents={'none'} style={styles.railCtaLabelOverlay}>
130
130
  {floatingButton.labelContent}
@@ -71,30 +71,6 @@ 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
-
98
74
  /**
99
75
  * numbers use the error color, text the warning color (Figma Badge round numeric / text)
100
76
  */
@@ -20,9 +20,6 @@ const TabBarMetrics = {
20
20
  indicatorPaddingHorizontal: Spacing.M,
21
21
  indicatorRadius: Radius.XL,
22
22
  indicatorHeight: 32,
23
- // label_s_medium line height: the label box keeps this height so a scaled label grows
24
- // downward instead of pushing the icon up
25
- labelHeight: 18,
26
23
  // home indicator / gesture bar area under the container
27
24
  systemIndicatorHeight: 24,
28
25
  // unfolded foldables (short side from 600, the smallest in the spec) use 65% of the short
@@ -0,0 +1,123 @@
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 };
@@ -0,0 +1,147 @@
1
+ import React from 'react';
2
+ import { InteractionManager, Platform } from 'react-native';
3
+
4
+ import { MiniAppContext } from '../../Context';
5
+ import { adoptionStore } from './AdoptionStore';
6
+ import { SETTLE_MS } from './constants';
7
+ import type {
8
+ FiberLike,
9
+ KitRegistries,
10
+ ScreenSnapshot,
11
+ WalkResult,
12
+ } from './types';
13
+ import {
14
+ createRegistries,
15
+ getAppId,
16
+ getCurrentFiber,
17
+ isAdoptionEnabled,
18
+ walkScreen,
19
+ } from './utils';
20
+
21
+ type NavigationLike = {
22
+ addListener?: (event: string, callback: () => void) => () => void;
23
+ };
24
+
25
+ type ProbeProps = {
26
+ screenName: string;
27
+ navigation?: NavigationLike;
28
+ children: React.ReactNode;
29
+ };
30
+
31
+ let registriesCache: KitRegistries | undefined;
32
+
33
+ /**
34
+ * Kit and RN identity sets, built on first use. Lazy require breaks the cycle
35
+ * between the foundation index and the Application screens that render this probe.
36
+ */
37
+ const getRegistries = (): KitRegistries => {
38
+ if (!registriesCache) {
39
+ const kitModule = require('../../index') as Record<string, unknown>;
40
+ const rnModule = require('react-native') as Record<string, unknown>;
41
+ registriesCache = createRegistries([kitModule], rnModule);
42
+ }
43
+ return registriesCache;
44
+ };
45
+
46
+ /** Foundation version from its package.json, or undefined if it cannot be read. */
47
+ const readFoundationVersion = (): string | undefined => {
48
+ try {
49
+ const pkg = require('../../package.json') as { version?: string };
50
+ return pkg.version;
51
+ } catch {
52
+ return undefined;
53
+ }
54
+ };
55
+
56
+ const createErrorResult = (): WalkResult => ({
57
+ counts: { K: 0, R: 0, O: 0 },
58
+ kit: {},
59
+ rn: {},
60
+ other: {},
61
+ top_transparent: [],
62
+ fibers: 0,
63
+ truncated: false,
64
+ status: 'error',
65
+ });
66
+
67
+ /** Stops the walk at nested probes so each screen is measured on its own. */
68
+ const isProbeFiber = (fiber: FiberLike): boolean =>
69
+ fiber.type === AdoptionProbeDev;
70
+
71
+ /** Passes children through with no measurement. Used in release builds. */
72
+ const PassThrough = (props: ProbeProps): React.JSX.Element => (
73
+ <>{props.children}</>
74
+ );
75
+
76
+ /**
77
+ * Dev-only wrapper around a screen. Measures the screen's fiber tree after
78
+ * the first interactions settle, and again on focus, when kit adoption is on.
79
+ */
80
+ class AdoptionProbeDev extends React.Component<ProbeProps> {
81
+ static contextType = MiniAppContext;
82
+
83
+ private timer: ReturnType<typeof setTimeout> | undefined;
84
+ private interaction: { cancel: () => void } | undefined;
85
+ private unsubscribeFocus: (() => void) | undefined;
86
+
87
+ componentDidMount(): void {
88
+ if (!isAdoptionEnabled(this.context)) return;
89
+ adoptionStore.setActive(this.measure);
90
+ this.unsubscribeFocus = this.props.navigation?.addListener?.(
91
+ 'focus',
92
+ this.handleFocus,
93
+ );
94
+ this.interaction = InteractionManager.runAfterInteractions(() => {
95
+ this.timer = setTimeout(this.measure, SETTLE_MS);
96
+ });
97
+ }
98
+
99
+ componentWillUnmount(): void {
100
+ if (this.timer !== undefined) clearTimeout(this.timer);
101
+ this.interaction?.cancel();
102
+ this.unsubscribeFocus?.();
103
+ adoptionStore.clearActive(this.measure);
104
+ }
105
+
106
+ render(): React.ReactNode {
107
+ return this.props.children;
108
+ }
109
+
110
+ private handleFocus = (): void => {
111
+ adoptionStore.setActive(this.measure);
112
+ };
113
+
114
+ private measure = (): void => {
115
+ const startedAt = Date.now();
116
+ let result: WalkResult;
117
+ try {
118
+ const self = getCurrentFiber(
119
+ (this as unknown as { _reactInternals: FiberLike })._reactInternals,
120
+ );
121
+ const root = self.child;
122
+ if (!root) return;
123
+ result = walkScreen(root, getRegistries(), isProbeFiber);
124
+ } catch {
125
+ result = createErrorResult();
126
+ }
127
+ this.save(result, startedAt);
128
+ };
129
+
130
+ private save(result: WalkResult, startedAt: number): void {
131
+ const snapshot: ScreenSnapshot = {
132
+ ...result,
133
+ app_id: getAppId(this.context),
134
+ screen_name: this.props.screenName,
135
+ foundation_version: readFoundationVersion(),
136
+ platform: Platform.OS,
137
+ ts: Date.now(),
138
+ walk_ms: Date.now() - startedAt,
139
+ };
140
+ adoptionStore.save(snapshot);
141
+ }
142
+ }
143
+
144
+ const AdoptionProbe = __DEV__ ? AdoptionProbeDev : PassThrough;
145
+
146
+ export type { NavigationLike, ProbeProps };
147
+ export { AdoptionProbe, AdoptionProbeDev };
@@ -0,0 +1,80 @@
1
+ import type { ScreenSnapshot } from './types';
2
+
3
+ type Listener = () => void;
4
+ type Measure = () => void;
5
+
6
+ /** Total classified nodes in a snapshot, used to keep the richer measurement. */
7
+ const getTotal = (snapshot: ScreenSnapshot): number =>
8
+ snapshot.counts.K + snapshot.counts.R + snapshot.counts.O;
9
+
10
+ const getKey = (snapshot: ScreenSnapshot): string =>
11
+ `${snapshot.app_id}/${snapshot.screen_name}`;
12
+
13
+ /**
14
+ * In-memory, dev-only store of per-screen snapshots. Keeps one snapshot per
15
+ * app and screen (the one with the most nodes) and holds the active measurer.
16
+ */
17
+ class AdoptionStore {
18
+ private snapshots = new Map<string, ScreenSnapshot>();
19
+ private listeners = new Set<Listener>();
20
+ private latestKey: string | undefined;
21
+ private activeMeasure: Measure | undefined;
22
+
23
+ /** Stores a snapshot unless the stored one for the same screen is larger. */
24
+ save(snapshot: ScreenSnapshot): void {
25
+ const key = getKey(snapshot);
26
+ const existing = this.snapshots.get(key);
27
+ if (!existing || getTotal(existing) <= getTotal(snapshot)) {
28
+ this.snapshots.set(key, snapshot);
29
+ }
30
+ this.latestKey = key;
31
+ this.notify();
32
+ }
33
+
34
+ getAll(): ScreenSnapshot[] {
35
+ return Array.from(this.snapshots.values());
36
+ }
37
+
38
+ /** The screen saved most recently, or undefined when nothing is saved. */
39
+ getLatest(): ScreenSnapshot | undefined {
40
+ return this.latestKey === undefined
41
+ ? undefined
42
+ : this.snapshots.get(this.latestKey);
43
+ }
44
+
45
+ clear(): void {
46
+ this.snapshots.clear();
47
+ this.latestKey = undefined;
48
+ this.notify();
49
+ }
50
+
51
+ /** Registers a change listener and returns its unsubscribe function. */
52
+ subscribe(listener: Listener): () => void {
53
+ this.listeners.add(listener);
54
+ return () => {
55
+ this.listeners.delete(listener);
56
+ };
57
+ }
58
+
59
+ setActive(measure: Measure): void {
60
+ this.activeMeasure = measure;
61
+ }
62
+
63
+ /** Clears the active measurer only if it is still the given one. */
64
+ clearActive(measure: Measure): void {
65
+ if (this.activeMeasure === measure) this.activeMeasure = undefined;
66
+ }
67
+
68
+ remeasureActive(): void {
69
+ this.activeMeasure?.();
70
+ }
71
+
72
+ private notify(): void {
73
+ this.listeners.forEach(listener => listener());
74
+ }
75
+ }
76
+
77
+ const adoptionStore = new AdoptionStore();
78
+
79
+ export type { Listener, Measure };
80
+ export { AdoptionStore, adoptionStore };
@@ -0,0 +1,104 @@
1
+ const SETTLE_MS = 3000;
2
+ const MAX_FIBERS = 20000;
3
+ const SLOT_SCAN_DEPTH = 4;
4
+ const TOP_TRANSPARENT_LIMIT = 10;
5
+
6
+ // Generic lib names (Badge, Title, Logo, ...) are left out on purpose so app components with the same name are not counted as kit.
7
+ const LIB_UNIT_NAMES: string[] = [
8
+ 'AutoComplete',
9
+ 'Avatar',
10
+ 'Calendar',
11
+ 'Carousel',
12
+ 'Chip',
13
+ 'Collapse',
14
+ 'DateTimePicker',
15
+ 'ProgressInfo',
16
+ 'Rating',
17
+ 'Slider',
18
+ 'Stepper',
19
+ 'Steps',
20
+ 'SuggestAction',
21
+ 'Swipe',
22
+ 'TabView',
23
+ 'TabBar',
24
+ 'CardTabBar',
25
+ 'ScrollableTabBar',
26
+ 'HeaderSliderBanner',
27
+ 'TrustBanner',
28
+ 'Uploader',
29
+ ];
30
+
31
+ const RN_PRIMITIVE_NAMES: string[] = [
32
+ 'View',
33
+ 'Text',
34
+ 'Image',
35
+ 'ImageBackground',
36
+ 'TextInput',
37
+ 'ScrollView',
38
+ 'FlatList',
39
+ 'SectionList',
40
+ 'VirtualizedList',
41
+ 'TouchableOpacity',
42
+ 'TouchableHighlight',
43
+ 'TouchableWithoutFeedback',
44
+ 'Pressable',
45
+ 'Switch',
46
+ 'ActivityIndicator',
47
+ 'Modal',
48
+ 'KeyboardAvoidingView',
49
+ 'RefreshControl',
50
+ ];
51
+
52
+ /** Foundation exports that come from third-party or RN and must not count as kit. */
53
+ const FOUNDATION_REEXPORT_NAMES: string[] = [
54
+ 'TouchableOpacity',
55
+ 'LinearGradient',
56
+ 'SafeAreaView',
57
+ 'SafeAreaProvider',
58
+ 'SafeAreaConsumer',
59
+ 'SafeAreaInsetsContext',
60
+ 'SafeAreaFrameContext',
61
+ 'withSafeAreaInsets',
62
+ ];
63
+
64
+ const FIBER_TAG = {
65
+ FunctionComponent: 0,
66
+ ClassComponent: 1,
67
+ HostRoot: 3,
68
+ HostComponent: 5,
69
+ HostText: 6,
70
+ Fragment: 7,
71
+ ContextProvider: 10,
72
+ ForwardRef: 11,
73
+ MemoComponent: 14,
74
+ SimpleMemoComponent: 15,
75
+ } as const;
76
+
77
+ /** Fiber tags that are component fibers; every other tag is walked through without counting. */
78
+ const COUNTED_FIBER_TAGS: number[] = [
79
+ FIBER_TAG.FunctionComponent,
80
+ FIBER_TAG.ClassComponent,
81
+ FIBER_TAG.HostComponent,
82
+ FIBER_TAG.ForwardRef,
83
+ FIBER_TAG.SimpleMemoComponent,
84
+ ];
85
+
86
+ const HOST_RN_PREFIXES: string[] = ['RCT', 'Android'];
87
+
88
+ const REACT_MEMO_TYPE = Symbol.for('react.memo');
89
+ const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');
90
+
91
+ export {
92
+ COUNTED_FIBER_TAGS,
93
+ FIBER_TAG,
94
+ FOUNDATION_REEXPORT_NAMES,
95
+ HOST_RN_PREFIXES,
96
+ LIB_UNIT_NAMES,
97
+ MAX_FIBERS,
98
+ REACT_FORWARD_REF_TYPE,
99
+ REACT_MEMO_TYPE,
100
+ RN_PRIMITIVE_NAMES,
101
+ SETTLE_MS,
102
+ SLOT_SCAN_DEPTH,
103
+ TOP_TRANSPARENT_LIMIT,
104
+ };
@@ -0,0 +1,5 @@
1
+ import { AdoptionBadge } from './AdoptionBadge';
2
+ import { AdoptionProbe } from './AdoptionProbe';
3
+ import { adoptionStore } from './AdoptionStore';
4
+
5
+ export { AdoptionBadge, AdoptionProbe, adoptionStore };