@momo-kits/foundation 0.77.8 → 0.78.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.
Files changed (52) hide show
  1. package/Application/BottomTab.tsx +13 -3
  2. package/Application/Components.tsx +51 -4
  3. package/Application/ModalScreen.tsx +17 -16
  4. package/Application/Navigation.ts +4 -2
  5. package/Application/NavigationContainer.tsx +22 -1
  6. package/Application/index.ts +8 -2
  7. package/Application/types.ts +19 -15
  8. package/Application/utils.tsx +13 -0
  9. package/Assets/DotAnimation.json +256 -0
  10. package/Assets/SpinnerAnimation.json +1027 -0
  11. package/Button/index.tsx +25 -14
  12. package/CheckBox/index.tsx +29 -24
  13. package/CheckBox/styles.ts +1 -1
  14. package/CheckBox/types.ts +1 -1
  15. package/Consts/styles.ts +0 -26
  16. package/Divider/index.tsx +2 -0
  17. package/Input/Input.tsx +126 -106
  18. package/Input/InputMoney.tsx +118 -110
  19. package/Input/InputSearch.tsx +129 -134
  20. package/Input/InputTextArea.tsx +126 -118
  21. package/Input/common.tsx +11 -5
  22. package/Input/index.tsx +12 -0
  23. package/Layout/Card.tsx +9 -2
  24. package/Layout/GridSystem.tsx +1 -1
  25. package/Layout/Item.tsx +15 -2
  26. package/Layout/Screen.tsx +76 -8
  27. package/Layout/Section.tsx +36 -3
  28. package/Layout/index.ts +1 -1
  29. package/Layout/types.ts +0 -37
  30. package/Layout/utils.ts +6 -9
  31. package/Loader/DotLoader.tsx +37 -0
  32. package/Loader/Loader.tsx +13 -0
  33. package/Loader/ProgressBar.tsx +44 -0
  34. package/Loader/Spinner.tsx +29 -0
  35. package/Loader/index.tsx +4 -0
  36. package/Loader/styles.ts +10 -0
  37. package/Loader/types.ts +35 -0
  38. package/Loader/utils.ts +25 -0
  39. package/Pagination/PaginationNumber.tsx +1 -2
  40. package/Pagination/PaginationWhiteDot.tsx +1 -3
  41. package/Popup/PopupNotify.tsx +11 -17
  42. package/Popup/PopupPromotion.tsx +19 -13
  43. package/Popup/types.ts +9 -1
  44. package/Radio/index.tsx +1 -1
  45. package/Skeleton/types.ts +3 -0
  46. package/Text/index.tsx +1 -16
  47. package/Text/utils.ts +1 -1
  48. package/code-scanner.js +51 -0
  49. package/index.ts +2 -0
  50. package/package.json +8 -4
  51. package/tsconfig.json +25 -0
  52. package/Application/NavigationButton.tsx +0 -54
@@ -8,17 +8,27 @@ import {ApplicationContext} from './index';
8
8
 
9
9
  const Tab = createBottomTabNavigator();
10
10
 
