@momo-kits/foundation 0.79.6-beta.1 → 0.79.6-beta.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.
@@ -225,7 +225,11 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
225
225
  barStyle={headerImage || theme.dark ? 'light-content' : 'dark-content'}
226
226
  />
227
227
  {!!headerImage && (
228
- <Image style={styles.headerBackground} source={{uri: headerImage}} />
228
+ <Image
229
+ style={styles.headerBackground}
230
+ source={{uri: headerImage}}
231
+ loading={false}
232
+ />
229
233
  )}
230
234
  </Animated.View>
231
235
  );
@@ -1,11 +1,4 @@
1
- import React, {
2
- useCallback,
3
- useContext,
4
- useEffect,
5
- useMemo,
6
- useRef,
7
- useState,
8
- } from 'react';
1
+ import React, {useContext, useEffect, useMemo, useRef} from 'react';
9
2
  import {
10
3
  KeyboardAvoidingView,
11
4
  Platform,
@@ -13,8 +6,12 @@ import {
13
6
  StyleSheet,
14
7
  View,
15
8
  } from 'react-native';
16
- import {SafeAreaView} from 'react-native-safe-area-context';
17
- import {BottomSheetBackdrop, BottomSheetModal} from '@gorhom/bottom-sheet';
9
+ import {SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
10
+ import {
11
+ BottomSheetBackdrop,
12
+ BottomSheetModal,
13
+ BottomSheetView,
14
+ } from '@gorhom/bottom-sheet';
18
15
  import Navigation from './Navigation';
19
16
  import {BottomSheetParams, ModalParams} from './types';
20
17
  import {Radius, Spacing, Styles} from '../Consts';
@@ -90,12 +87,9 @@ const Modal: React.FC<ModalParams> = props => {
90
87
  };
91
88
 
92
89
  const BottomSheet: React.FC<BottomSheetParams> = props => {
90
+ const insets = useSafeAreaInsets();
93
91
  const {theme, navigator} = useContext(ApplicationContext);
94
- const {
95
- screen,
96
- options,
97
- useSnap = true,
98
- }: BottomSheetParams = props.route.params;
92
+ const {screen, options, snapPoint}: BottomSheetParams = props.route.params;
99
93
  const Component = useRef(screen).current;
100
94
  const navigation = new Navigation(props.navigation, theme);
101
95
  const params = {
@@ -105,31 +99,16 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
105
99
 
106
100
  delete params.screen;
107
101
 
108
- const [contentHeight, setContentHeight] = useState(undefined);
109
102
  const snapPoints = useMemo(() => {
110
- if (useSnap) {
111
- return ['50%', '90%'];
103
+ if (snapPoint) {
104
+ return [snapPoint];
112
105
  }
113
- return [contentHeight ?? '50%'];
114
- }, [contentHeight]);
106
+ return ['50%', '70%', '90%'];
107
+ }, []);
115
108
 
116
109
  const bottomSheetRef = useRef<any>(null);
117
110
  const mountedRef = useRef(true);
118
111
 
119
- let handleOnLayout;
120
- if (!useSnap) {
121
- handleOnLayout = useCallback(
122
- ({
123
- nativeEvent: {
124
- layout: {height},
125
- },
126
- }) => {
127
- setContentHeight(height);
128
- },
129
- [],
130
- );
131
- }
132
-
133
112
  let backgroundColor = theme.colors.background.default;
134
113
  if (options?.surface) {
135
114
  backgroundColor = theme.colors.background.surface;
@@ -162,8 +141,15 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
162
141
  }}
163
142
  handleComponent={null}
164
143
  backdropComponent={backdropComponent}>
165
- <View onLayout={handleOnLayout} accessibilityLabel={'BottomSheet'}>
166
- <View style={[styles.sheetContainer, {backgroundColor}]}>
144
+ <BottomSheetView accessibilityLabel={'BottomSheet'}>
145
+ <View
146
+ style={[
147
+ styles.sheetContainer,
148
+ {
149
+ backgroundColor,
150
+ paddingBottom: Math.min(insets.bottom, 20) + Spacing.S,
151
+ },
152
+ ]}>
167
153
  <View style={styles.indicatorContainer}>
168
154
  <View
169
155
  style={[
@@ -222,7 +208,7 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
222
208
  }}
223
209
  />
224
210
  </View>
225
- </View>
211
+ </BottomSheetView>
226
212
  </BottomSheetModal>
227
213
  </SafeAreaView>
228
214
  );
@@ -255,11 +241,12 @@ const styles = StyleSheet.create({
255
241
  indicatorContainer: {
256
242
  width: '100%',
257
243
  paddingTop: Spacing.S,
244
+ paddingBottom: Spacing.XS,
258
245
  alignItems: 'center',
259
246
  justifyContent: 'center',
260
247
  },
261
248
  indicator: {
262
- width: 64,
249
+ width: 40,
263
250
  height: 4,
264
251
  borderRadius: Radius.S,
265
252
  },
@@ -10,9 +10,10 @@ import StackScreen from './StackScreen';
10
10
  import ModalScreen from './ModalScreen';
11
11
  import Navigator from './Navigator';
12
12
  import {getDialogOptions, getModalOptions, getStackOptions} from './utils';
13
- import {NavigationContainerProps} from './types';
13
+ import {LocalizationObject, NavigationContainerProps} from './types';
14
14
  import {ApplicationContext} from './index';
15
15
  import {DeviceEventEmitter} from 'react-native';
16
+ import kitLocalization from '../Assets/language.json';
16
17
 
17
18
  const Stack = createStackNavigator();
18
19
 
@@ -52,7 +53,11 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
52
53
  navigator.current.maxApi = maxApi;
53
54
 
54
55
  const translate = (key: string) => {
55
- return localization?.[language]?.[key] || key;
56
+ const mergedLocalization: LocalizationObject = {
57
+ vi: {...localization?.vi, ...kitLocalization.vi},
58
+ en: {...localization?.en, ...kitLocalization.en},
59
+ };
60
+ return mergedLocalization?.[language]?.[key] || key;
56
61
  };
57
62
 
58
63
  return (
@@ -107,7 +107,7 @@ export interface ModalParams extends ScreenParams {
107
107
  export interface BottomSheetParams extends ScreenParams {
108
108
  [key: string]: any;
109
109
  onDismiss?: () => void;
110
- useSnap?: boolean;
110
+ snapPoint?: '30%' | '50%' | '70%' | '90%';
111
111
  }
112
112
 
113
113
  export type NavigationButtonProps = {
@@ -0,0 +1,171 @@
1
+ import React, {FC, useContext, useRef, useState} from 'react';
2
+ import {
3
+ KeyboardType,
4
+ NativeSyntheticEvent,
5
+ TextInput,
6
+ TextInputFocusEventData,
7
+ TouchableOpacity,
8
+ View,
9
+ } from 'react-native';
10
+ import {InputOTPProps} from './index';
11
+ import {Text} from '../Text';
12
+ import styles from './styles';
13
+ import {ErrorView, getBorderColor} from './common';
14
+ import {ApplicationContext} from '../Application';
15
+ import {Spacing} from '../Consts';
16
+ import OTPCaret from './OTPCaret';
17
+
18
+ const InputOTP: FC<InputOTPProps> = ({
19
+ length,
20
+ errorMessage,
21
+ errorSpacing,
22
+ floatingValue,
23
+ floatingIconColor,
24
+ floatingIcon,
25
+ placeholder,
26
+ onChangeText,
27
+ onFocus,
28
+ onBlur,
29
+ dataType = 'number',
30
+ ...props
31
+ }) => {
32
+ const MAX_LENGTH = 10;
33
+ const [value, setValue] = useState('');
34
+ const [focused, setFocused] = useState(false);
35
+ const inputRef = useRef<TextInput>(null);
36
+ const {theme} = useContext(ApplicationContext);
37
+
38
+ const onFocusInput = () => {
39
+ setFocused(true);
40
+ inputRef.current?.focus();
41
+ };
42
+
43
+ const onBlurInput = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
44
+ setFocused(false);
45
+ onBlur?.(e);
46
+ };
47
+
48
+ const _onChangeText = (text: string) => {
49
+ if (text.length > MAX_LENGTH) return;
50
+ if (dataType === 'number' && isNaN(Number(text))) return;
51
+ if (
52
+ !isNaN(Number(text)) &&
53
+ value.length >= Number(length) &&
54
+ text.length >= value.length
55
+ )
56
+ return;
57
+
58
+ setValue(text);
59
+ onChangeText?.(text);
60
+ };
61
+
62
+ const renderInputs = (length: number) => {
63
+ const TextInputs = [];
64
+ for (let i = 0; i < length; i++) {
65
+ TextInputs.push(
66
+ <View>
67
+ {focused && value.length === i ? (
68
+ <OTPCaret index={i} length={length} />
69
+ ) : (
70
+ <Text
71
+ style={i !== length - 1 && {marginRight: Spacing.L}}
72
+ color={
73
+ !!value[i] ? theme.colors.text.default : theme.colors.text.hint
74
+ }
75
+ typography={!!value[i] ? 'title_s' : 'paragraph_default'}>
76
+ {value[i] || '-'}
77
+ </Text>
78
+ )}
79
+ </View>,
80
+ );
81
+ }
82
+ return TextInputs;
83
+ };
84
+
85
+ const renderUnidentifiedInputs = () => {
86
+ const splitValue = value.split('');
87
+
88
+ if (!focused && value.length === 0 && !!placeholder) {
89
+ return (
90
+ <Text color={theme.colors.text.hint} typography={'description_s'}>
91
+ {placeholder}
92
+ </Text>
93
+ );
94
+ }
95
+
96
+ return (
97
+ <View style={{flexDirection: 'row'}}>
98
+ {splitValue.map((letter, index) => {
99
+ return (
100
+ <Text
101
+ style={
102
+ (index !== value.length - 1 ||
103
+ (focused && value.length !== MAX_LENGTH)) && {
104
+ marginRight: Spacing.L,
105
+ }
106
+ }
107
+ typography={'title_s'}>
108
+ {letter}
109
+ </Text>
110
+ );
111
+ })}
112
+ {focused && value.length !== MAX_LENGTH && <OTPCaret />}
113
+ </View>
114
+ );
115
+ };
116
+
117
+ const renderInputView = () => {
118
+ let placeholderColor = theme.colors.text.hint;
119
+ const keyboardType: KeyboardType =
120
+ dataType === 'number' ? 'number-pad' : 'default';
121
+ return (
122
+ <View
123
+ style={[
124
+ styles.otpInput,
125
+ {backgroundColor: theme.colors.background.surface},
126
+ getBorderColor(theme, focused, errorMessage),
127
+ ]}>
128
+ {!!floatingValue && (
129
+ <View
130
+ style={[
131
+ styles.otpFloatingView,
132
+ {backgroundColor: theme.colors.background.surface},
133
+ ]}>
134
+ <Text typography={'description_s'}>{floatingValue}</Text>
135
+ </View>
136
+ )}
137
+ <View style={styles.otpInputsView}>
138
+ {length ? renderInputs(length) : renderUnidentifiedInputs()}
139
+ </View>
140
+ <View style={styles.inputView}>
141
+ <TextInput
142
+ {...props}
143
+ accessibilityLabel={`TextInput`}
144
+ ref={inputRef}
145
+ value={value}
146
+ onChangeText={_onChangeText}
147
+ keyboardType={keyboardType}
148
+ onFocus={onFocusInput}
149
+ onBlur={onBlurInput}
150
+ style={{opacity: 0}}
151
+ selectionColor={theme.colors.primary}
152
+ placeholderTextColor={placeholderColor}
153
+ />
154
+ </View>
155
+ </View>
156
+ );
157
+ };
158
+
159
+ return (
160
+ <TouchableOpacity
161
+ activeOpacity={1}
162
+ onPress={onFocusInput}
163
+ style={styles.otpWrapper}
164
+ accessibilityLabel={`Input/${floatingValue}`}>
165
+ {renderInputView()}
166
+ <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
167
+ </TouchableOpacity>
168
+ );
169
+ };
170
+
171
+ export default InputOTP;
@@ -0,0 +1,50 @@
1
+ import React, {FC, useContext, useEffect, useRef} from 'react';
2
+ import {Animated, View} from 'react-native';
3
+ import {Spacing} from '../Consts';
4
+ import {scaleSize, Text} from '../Text';
5
+ import {ApplicationContext} from '../Application';
6
+ import {CaretProps} from './index';
7
+
8
+ const OtpCaret: FC<CaretProps> = ({index, length}) => {
9
+ const DURATION = 300;
10
+ const {theme} = useContext(ApplicationContext);
11
+ const opacity = useRef(new Animated.Value(0)).current;
12
+
13
+ useEffect(() => {
14
+ Animated.loop(
15
+ Animated.sequence([
16
+ Animated.timing(opacity, {
17
+ toValue: 1,
18
+ duration: DURATION,
19
+ useNativeDriver: true,
20
+ }),
21
+ Animated.delay(DURATION * 2),
22
+ Animated.timing(opacity, {
23
+ toValue: 0,
24
+ duration: DURATION,
25
+ useNativeDriver: true,
26
+ }),
27
+ ]),
28
+ ).start();
29
+ }, []);
30
+ const spacingStyle = !isNaN(Number(length)) &&
31
+ index !== Number(length) - 1 && {marginRight: Spacing.L};
32
+
33
+ return (
34
+ <View style={[{flexDirection: 'row', alignItems: 'center'}, spacingStyle]}>
35
+ <Animated.View
36
+ style={{
37
+ height: scaleSize(12),
38
+ width: 1,
39
+ backgroundColor: theme.colors.primary,
40
+ opacity,
41
+ }}
42
+ />
43
+ <Text color={theme.colors.text.hint} typography={'paragraph_default'}>
44
+ -
45
+ </Text>
46
+ </View>
47
+ );
48
+ };
49
+
50
+ export default OtpCaret;
package/Input/common.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import {View} from 'react-native';
1
+ import {View, ViewStyle} from 'react-native';
2
2
  import styles from './styles';
3
3
  import {Text} from '../Text';
4
4
  import React, {FC, useContext} from 'react';
@@ -13,6 +13,7 @@ type FloatingViewProps = {
13
13
  disabled?: boolean;
14
14
  floatingIcon?: string;
15
15
  required?: boolean;
16
+ style?: ViewStyle;
16
17
  };
17
18
 
18
19
  export const DEFAULT_HEIGHT = 112;
@@ -81,6 +82,7 @@ export const FloatingView: FC<FloatingViewProps> = ({
81
82
  disabled,
82
83
  floatingIcon,
83
84
  required,
85
+ style,
84
86
  }) => {
85
87
  const {theme} = useContext(ApplicationContext);
86
88
 
@@ -100,6 +102,7 @@ export const FloatingView: FC<FloatingViewProps> = ({
100
102
  backgroundColor: theme.colors.background.surface,
101
103
  zIndex: 10,
102
104
  },
105
+ style,
103
106
  ]}>
104
107
  <Text color={floatingTextColor} typography={'label_s'}>
105
108
  {floatingValue}
package/Input/index.tsx CHANGED
@@ -2,6 +2,7 @@ import Input from './Input';
2
2
  import InputTextArea from './InputTextArea';
3
3
  import InputSearch from './InputSearch';
4
4
  import InputMoney from './InputMoney';
5
+ import InputOTP from './InputOTP';
5
6
  import {TextInputProps} from 'react-native';
6
7
 
7
8
  export interface InputProps extends TextInputProps {
@@ -109,4 +110,15 @@ export interface InputSearchProps extends InputPropsOmitForSearch {
109
110
 
110
111
  export interface InputMoneyProps extends InputPropsWithoutPlaceholder {}
111
112
 
112
- export {Input, InputTextArea, InputSearch, InputMoney};
113
+ export type OTPInputLength = 2 | 4 | 6 | 8 | 10;
114
+
115
+ export interface InputOTPProps extends InputPropsWithoutSizeAndIcon {
116
+ length?: OTPInputLength;
117
+ dataType?: 'string' | 'number';
118
+ }
119
+
120
+ export type CaretProps = {
121
+ index?: number;
122
+ length?: number;
123
+ };
124
+ export {Input, InputTextArea, InputSearch, InputMoney, InputOTP};
package/Input/styles.ts CHANGED
@@ -142,4 +142,28 @@ export default StyleSheet.create({
142
142
  paddingVertical: Spacing.S,
143
143
  fontWeight: 'bold',
144
144
  },
145
+
146
+ //OTP
147
+ otpWrapper: {
148
+ width: '100%',
149
+ marginTop: Spacing.M,
150
+ },
151
+ otpInput: {
152
+ height: scaleSize(56),
153
+ borderRadius: Radius.S,
154
+ borderWidth: 1,
155
+ },
156
+ otpFloatingView: {
157
+ position: 'absolute',
158
+ top: -Spacing.S,
159
+ alignSelf: 'center',
160
+ paddingHorizontal: Spacing.S,
161
+ },
162
+ otpInputsView: {
163
+ width: '100%',
164
+ height: '100%',
165
+ flexDirection: 'row',
166
+ alignItems: 'center',
167
+ justifyContent: 'center',
168
+ },
145
169
  });
package/Switch/index.tsx CHANGED
@@ -1,19 +1,17 @@
1
- import React, {FC, useContext} from 'react';
1
+ import React, {FC} from 'react';
2
2
  import {TouchableOpacity, View} from 'react-native';
3
3
  import {SwitchProps} from './types';
4
4
  import styles from './styles';
5
- import {ApplicationContext} from '../Application';
6
5
  import {Colors} from '../Consts';
7
6
 
8
7
  const Switch: FC<SwitchProps> = props => {
9
- const {theme} = useContext(ApplicationContext);
10
8
  const {value, onChange, disabled, style} = props;
11
9
  const circleBackgroundColor = value ? Colors.black_01 : Colors.black_03;
12
10
  const circleAlign = value ? 'flex-end' : 'flex-start';
13
11
 
14
- let backgroundColor = value ? theme.colors.primary : Colors.black_07;
12
+ let backgroundColor = value ? Colors.green_03 : Colors.black_07;
15
13
  if (disabled) {
16
- backgroundColor = value ? theme.colors.background.tonal : Colors.black_05;
14
+ backgroundColor = value ? Colors.green_09 : Colors.black_05;
17
15
  }
18
16
 
19
17
  return (
@@ -0,0 +1,89 @@
1
+ import React, {FC, useContext} from 'react';
2
+ import {Text as RNText, TouchableOpacity, View} from 'react-native';
3
+ import {TitleProps} from './types';
4
+ import {Icon} from '../Icon';
5
+ import styles from './styles';
6
+ import {ApplicationContext} from '../Application';
7
+ import {Colors, Spacing} from '../Consts';
8
+ import {Button} from '../Button';
9
+ import {scaleSize, Text} from '../Text';
10
+
11
+ const Title: FC<TitleProps> = ({
12
+ size = 'large',
13
+ type = 'section',
14
+ onPressAction,
15
+ actionTitle,
16
+ title = 'Title',
17
+ titleFlex = true,
18
+ showAction = true,
19
+ icon,
20
+ description,
21
+ }) => {
22
+ const {theme} = useContext(ApplicationContext);
23
+ const flexStyle = titleFlex ? {flex: 1} : {};
24
+ const typeStyle =
25
+ type === 'screen' ? styles.screen : styles[`${type}_${size}`];
26
+ const actionColor = titleFlex
27
+ ? theme.colors.primary
28
+ : theme.colors.text.default;
29
+ const actionBackground = titleFlex ? Colors.pink_08 + '4D' : Colors.black_06;
30
+ const actionSize = titleFlex ? scaleSize(22) : scaleSize(18);
31
+ const titleWeight = type === 'screen' ? 'Semibold' : 'Bold';
32
+ const marginStyle = type === 'section' ? {marginTop: Spacing.M} : {};
33
+
34
+ const renderAction = () => {
35
+ return !!actionTitle && titleFlex ? (
36
+ <Button
37
+ onPress={() => onPressAction?.()}
38
+ type={'text'}
39
+ full={false}
40
+ size={'small'}
41
+ title={actionTitle}
42
+ />
43
+ ) : (
44
+ <TouchableOpacity
45
+ style={[
46
+ {backgroundColor: actionBackground},
47
+ styles.actionIcon,
48
+ {width: actionSize, height: actionSize},
49
+ ]}
50
+ onPress={onPressAction}>
51
+ <Icon
52
+ size={actionSize}
53
+ color={actionColor}
54
+ source={'arrow_chevron_right_small'}
55
+ />
56
+ </TouchableOpacity>
57
+ );
58
+ };
59
+
60
+ return (
61
+ <View style={styles.wrapper}>
62
+ <View style={[styles.container, marginStyle]}>
63
+ {!!icon && type !== 'screen' && (
64
+ <Icon style={styles.icon} source={icon} />
65
+ )}
66
+ <RNText
67
+ style={[
68
+ typeStyle,
69
+ flexStyle,
70
+ styles.title,
71
+ {
72
+ fontFamily: `${theme.font}-${titleWeight}`,
73
+ },
74
+ ]}>
75
+ {title}
76
+ </RNText>
77
+ {showAction && type !== 'screen' && renderAction()}
78
+ </View>
79
+ {!!description && !!icon && type !== 'screen' && (
80
+ <Text typography={'description_s'} color={theme.colors.text.secondary}>
81
+ {description}
82
+ </Text>
83
+ )}
84
+ </View>
85
+ );
86
+ };
87
+
88
+ export {Title};
89
+ export type {TitleProps};
@@ -0,0 +1,46 @@
1
+ import {StyleSheet} from 'react-native';
2
+ import {scaleSize} from '../Text';
3
+ import {Radius, Spacing} from '../Consts';
4
+
5
+ export default StyleSheet.create({
6
+ card_small: {
7
+ fontSize: scaleSize(16),
8
+ lineHeight: scaleSize(22),
9
+ },
10
+ card_large: {
11
+ fontSize: scaleSize(18),
12
+ lineHeight: scaleSize(26),
13
+ },
14
+ section_small: {
15
+ fontSize: scaleSize(20),
16
+ lineHeight: scaleSize(28),
17
+ },
18
+ section_large: {
19
+ fontSize: scaleSize(24),
20
+ lineHeight: scaleSize(34),
21
+ },
22
+ screen: {
23
+ fontSize: scaleSize(36),
24
+ lineHeight: scaleSize(44),
25
+ },
26
+ title: {
27
+ marginRight: Spacing.XS,
28
+ },
29
+ container: {
30
+ flexDirection: 'row',
31
+ alignItems: 'center',
32
+ width: '100%',
33
+ },
34
+ actionIcon: {
35
+ borderRadius: Radius.M,
36
+ alignItems: 'center',
37
+ justifyContent: 'center',
38
+ },
39
+ icon: {
40
+ marginRight: Spacing.XS,
41
+ borderRadius: Radius.XS,
42
+ },
43
+ wrapper: {
44
+ width: '100%',
45
+ },
46
+ });
package/Title/types.ts ADDED
@@ -0,0 +1,11 @@
1
+ export type TitleProps = {
2
+ type?: 'screen' | 'section' | 'card';
3
+ title: string;
4
+ description?: string;
5
+ size?: 'large' | 'small';
6
+ icon?: string;
7
+ titleFlex?: boolean;
8
+ actionTitle?: string;
9
+ onPressAction?: () => void;
10
+ showAction?: boolean;
11
+ };
package/index.ts CHANGED
@@ -45,3 +45,5 @@ export * from './Pagination';
45
45
  export * from './Pagination/types';
46
46
  export * from './Loader';
47
47
  export * from './Loader/types';
48
+ export * from './Title';
49
+ export * from './Title/types';
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.79.6-beta.1",
3
+ "version": "0.79.6-beta.12",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
7
+ "postinstall": "node verify.js"
8
8
  },
9
9
  "keywords": [
10
10
  "@momo-kits/foundation"
package/verify.js ADDED
@@ -0,0 +1,22 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ try {
5
+ const package = path.join(`${__dirname}`, 'package.json');
6
+ const packageInfo = JSON.parse(fs.readFileSync(package, 'utf8'));
7
+ const packageVersion = parseInt(packageInfo?.version.split('.')?.[1]);
8
+
9
+ const app = path.join(`${__dirname}/../../../`, 'app.json');
10
+ const appInfo = JSON.parse(fs.readFileSync(app, 'utf8'));
11
+ const iOSAppTarget = appInfo?.client?.ios.deploymentTarget;
12
+ const androidAppTarget = appInfo?.client?.android.deploymentTarget;
13
+
14
+ if (packageVersion > iOSAppTarget || packageVersion > androidAppTarget) {
15
+ throw new Error(
16
+ `Package ${packageInfo.name} version: ${packageInfo.version} require deploymentTarget ${packageVersion}`,
17
+ );
18
+ }
19
+ } catch (error) {
20
+ console.error(`Installation failed: ${error.message}`);
21
+ process.exit(1);
22
+ }