@momo-kits/foundation 0.89.6 → 0.92.1-tracking.12

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.
@@ -8,7 +8,7 @@ import {NavigationContainer} from '@react-navigation/native';
8
8
  import {Icon} from '../Icon';
9
9
  import {Text} from '../Text';
10
10
  import {ApplicationContext} from './index';
11
- import {getStackOptions} from './utils';
11
+ import {getAccessibilityID, getStackOptions} from './utils';
12
12
  import StackScreen from './StackScreen';
13
13
 
14
14
  const Tab = createBottomTabNavigator();
@@ -58,8 +58,11 @@ const BottomTab: React.FC<BottomTabProps> = ({
58
58
  });
59
59
  }, []);
60
60
 
61
+ const accessibilityID = getAccessibilityID?.("tbr_main_bottom")
62
+
61
63
  return (
62
64
  <Tab.Navigator
65
+ {...accessibilityID}
63
66
  initialRouteName={initialRouteName}
64
67
  backBehavior={'firstRoute'}
65
68
  tabBarOptions={{
@@ -72,8 +75,10 @@ const BottomTab: React.FC<BottomTabProps> = ({
72
75
  },
73
76
  }}>
74
77
  {tabs.map(item => {
78
+ const itemAccessibilityID = getAccessibilityID?.(`btn_tabbar_${item.name}`)
75
79
  return (
76
80
  <Tab.Screen
81
+ {...itemAccessibilityID}
77
82
  key={item.name}
78
83
  name={item.name}
79
84
  component={TabScreen}
@@ -29,6 +29,7 @@ import {scaleSize, Text} from '../Text';
29
29
  import {Icon} from '../Icon';
30
30
  import {PopupNotify} from '../Popup';
31
31
  import {Badge, BadgeDot} from '../Badge';
32
+ import {getAccessibilityID} from './utils';
32
33
 
33
34
  const NavigationButton: React.FC<NavigationButtonProps> = ({
34
35
  icon,
@@ -37,6 +38,7 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
37
38
  useBorder = true,
38
39
  badgeType,
39
40
  badgeValue,
41
+ accessibilityID = '',
40
42
  }) => {
41
43
  const {theme} = useContext(ApplicationContext);
42
44
  let buttonStyle: ViewStyle = {backgroundColor: '#00000066'};
@@ -63,8 +65,9 @@ const NavigationButton: React.FC<NavigationButtonProps> = ({
63
65
  }
64
66
  }, [badgeType, badgeValue]);
65
67
 
68
+ const ID = getAccessibilityID?.(accessibilityID);
66
69
  return (
67
- <View style={{width: scaleSize(28)}}>
70
+ <View {...ID} style={{width: scaleSize(28)}}>
68
71
  <TouchableOpacity
69
72
  style={[styles.navigationButton, buttonStyle]}
70
73
  onPress={onPress}>
@@ -90,6 +93,7 @@ const HeaderTitle: React.FC<any> = props => {
90
93
  return (
91
94
  <Animated.Text
92
95
  {...props}
96
+ accessibilityLabel={getAccessibilityID('title_navigation_header')}
93
97
  style={[
94
98
  styles.title,
95
99
  {fontFamily: `${theme.font}-Bold`, opacity, color: props.tintColor},
@@ -166,10 +170,10 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
166
170
  }
167
171
  return true;
168
172
  };
169
-
170
173
  return (
171
174
  <View style={styles.headerLeft}>
172
175
  <NavigationButton
176
+ accessibilityID="btn_navigation_back"
173
177
  icon="ic_back"
174
178
  tintColor={tintColor}
175
179
  onPress={goBackSafe}
@@ -243,7 +247,10 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
243
247
  )}
244
248
  </View>
245
249
  <View style={[Styles.flex, {paddingHorizontal: 8}]}>
246
- <Text typography="header_default_bold" color={tintColor}>
250
+ <Text
251
+ {...getAccessibilityID('title_navigation_header')}
252
+ typography="header_default_bold"
253
+ color={tintColor}>
247
254
  {title}
248
255
  </Text>
249
256
  <Text typography="description_default_regular" color={tintColor}>
@@ -369,6 +376,7 @@ const HeaderToolkitAction: React.FC<any> = ({
369
376
  if (pinTool)
370
377
  return (
371
378
  <NavigationButton
379
+ accessibilityID="btn_navigation_pin"
372
380
  icon={pinTool.icon as string}
373
381
  tintColor={tintColor}
374
382
  badgeValue={badgeValue}
@@ -386,7 +394,6 @@ const HeaderToolkitAction: React.FC<any> = ({
386
394
  />
387
395
  );
388
396
  };
389
-
390
397
  if (toolConfig) {
391
398
  return (
392
399
  <View style={styles.headerRightButton}>
@@ -399,11 +406,15 @@ const HeaderToolkitAction: React.FC<any> = ({
399
406
  borderWidth: backgroundColor ? 0.5 : 0,
400
407
  },
401
408
  ]}>
402
- <TouchableOpacity onPress={onMore}>
409
+ <TouchableOpacity
410
+ {...getAccessibilityID?.('btn_navigation_more')}
411
+ onPress={onMore}>
403
412
  <Icon color={tintColor} source="navigation_more_horiz" size={20} />
404
413
  </TouchableOpacity>
405
414
  <View style={[styles.divider, {backgroundColor: tintColor}]} />
406
- <TouchableOpacity onPress={onClose}>
415
+ <TouchableOpacity
416
+ {...getAccessibilityID?.('btn_navigation_close')}
417
+ onPress={onClose}>
407
418
  <Icon
408
419
  color={tintColor}
409
420
  source="16_navigation_close_circle"
@@ -1,21 +1,29 @@
1
- import React, {useContext, useEffect, useRef} from 'react';
1
+ import React, {useContext, useEffect, useMemo, useRef, useState} from 'react';
2
2
  import {
3
+ Dimensions,
4
+ Keyboard,
3
5
  KeyboardAvoidingView,
4
6
  Platform,
5
7
  Pressable,
6
8
  StyleSheet,
7
- TouchableOpacity,
8
9
  View,
9
10
  } from 'react-native';
10
- import {Modalize} from 'react-native-modalize';
11
11
  import {SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
12
-
13
- import {ApplicationContext} from '.';
14
- import {Radius, Spacing, Styles} from '../Consts';
15
- import {Icon} from '../Icon';
16
- import {Text} from '../Text';
12
+ import {
13
+ BottomSheetBackdrop,
14
+ BottomSheetModal,
15
+ BottomSheetView,
16
+ } from '@gorhom/bottom-sheet';
17
17
  import Navigation from './Navigation';
18
18
  import {BottomSheetParams, ModalParams} from './types';
19
+ import {Radius, Spacing, Styles} from '../Consts';
20
+ import {
21
+ ApplicationContext,
22
+ HeaderRightAction,
23
+ NavigationButton,
24
+ NavigationContainer,
25
+ } from './index';
26
+ import {HeaderBackground, HeaderLeft, HeaderTitle} from './Components';
19
27
 
20
28
  const ModalScreen: React.FC<any> = props => {
21
29
  /**
@@ -84,88 +92,141 @@ const Modal: React.FC<ModalParams> = props => {
84
92
  };
85
93
 
86
94
  const BottomSheet: React.FC<BottomSheetParams> = props => {
95
+ const insets = useSafeAreaInsets();
87
96
  const {theme, navigator} = useContext(ApplicationContext);
88
- const {
89
- screen: Screen,
90
- options,
91
- footerComponent,
92
- flatListProps,
93
- }: BottomSheetParams = props.route.params;
94
-
97
+ const [keyboardSnap, setKeyboardSnap] = useState(0);
98
+ const {screen, options, snapPoint, indicatorColor}: BottomSheetParams =
99
+ props.route.params;
100
+ const Component = useRef(screen).current;
95
101
  const navigation = new Navigation(props.navigation, theme);
96
-
97
102
  const params = {
98
103
  ...props.route.params,
99
104
  navigation,
100
105
  };
101
106
 
102
107
  delete params.screen;
103
- const modalizeRef = useRef<Modalize>(null);
108
+
109
+ const snapPoints = useMemo(() => {
110
+ if (snapPoint) {
111
+ const current = parseInt(snapPoint) + keyboardSnap * 100;
112
+ return [`${current}%`];
113
+ }
114
+ return ['50%', '70%', '90%'];
115
+ }, [keyboardSnap]);
116
+
117
+ const bottomSheetRef = useRef<any>(null);
118
+ const mountedRef = useRef(true);
119
+
120
+ let backgroundColor = theme.colors.background.default;
121
+ let bottomInset = keyboardSnap * Dimensions.get('window').height;
122
+ if (bottomInset > 16) {
123
+ bottomInset -= 16;
124
+ }
125
+ if (options?.surface) {
126
+ backgroundColor = theme.colors.background.surface;
127
+ }
104
128
 
105
129
  useEffect(() => {
106
- modalizeRef.current?.open();
130
+ const keyboardDidShow = Keyboard.addListener('keyboardDidShow', e => {
131
+ setKeyboardSnap(
132
+ e.endCoordinates.height / Dimensions.get('window').height,
133
+ );
134
+ bottomSheetRef.current?.expand();
135
+ });
136
+
137
+ const keyboardDidHide = Keyboard.addListener('keyboardDidHide', () => {
138
+ setKeyboardSnap(0);
139
+ });
140
+
141
+ bottomSheetRef.current?.present();
142
+ return () => {
143
+ mountedRef.current = false;
144
+ keyboardDidShow.remove();
145
+ keyboardDidHide.remove();
146
+ };
107
147
  }, []);
108
148
 
109
- const handleClose = () => {
110
- modalizeRef?.current?.close();
111
- };
149
+ const backdropComponent = (backdropProps: any) => (
150
+ <BottomSheetBackdrop
151
+ disappearsOnIndex={-1}
152
+ appearsOnIndex={0}
153
+ {...backdropProps}
154
+ />
155
+ );
112
156
 
113
157
  return (
114
158
  <SafeAreaView style={Styles.flex}>
115
- <Modalize
116
- keyboardAvoidingOffset={-20}
117
- adjustToContentHeight
118
- closeOnOverlayTap
119
- closeSnapPointStraightEnabled
120
- onClosed={() => {
121
- navigator?.pop();
159
+ <BottomSheetModal
160
+ ref={bottomSheetRef}
161
+ snapPoints={snapPoints}
162
+ onDismiss={() => {
163
+ if (mountedRef.current) {
164
+ navigator?.pop();
165
+ }
122
166
  }}
123
- ref={modalizeRef}
124
- withHandle={false}
125
- flatListProps={flatListProps}
126
- HeaderComponent={headerDefault(
127
- options?.title ?? options?.customTitle?.title ?? '',
128
- handleClose,
129
- )}
130
- FooterComponent={footerDefault(footerComponent)}>
131
- <View style={styles.bottomSheetContainer}>
132
- <Screen {...props} {...params} />
133
- </View>
134
- </Modalize>
167
+ bottomInset={Platform.OS === 'ios' ? bottomInset : 0}
168
+ handleComponent={null}
169
+ backdropComponent={backdropComponent}>
170
+ <BottomSheetView>
171
+ <View style={[styles.sheetContainer, {backgroundColor}]}>
172
+ <View style={styles.indicatorContainer}>
173
+ <View
174
+ style={[
175
+ styles.indicator,
176
+ {backgroundColor: theme.colors.text.disable},
177
+ ]}
178
+ />
179
+ </View>
180
+ <NavigationContainer
181
+ maxApi={navigator?.maxApi}
182
+ theme={{
183
+ ...theme,
184
+ assets: {...theme.assets, headerBackground: undefined},
185
+ }}
186
+ screen={props => <Component {...props} {...params} />}
187
+ options={{
188
+ ...options,
189
+ ...{
190
+ headerLeft: (props: any) => {
191
+ if (props.canGoBack) {
192
+ return <HeaderLeft {...props} useBorder={false} />;
193
+ }
194
+ },
195
+ headerTitle: (props: any) => {
196
+ return <HeaderTitle {...props} />;
197
+ },
198
+ headerTintColor: theme.colors.text.default,
199
+ headerBackground: () => (
200
+ <HeaderBackground backgroundColor={backgroundColor} />
201
+ ),
202
+ headerTransparent: false,
203
+ },
204
+ headerTitleAlign: 'center',
205
+ headerRight: props => (
206
+ <HeaderRightAction>
207
+ <NavigationButton
208
+ {...props}
209
+ icon="24_navigation_close"
210
+ useBorder={false}
211
+ onPress={() => bottomSheetRef.current?.dismiss()}
212
+ />
213
+ </HeaderRightAction>
214
+ ),
215
+ }}
216
+ />
217
+ <View
218
+ style={{
219
+ height: Math.min(insets.bottom, 20),
220
+ backgroundColor: indicatorColor ?? backgroundColor,
221
+ }}
222
+ />
223
+ </View>
224
+ </BottomSheetView>
225
+ </BottomSheetModal>
135
226
  </SafeAreaView>
136
227
  );
137
228
  };
138
229
 
139
- const headerDefault = (title: string, onClose: () => void) => {
140
- return (
141
- <View style={styles.header}>
142
- <Text
143
- style={styles.textOption}
144
- numberOfLines={2}
145
- typography="header_default_bold">
146
- {title ?? ''}
147
- </Text>
148
- <TouchableOpacity style={styles.buttonClose} onPress={onClose}>
149
- <Icon source="navigation_close" />
150
- </TouchableOpacity>
151
- </View>
152
- );
153
- };
154
-
155
- const footerDefault = (footerComponent: React.ReactNode) => {
156
- const insets = useSafeAreaInsets();
157
- if (!footerComponent) return;
158
- return (
159
- <View
160
- style={{
161
- marginBottom: Math.min(insets.bottom, 21) + Spacing.S,
162
- paddingHorizontal: 12,
163
- }}>
164
- {footerComponent}
165
- </View>
166
- );
167
- };
168
-
169
230
  const styles = StyleSheet.create({
170
231
  container: {flex: 1, flexDirection: 'row'},
171
232
  modalContent: {
@@ -202,43 +263,6 @@ const styles = StyleSheet.create({
202
263
  height: 4,
203
264
  borderRadius: Radius.S,
204
265
  },
205
- bottomSheetContainer: {
206
- width: '100%',
207
- backgroundColor: 'white',
208
- borderTopRightRadius: 16,
209
- borderTopLeftRadius: 16,
210
- },
211
- header: {
212
- height: 50,
213
- width: '100%',
214
- alignItems: 'center',
215
- justifyContent: 'center',
216
- },
217
- textOption: {
218
- fontSize: 16,
219
- color: '#303233',
220
- textAlign: 'center',
221
- fontWeight: 'bold',
222
- paddingHorizontal: 60,
223
- },
224
- imageOption: {
225
- height: 1,
226
- backgroundColor: '#ebebeb',
227
- width: '100%',
228
- position: 'absolute',
229
- bottom: 1,
230
- },
231
- buttonClose: {
232
- padding: 12,
233
- position: 'absolute',
234
- right: 0,
235
- },
236
- icon: {
237
- width: 24,
238
- height: 24,
239
- tintColor: '#303233',
240
- backgroundColor: 'red',
241
- },
242
266
  });
243
267
 
244
268
  export default ModalScreen;
@@ -1,4 +1,5 @@
1
1
  import React, {useContext, useEffect, useRef, useState} from 'react';
2
+ import {BottomSheetModalProvider} from '@gorhom/bottom-sheet';
2
3
  import {SafeAreaProvider} from 'react-native-safe-area-context';
3
4
  import {
4
5
  NavigationContainer as ReactNavigationContainer,
@@ -22,6 +23,7 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
22
23
  options,
23
24
  maxApi,
24
25
  localization,
26
+ initialParams,
25
27
  }) => {
26
28
  const context = useContext(MiniAppContext);
27
29
  const navigationRef = useRef<NavigationContainerRef>(null);
@@ -67,53 +69,55 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
67
69
 
68
70
  return (
69
71
  <SafeAreaProvider>
70
- <ApplicationContext.Provider
71
- value={{
72
- navigator: navigator.current,
73
- config: config.current,
74
- theme,
75
- showGrid,
76
- translate,
77
- }}>
78
- <ReactNavigationContainer
79
- theme={{
80
- ...theme,
81
- colors: {
82
- ...theme.colors,
83
- background: theme.colors.background.default,
84
- card: theme.colors.background.surface,
85
- text: theme.colors.text.default,
86
- border: theme.colors.border.default,
87
- notification: theme.colors.error.primary,
88
- },
89
- }}
90
- ref={navigator.current?.ref}
91
- onReady={() => {
92
- isReady.current = true;
93
- }}
94
- independent={true}>
95
- <Stack.Navigator initialRouteName="Stack" headerMode="screen">
96
- <Stack.Screen
97
- name="Stack"
98
- component={StackScreen}
99
- initialParams={{screen}}
100
- options={{...getStackOptions(), ...options}}
101
- />
102
- <Stack.Screen
103
- name="Dialog"
104
- component={StackScreen}
105
- options={getDialogOptions()}
106
- initialParams={{screen}}
107
- />
108
- <Stack.Screen
109
- name="Modal"
110
- component={ModalScreen}
111
- options={getModalOptions()}
112
- initialParams={{screen}}
113
- />
114
- </Stack.Navigator>
115
- </ReactNavigationContainer>
116
- </ApplicationContext.Provider>
72
+ <BottomSheetModalProvider>
73
+ <ApplicationContext.Provider
74
+ value={{
75
+ navigator: navigator.current,
76
+ config: config.current,
77
+ theme,
78
+ showGrid,
79
+ translate,
80
+ }}>
81
+ <ReactNavigationContainer
82
+ theme={{
83
+ ...theme,
84
+ colors: {
85
+ ...theme.colors,
86
+ background: theme.colors.background.default,
87
+ card: theme.colors.background.surface,
88
+ text: theme.colors.text.default,
89
+ border: theme.colors.border.default,
90
+ notification: theme.colors.error.primary,
91
+ },
92
+ }}
93
+ ref={navigator.current?.ref}
94
+ onReady={() => {
95
+ isReady.current = true;
96
+ }}
97
+ independent={true}>
98
+ <Stack.Navigator initialRouteName="Stack" headerMode="screen">
99
+ <Stack.Screen
100
+ name="Stack"
101
+ component={StackScreen}
102
+ initialParams={{screen, initialParams}}
103
+ options={{...getStackOptions(), ...options}}
104
+ />
105
+ <Stack.Screen
106
+ name="Dialog"
107
+ component={StackScreen}
108
+ options={getDialogOptions()}
109
+ initialParams={{screen}}
110
+ />
111
+ <Stack.Screen
112
+ name="Modal"
113
+ component={ModalScreen}
114
+ options={getModalOptions()}
115
+ initialParams={{screen}}
116
+ />
117
+ </Stack.Navigator>
118
+ </ReactNavigationContainer>
119
+ </ApplicationContext.Provider>
120
+ </BottomSheetModalProvider>
117
121
  </SafeAreaProvider>
118
122
  );
119
123
  };
@@ -1,29 +1,53 @@
1
- import React, {useContext, useEffect, useLayoutEffect} from 'react';
1
+ import React, {useContext, useEffect, useLayoutEffect, useRef} from 'react';
2
2
  import {ScreenParams} from './types';
3
3
  import Navigation from './Navigation';
4
4
  import {ApplicationContext, MiniAppContext} from './index';
5
5
  import {GridSystem} from '../Layout';
6
6
  import {useHeaderHeight} from '@react-navigation/stack';
7
+ import {Alert, InteractionManager} from 'react-native';
8
+
9
+ const {
10
+ ScreenContext,
11
+ } = require('react-native/Libraries/Components/ScreenContext');
7
12
 
8
13
  const StackScreen: React.FC<ScreenParams> = props => {
9
14
  const {theme, showGrid, navigator} = useContext(ApplicationContext);
15
+ const startTime = useRef(Date.now());
16
+ const endTime = useRef(Date.now());
17
+ const timeLoad = useRef(0);
18
+ const timeout = useRef<any>();
19
+
10
20
  const context = useContext(MiniAppContext);
11
21
 
12
- const {screen: Component, options}: ScreenParams = props.route.params;
22
+ const {
23
+ screen: Component,
24
+ options,
25
+ initialParams,
26
+ }: ScreenParams = props.route.params;
13
27
  const navigation = new Navigation(props.navigation, theme);
14
28
  const heightHeader = useHeaderHeight();
15
29
 
16
- const params = {
30
+ const data = {
17
31
  ...props.route.params,
32
+ ...initialParams,
18
33
  navigation,
19
34
  };
20
35
 
21
- delete params.screen;
36
+ delete data.screen;
37
+ delete data.initialParams;
22
38
 
23
39
  /**
24
40
  * set options for screen
25
41
  */
26
42
  useLayoutEffect(() => {
43
+ InteractionManager.runAfterInteractions(() => {
44
+ navigator?.maxApi?.showToastDebug?.({
45
+ appId: context.appId,
46
+ message: `${Component.name} screen_interaction_time ${
47
+ Date.now() - startTime.current
48
+ }`,
49
+ });
50
+ });
27
51
  if (options) {
28
52
  navigation.setOptions(options);
29
53
  }
@@ -33,6 +57,15 @@ const StackScreen: React.FC<ScreenParams> = props => {
33
57
  * tracking for screen
34
58
  */
35
59
  useEffect(() => {
60
+ if (__DEV__) {
61
+ if (!Component.name || Component.name === 'screen') {
62
+ Alert.alert(
63
+ 'Design system',
64
+ `Unvalidated screen name "${Component.name}" !`,
65
+ );
66
+ }
67
+ }
68
+
36
69
  const tracking = {
37
70
  ...context,
38
71
  screen_name: Component.name,
@@ -73,10 +106,35 @@ const StackScreen: React.FC<ScreenParams> = props => {
73
106
  }, []);
74
107
 
75
108
  return (
76
- <>
77
- <Component heightHeader={heightHeader} {...params} />
109
+ <ScreenContext.Provider
110
+ value={{
111
+ appId: context.appId,
112
+ code: context.code,
113
+ screenName: Component.name,
114
+ autoTracking: (data: any) => {
115
+ navigator?.maxApi?.dispatchFunction?.('autoTracking', data);
116
+ },
117
+ onElementLoad: () => {
118
+ endTime.current = Date.now();
119
+ clearTimeout(timeout.current);
120
+ timeout.current = setTimeout(() => {
121
+ if (timeLoad.current === 0) {
122
+ timeLoad.current = endTime.current - startTime.current;
123
+ navigator?.maxApi?.showToastDebug?.({
124
+ appId: context.appId,
125
+ message: `${Component.name} screen_load_time ${timeLoad.current}`,
126
+ });
127
+ }
128
+ }, 1000);
129
+ },
130
+ }}>
131
+ <Component
132
+ heightHeader={heightHeader}
133
+ {...data}
134
+ onScreenLoad={() => {}}
135
+ />
78
136
  {showGrid && <GridSystem />}
79
- </>
137
+ </ScreenContext.Provider>
80
138
  );
81
139
  };
82
140
 
@@ -1,4 +1,4 @@
1
- import {Animated, FlatListProps, ViewProps} from 'react-native';
1
+ import {Animated, ViewProps} from 'react-native';
2
2
  import {StackNavigationOptions} from '@react-navigation/stack';
3
3
  import React from 'react';
4
4
  import Navigator from './Navigator';
@@ -94,6 +94,7 @@ export type NavigationContainerProps = {
94
94
  options?: NavigationOptions;
95
95
  theme: Theme;
96
96
  maxApi: any;
97
+ initialParams: Record<string, any>;
97
98
  localization?: LocalizationObject;
98
99
  };
99
100
 
@@ -118,8 +119,8 @@ export interface ModalParams extends ScreenParams {
118
119
  export interface BottomSheetParams extends ScreenParams {
119
120
  [key: string]: any;
120
121
  onDismiss?: () => void;
121
- footerComponent?: React.ReactNode;
122
- flatListProps: FlatListProps<any>;
122
+ snapPoint?: '30%' | '50%' | '70%' | '90%' | 'content';
123
+ indicatorColor?: string;
123
124
  }
124
125
 
125
126
  export type NavigationButtonProps = {
@@ -129,6 +130,7 @@ export type NavigationButtonProps = {
129
130
  onPress: () => void;
130
131
  badgeType?: 'dot' | 'number';
131
132
  badgeValue?: number;
133
+ accessibilityID?: string;
132
134
  };
133
135
 
134
136
  export type PinnedToolType = {