11
- const BottomTab: React.FC<BottomTabProps> = ({tabs, listeners}) => {
11
+ const BottomTab: React.FC<BottomTabProps> = ({tabs, listeners, navigation}) => {
12
12
  const {theme} = useContext(ApplicationContext);
13
+
14
+ const defaultListener = {
15
+ focus: (item: any) => {
16
+ const focusItem = tabs.find(i => item.target.includes(i.name));
17
+ if (focusItem?.options) {
18
+ navigation?.setOptions?.(focusItem.options);
19
+ }
20
+ },
21
+ };
22
+
13
23
  return (
14
- <Tab.Navigator>
24
+ <Tab.Navigator backBehavior={'firstRoute'}>
15
25
  {tabs.map(item => {
16
26
  return (
17
27
  <Tab.Screen
18
28
  key={item.name}
19
29
  name={item.name}
20
30
  component={item.screen}
21
- listeners={listeners}
31
+ listeners={listeners ?? defaultListener}
22
32
  options={{
23
33
  tabBarLabel: ({color, focused}) => {
24
34
  return (
@@ -1,5 +1,6 @@
1
1
  import React, {useContext, useEffect, useState} from 'react';
2
2
  import {
3
+ Alert,
3
4
  Animated,
4
5
  DeviceEventEmitter,
5
6
  StatusBar,
@@ -7,13 +8,14 @@ import {
7
8
  TouchableOpacity,
8
9
  View,
9
10
  } from 'react-native';
10
- import {ApplicationContext, NavigationButton} from './index';
11
+ import {ApplicationContext} from './index';
11
12
  import {Colors, Radius, Spacing, Styles} from '../Consts';
12
13
  import {Image} from '../Image';
13
14
  import {
14
15
  HeaderBackgroundProps,
15
16
  HeaderBackProps,
16
17
  HeaderToolkitProps,
18
+ NavigationButtonProps,
17
19
  TitleCustomProps,
18
20
  } from './types';
19
21
  import {scaleSize, Text} from '../Text';
@@ -21,6 +23,14 @@ import {Icon} from '../Icon';
21
23
  import {PopupNotify} from '../Popup';
22
24
 
23
25
  const styles = StyleSheet.create({
26
+ navigationButton: {
27
+ height: 28,
28
+ width: 28,
29
+ borderRadius: 14,
30
+ borderColor: '#00000066',
31
+ justifyContent: 'center',
32
+ alignItems: 'center',
33
+ },
24
34
  headerBackground: {
25
35
  width: '100%',
26
36
  height: undefined,
@@ -77,6 +87,39 @@ const styles = StyleSheet.create({
77
87
  },
78
88
  });
79
89
 
90
+ const NavigationButton: React.FC<NavigationButtonProps> = ({
91
+ icon,
92
+ tintColor,
93
+ onPress,
94
+ backgroundColor,
95
+ useBorder = true,
96
+ accessibilityLabel,
97
+ }) => {
98
+ const {theme} = useContext(ApplicationContext);
99
+ if (!backgroundColor && tintColor != Colors.black_01) {
100
+ backgroundColor = theme.colors.background.surface;
101
+ }
102
+
103
+ return (
104
+ <TouchableOpacity
105
+ accessibilityLabel={`NavigationButton/${accessibilityLabel}`}
106
+ style={[
107
+ styles.navigationButton,
108
+ {
109
+ backgroundColor: backgroundColor ?? '#00000066',
110
+ borderWidth: useBorder && backgroundColor ? 0.5 : 0,
111
+ },
112
+ ]}
113
+ onPress={onPress}>
114
+ <Icon
115
+ source={icon}
116
+ color={tintColor ?? theme.colors.text.default}
117
+ size={20}
118
+ />
119
+ </TouchableOpacity>
120
+ );
121
+ };
122
+
80
123
  const HeaderTitle: React.FC<any> = ({accessibilityLabel = '', ...props}) => {
81
124
  const {theme} = useContext(ApplicationContext);
82
125
  const opacity = props.animatedValue?.interpolate({
@@ -100,6 +143,7 @@ const HeaderTitle: React.FC<any> = ({accessibilityLabel = '', ...props}) => {
100
143
  const HeaderLeft: React.FC<HeaderBackProps> = ({
101
144
  tintColor,
102
145
  preventBack,
146
+ onPressLeftHeader,
103
147
  useBorder,
104
148
  backgroundColor,
105
149
  accessibilityLabel = '',
@@ -131,6 +175,7 @@ const HeaderLeft: React.FC<HeaderBackProps> = ({
131
175
  const requestId = `navigationBackPress#${currentTime}`;
132
176
  DeviceEventEmitter.emit('dismiss', {requestId});
133
177
  }
178
+ onPressLeftHeader?.();
134
179
  };
135
180
 
136
181
  return (
@@ -204,7 +249,7 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
204
249
  <View style={[styles.dotAvatar, {backgroundColor: dotColor}]} />
205
250
  )}
206
251
  </View>
207
- <View style={[Styles.flex, Styles.paddingHorizontal8]}>
252
+ <View style={[Styles.flex, {paddingHorizontal: 8}]}>
208
253
  <Text typography="title_xs" color={tintColor}>
209
254
  {title}
210
255
  </Text>
@@ -220,8 +265,9 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
220
265
  const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
221
266
  const validType = (item: any) => {
222
267
  if (__DEV__ && item.type !== NavigationButton) {
223
- console.warn(
224
- 'element type of NavigationButton, Please migrate to use NavigationButton of kits.',
268
+ Alert.alert(
269
+ 'Rule',
270
+ 'HeaderRightAction contains element type of NavigationButton, Please check again.',
225
271
  );
226
272
  return <View />;
227
273
  }
@@ -366,6 +412,7 @@ const HeaderToolkitAction: React.FC<any> = ({tintColor}) => {
366
412
  };
367
413
 
368
414
  export {
415
+ NavigationButton,
369
416
  HeaderTitle,
370
417
  HeaderLeft,
371
418
  HeaderBackground,
@@ -1,14 +1,14 @@
1
- import React, {useContext, useEffect, useMemo, useRef} from 'react';
1
+ import React, {useContext, useEffect, useRef} from 'react';
2
2
  import {
3
+ Dimensions,
3
4
  KeyboardAvoidingView,
4
5
  Platform,
5
6
  Pressable,
6
7
  StyleSheet,
7
8
  View,
8
9
  } from 'react-native';
9
- import {SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
10
+ import {SafeAreaView} from 'react-native-safe-area-context';
10
11
  import {BottomSheetBackdrop, BottomSheetModal} from '@gorhom/bottom-sheet';
11
- import {BottomSheetModalMethods} from '@gorhom/bottom-sheet/lib/typescript/types';
12
12
  import Navigation from './Navigation';
13
13
  import {BottomSheetParams, ModalParams} from './types';
14
14
  import {Radius, Spacing, Styles} from '../Consts';
@@ -85,7 +85,12 @@ const Modal: React.FC<ModalParams> = props => {
85
85
 
86
86
  const BottomSheet: React.FC<BottomSheetParams> = props => {
87
87
  const {theme, navigator} = useContext(ApplicationContext);
88
- const {screen, options}: BottomSheetParams = props.route.params;
88
+ const {height} = Dimensions.get('window');
89
+ const {
90
+ screen,
91
+ options,
92
+ snapPoints = [height * 0.5, height * 0.9],
93
+ }: BottomSheetParams = props.route.params;
89
94
  const Component = useRef(screen).current;
90
95
  const navigation = new Navigation(props.navigation, theme);
91
96
  const params = {
@@ -95,11 +100,14 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
95
100
 
96
101
  delete params.screen;
97
102
 
98
- const snapPoints = useMemo(() => ['50%', '90%'], []);
99
- const {bottom} = useSafeAreaInsets();
100
- const bottomSheetRef = useRef<BottomSheetModalMethods>(null);
103
+ const bottomSheetRef = useRef<any>(null);
101
104
  const mountedRef = useRef(true);
102
105
 
106
+ let backgroundColor = theme.colors.background.default;
107
+ if (options?.surface) {
108
+ backgroundColor = theme.colors.background.surface;
109
+ }
110
+
103
111
  useEffect(() => {
104
112
  bottomSheetRef.current?.present();
105
113
  return () => {
@@ -115,16 +123,11 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
115
123
  />
116
124
  );
117
125
 
118
- let backgroundColor = theme.colors.background.default;
119
- if (options?.surface) {
120
- backgroundColor = theme.colors.background.surface;
121
- }
122
-
123
126
  return (
124
127
  <SafeAreaView style={Styles.flex}>
125
128
  <BottomSheetModal
126
129
  ref={bottomSheetRef}
127
- snapPoints={snapPoints}
130
+ snapPoints={snapPoints?.map(item => item + 68)}
128
131
  onDismiss={() => {
129
132
  if (mountedRef.current) {
130
133
  navigator?.pop();
@@ -132,9 +135,7 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
132
135
  }}
133
136
  handleComponent={null}
134
137
  backdropComponent={backdropComponent}>
135
- <View
136
- style={{paddingBottom: bottom}}
137
- accessibilityLabel={'BottomSheet'}>
138
+ <View accessibilityLabel={'BottomSheet'}>
138
139
  <View style={[styles.sheetContainer, {backgroundColor}]}>
139
140
  <View style={styles.indicatorContainer}>
140
141
  <View
@@ -1,4 +1,5 @@
1
1
  import {NavigationProp} from '@react-navigation/native';
2
+ import {Alert} from 'react-native';
2
3
  import {NavigationOptions, Theme} from './types';
3
4
  import {HeaderRightAction} from './index';
4
5
  import {getOptions} from './utils';
@@ -18,8 +19,9 @@ class Navigation {
18
19
  const headerRight = params.headerRight?.();
19
20
  const type = headerRight?.type;
20
21
  if (type !== HeaderRightAction && type !== HeaderToolkitAction) {
21
- console.warn(
22
- 'headerRight not return element type of HeaderRightAction | HeaderToolkitAction, Please migrate to use of kits.',
22
+ Alert.alert(
23
+ 'Rule',
24
+ 'headerRight contains element type of HeaderRightAction | HeaderToolkitAction, Please check again.',
23
25
  );
24
26
  delete params.headerRight;
25
27
  }
@@ -21,10 +21,12 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
21
21
  theme,
22
22
  options,
23
23
  maxApi,
24
+ localization,
24
25
  }) => {
25
26
  const navigationRef = React.useRef<NavigationContainerRef>(null);
26
27
  const navigator = useRef(new Navigator(navigationRef));
27
28
  const [showGrid, setShowGrid] = useState(false);
29
+ const [language, setLanguage] = useState<'vi' | 'en'>('vi');
28
30
 
29
31
  useEffect(() => {
30
32
  const subscription = DeviceEventEmitter.addListener(
@@ -38,13 +40,32 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
38
40
  };
39
41
  }, []);
40
42
 
43
+ useEffect(() => {
44
+ const listener = maxApi?.observer?.('language', (lang: 'vi' | 'en') => {
45
+ setLanguage(lang);
46
+ });
47
+ return () => {
48
+ listener?.();
49
+ };
50
+ }, []);
51
+
41
52
  navigator.current.maxApi = maxApi;
42
53
 
54
+ const translate = (key: string) => {
55
+ return localization?.[language]?.[key] || key;
56
+ };
57
+
43
58
  return (
44
59
  <SafeAreaProvider>
45
60
  <BottomSheetModalProvider>
46
61
  <ApplicationContext.Provider
47
- value={{theme, navigator: navigator.current, showGrid}}>
62
+ value={{
63
+ theme,
64
+ navigator: navigator.current,
65
+ showGrid,
66
+ language,
67
+ translate,
68
+ }}>
48
69
  <ReactNavigationContainer
49
70
  theme={{
50
71
  ...theme,
@@ -1,7 +1,11 @@
1
1
  import {NavigationContainer} from './NavigationContainer';
2
2
  import Screen from '../Layout/Screen';
3
- import NavigationButton from './NavigationButton';
4
- import {HeaderRightAction} from './Components';
3
+ import {
4
+ HeaderRightAction,
5
+ NavigationButton,
6
+ HeaderToolkitAction,
7
+ HeaderTitle,
8
+ } from './Components';
5
9
  import BottomTab from './BottomTab';
6
10
  import {createContext} from 'react';
7
11
  import {defaultContext} from '../Consts';
@@ -14,5 +18,7 @@ export {
14
18
  Screen,
15
19
  NavigationButton,
16
20
  HeaderRightAction,
21
+ HeaderToolkitAction,
22
+ HeaderTitle,
17
23
  BottomTab,
18
24
  };
@@ -1,5 +1,5 @@
1
- import {Animated, ScrollViewProps, ViewProps} from 'react-native';
2
- import React, {ReactNode} from 'react';
1
+ import {Animated} from 'react-native';
2
+ import React from 'react';
3
3
  import Navigator from './Navigator';
4
4
  import {PopupNotifyProps} from '../Popup/types';
5
5
  import Navigation from './Navigation';
@@ -65,6 +65,17 @@ export type Context = {
65
65
  theme: Theme;
66
66
  navigator?: Navigator;
67
67
  showGrid?: boolean;
68
+ language: 'vi' | 'en';
69
+ translate: (key: string) => string;
70
+ };
71
+
72
+ export type LocalizationObject = {
73
+ vi: {
74
+ [key: string]: string;
75
+ };
76
+ en: {
77
+ [key: string]: string;
78
+ };
68
79
  };
69
80
 
70
81
  export type NavigationContainerProps = {
@@ -72,6 +83,7 @@ export type NavigationContainerProps = {
72
83
  options?: NavigationOptions;
73
84
  theme: Theme;
74
85
  maxApi?: any;
86
+ localization: LocalizationObject;
75
87
  };
76
88
 
77
89
  export type NavigationScreenProps = {
@@ -80,19 +92,6 @@ export type NavigationScreenProps = {
80
92
  navigation: Navigation;
81
93
  };
82
94
 
83
- export interface ScreenProps extends ViewProps {
84
- navigation?: Navigation;
85
- enableKeyboardAvoidingView?: boolean;
86
- headerBackground?: string;
87
- scrollable?: boolean;
88
- useAnimatedHeader?: boolean;
89
- useExtendedHeader?: boolean;
90
- scrollViewProps?: ScrollViewProps;
91
- footerComponent?: ReactNode;
92
- marginHeader?: number;
93
- backgroundColor?: string;
94
- }
95
-
96
95
  export type ScreenParams = {
97
96
  [key: string]: any;
98
97
  screen: Screen;
@@ -108,6 +107,7 @@ export interface ModalParams extends ScreenParams {
108
107
  export interface BottomSheetParams extends ScreenParams {
109
108
  [key: string]: any;
110
109
  onDismiss?: () => void;
110
+ snapPoints?: ReadonlyArray<number>;
111
111
  }
112
112
 
113
113
  export type NavigationButtonProps = {
@@ -121,6 +121,7 @@ export type NavigationButtonProps = {
121
121
 
122
122
  export type NavigationOptions = {
123
123
  preventBack?: PopupNotifyProps;
124
+ onPressLeftHeader?: () => void;
124
125
  surface?: boolean;
125
126
  headerTransparent?: boolean;
126
127
  hiddenBack?: boolean;
@@ -134,6 +135,7 @@ export type NavigationOptions = {
134
135
 
135
136
  export interface HeaderBackProps extends NavigationButtonProps {
136
137
  preventBack?: PopupNotifyProps;
138
+ onPressLeftHeader?: () => void;
137
139
  accessibilityLabel?: string;
138
140
  }
139
141
 
@@ -169,10 +171,12 @@ export type BottomTabItemProps = {
169
171
  showDot?: boolean;
170
172
  badgeLabel?: string;
171
173
  screen: Screen;
174
+ options: NavigationOptions;
172
175
  };
173
176
 
174
177
  export type BottomTabProps = {
175
178
  tabs: BottomTabItemProps[];
179
+ navigation: Navigation;
176
180
  listeners?: {
177
181
  tabPress?: any;
178
182
  focus?: any;
@@ -76,6 +76,19 @@ const getOptions = (params: NavigationOptions, theme: Theme) => {
76
76
  let titleProps = {};
77
77
  let options = {};
78
78
 
79
+ if (typeof params.onPressLeftHeader === 'function') {
80
+ options = {
81
+ ...options,
82
+ headerLeft: (props: any) => (
83
+ <HeaderLeft
84
+ {...props}
85
+ preventBack={params.preventBack}
86
+ onPressLeftHeader={params.onPressLeftHeader}
87
+ />
88
+ ),
89
+ };
90
+ }
91
+
79
92
  if (params.preventBack) {
80
93
  options = {
81
94
  ...options,
@@ -0,0 +1,256 @@
1
+ {
2
+ "v": "4.8.0",
3
+ "meta": {"g": "LottieFiles AE 3.2.2", "a": "", "k": "", "d": "", "tc": ""},
4
+ "fr": 60,
5
+ "ip": 10,
6
+ "op": 54,
7
+ "w": 52,
8
+ "h": 20,
9
+ "nm": "Dot 10",
10
+ "ddd": 0,
11
+ "assets": [
12
+ {
13
+ "id": "comp_0",
14
+ "layers": [
15
+ {
16
+ "ddd": 0,
17
+ "ind": 1,
18
+ "ty": 4,
19
+ "nm": "1",
20
+ "sr": 1,
21
+ "ks": {
22
+ "o": {"a": 0, "k": 100, "ix": 11},
23
+ "r": {"a": 0, "k": 0, "ix": 10},
24
+ "p": {
25
+ "a": 1,
26
+ "k": [
27
+ {
28
+ "i": {"x": 0.711, "y": 1},
29
+ "o": {"x": 0.26, "y": 0.24},
30
+ "t": 0,
31
+ "s": [-14, 11, 0],
32
+ "to": [0, -1.172, 0],
33
+ "ti": [0, -0.21, 0]
34
+ },
35
+ {
36
+ "i": {"x": 0.667, "y": 1},
37
+ "o": {"x": 0.333, "y": 0},
38
+ "t": 17,
39
+ "s": [-14, 5, 0],
40
+ "to": [0, 0.333, 0],
41
+ "ti": [0, -1, 0]
42
+ },
43
+ {
44
+ "i": {"x": 0.833, "y": 0.542},
45
+ "o": {"x": 0.333, "y": 0},
46
+ "t": 30,
47
+ "s": [-14, 13, 0],
48
+ "to": [0, 1, 0],
49
+ "ti": [0, 0.333, 0]
50
+ },
51
+ {"t": 45, "s": [-14, 11, 0]}
52
+ ],
53
+ "ix": 2
54
+ },
55
+ "a": {"a": 0, "k": [-40, 0, 0], "ix": 1},
56
+ "s": {"a": 0, "k": [100, 100, 100], "ix": 6}
57
+ },
58
+ "ao": 0,
59
+ "shapes": [
60
+ {
61
+ "ty": "gr",
62
+ "it": [
63
+ {
64
+ "d": 1,
65
+ "ty": "el",
66
+ "s": {"a": 0, "k": [12, 12], "ix": 2},
67
+ "p": {"a": 0, "k": [0, 0], "ix": 3},
68
+ "nm": "Ellipse Path 1",
69
+ "mn": "ADBE Vector Shape - Ellipse",
70
+ "hd": false
71
+ },
72
+ {
73
+ "ty": "st",
74
+ "c": {"a": 0, "k": [1, 1, 1, 1], "ix": 3},
75
+ "o": {"a": 0, "k": 100, "ix": 4},
76
+ "w": {"a": 0, "k": 0, "ix": 5},
77
+ "lc": 1,
78
+ "lj": 1,
79
+ "ml": 4,
80
+ "bm": 0,
81
+ "nm": "Stroke 1",
82
+ "mn": "ADBE Vector Graphic - Stroke",
83
+ "hd": false
84
+ },
85
+ {
86
+ "ty": "fl",
87
+ "c": {
88
+ "a": 1,
89
+ "k": [
90
+ {
91
+ "i": {"x": [0.833], "y": [0.833]},
92
+ "o": {"x": [0.167], "y": [0.167]},
93
+ "t": 0,
94
+ "s": [0.968627510819, 0.674509803922, 0.835294177485, 1]
95
+ },
96
+ {
97
+ "i": {"x": [0.833], "y": [0.833]},
98
+ "o": {"x": [0.167], "y": [0.167]},
99
+ "t": 17,
100
+ "s": [0.921568632126, 0.184313729405, 0.588235318661, 1]
101
+ },
102
+ {
103
+ "t": 35,
104
+ "s": [0.968627510819, 0.674509803922, 0.835294177485, 1]
105
+ }
106
+ ],
107
+ "ix": 4
108
+ },
109
+ "o": {"a": 0, "k": 100, "ix": 5},
110
+ "r": 1,
111
+ "bm": 0,
112
+ "nm": "Fill 1",
113
+ "mn": "ADBE Vector Graphic - Fill",
114
+ "hd": false
115
+ },
116
+ {
117
+ "ty": "tr",
118
+ "p": {"a": 0, "k": [-20, 1], "ix": 2},
119
+ "a": {"a": 0, "k": [0, 0], "ix": 1},
120
+ "s": {"a": 0, "k": [100, 100], "ix": 3},
121
+ "r": {"a": 0, "k": 0, "ix": 6},
122
+ "o": {"a": 0, "k": 100, "ix": 7},
123
+ "sk": {"a": 0, "k": 0, "ix": 4},
124
+ "sa": {"a": 0, "k": 0, "ix": 5},
125
+ "nm": "Transform"
126
+ }
127
+ ],
128
+ "nm": "Ellipse 1",
129
+ "np": 3,
130
+ "cix": 2,
131
+ "bm": 0,
132
+ "ix": 1,
133
+ "mn": "ADBE Vector Group",
134
+ "hd": false
135
+ }
136
+ ],
137
+ "ip": 0,
138
+ "op": 45,
139
+ "st": 0,
140
+ "bm": 0
141
+ }
142
+ ]
143
+ }
144
+ ],
145
+ "layers": [
146
+ {
147
+ "ddd": 0,
148
+ "ind": 1,
149
+ "ty": 0,
150
+ "nm": "Dot 0",
151
+ "refId": "comp_0",
152
+ "sr": 1,
153
+ "ks": {
154
+ "o": {"a": 0, "k": 100, "ix": 11},
155
+ "r": {"a": 0, "k": 0, "ix": 10},
156
+ "p": {"a": 0, "k": [6, 10, 0], "ix": 2},
157
+ "a": {"a": 0, "k": [-34, 10, 0], "ix": 1},
158
+ "s": {"a": 0, "k": [100, 100, 100], "ix": 6}
159
+ },
160
+ "ao": 0,
161
+ "tm": {
162
+ "a": 1,
163
+ "k": [
164
+ {
165
+ "i": {"x": [0.833], "y": [0.833]},
166
+ "o": {"x": [0.167], "y": [0.167]},
167
+ "t": 10,
168
+ "s": [0]
169
+ },
170
+ {"t": 54, "s": [0.733]}
171
+ ],
172
+ "ix": 2,
173
+ "x": "var $bm_rt;\n$bm_rt = loopOut('cycle', 0);"
174
+ },
175
+ "w": 12,
176
+ "h": 20,
177
+ "ip": 10,
178
+ "op": 90,
179
+ "st": 10,
180
+ "bm": 0
181
+ },
182
+ {
183
+ "ddd": 0,
184
+ "ind": 2,
185
+ "ty": 0,
186
+ "nm": "Dot 0",
187
+ "refId": "comp_0",
188
+ "sr": 1,
189
+ "ks": {
190
+ "o": {"a": 0, "k": 100, "ix": 11},
191
+ "r": {"a": 0, "k": 0, "ix": 10},
192
+ "p": {"a": 0, "k": [6, 10, 0], "ix": 2},
193
+ "a": {"a": 0, "k": [-14, 10, 0], "ix": 1},
194
+ "s": {"a": 0, "k": [100, 100, 100], "ix": 6}
195
+ },
196
+ "ao": 0,
197
+ "tm": {
198
+ "a": 1,
199
+ "k": [
200
+ {
201
+ "i": {"x": [0.833], "y": [0.833]},
202
+ "o": {"x": [0.167], "y": [0.167]},
203
+ "t": 5,
204
+ "s": [0]
205
+ },
206
+ {"t": 49, "s": [0.733]}
207
+ ],
208
+ "ix": 2,
209
+ "x": "var $bm_rt;\n$bm_rt = loopOut('cycle', 0);"
210
+ },
211
+ "w": 12,
212
+ "h": 20,
213
+ "ip": 5,
214
+ "op": 85,
215
+ "st": 5,
216
+ "bm": 0
217
+ },
218
+ {
219
+ "ddd": 0,
220
+ "ind": 3,
221
+ "ty": 0,
222
+ "nm": "Dot 0",
223
+ "refId": "comp_0",
224
+ "sr": 1,
225
+ "ks": {
226
+ "o": {"a": 0, "k": 100, "ix": 11},
227
+ "r": {"a": 0, "k": 0, "ix": 10},
228
+ "p": {"a": 0, "k": [6, 10, 0], "ix": 2},
229
+ "a": {"a": 0, "k": [6, 10, 0], "ix": 1},
230
+ "s": {"a": 0, "k": [100, 100, 100], "ix": 6}
231
+ },
232
+ "ao": 0,
233
+ "tm": {
234
+ "a": 1,
235
+ "k": [
236
+ {
237
+ "i": {"x": [0.833], "y": [0.833]},
238
+ "o": {"x": [0.167], "y": [0.167]},
239
+ "t": 0,
240
+ "s": [0]
241
+ },
242
+ {"t": 44, "s": [0.733]}
243
+ ],
244
+ "ix": 2,
245
+ "x": "var $bm_rt;\n$bm_rt = loopOut('cycle', 0);"
246
+ },
247
+ "w": 12,
248
+ "h": 20,
249
+ "ip": 0,
250
+ "op": 80,
251
+ "st": 0,
252
+ "bm": 0
253
+ }
254
+ ],
255
+ "markers": []
256
+ }