@momo-kits/foundation 0.77.8-beta.3 → 0.77.8-beta.5

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.
@@ -1,4 +1,4 @@
1
- import React, {FC, useContext, useRef, useState} from 'react';
1
+ import React, {FC, forwardRef, useContext, useRef, useState} from 'react';
2
2
  import {
3
3
  NativeSyntheticEvent,
4
4
  TextInput,
@@ -19,134 +19,142 @@ import {InputTextAreaProps} from './index';
19
19
  import {Icon} from '../Icon';
20
20
  import {ApplicationContext} from '../Application';
21
21
 
22
- const InputTextArea: FC<InputTextAreaProps> = ({
23
- errorMessage,
24
- onChangeText,
25
- floatingIconColor,
26
- floatingIcon,
27
- floatingValue,
28
- onFocus,
29
- onBlur,
30
- disabled,
31
- value,
32
- defaultValue,
33
- height,
34
- placeholder,
35
- maxLength,
36
- required,
37
- ...props
38
- }) => {
39
- const {theme} = useContext(ApplicationContext);
40
- const [focused, setFocused] = useState(false);
41
- const [inputValue, setInputValue] = useState(defaultValue ?? '');
42
- const inputRef = useRef<any>(null);
22
+ const InputTextArea: FC<InputTextAreaProps> = forwardRef(
23
+ (
24
+ {
25
+ errorMessage,
26
+ onChangeText,
27
+ floatingIconColor,
28
+ floatingIcon,
29
+ floatingValue,
30
+ onFocus,
31
+ onBlur,
32
+ disabled,
33
+ value,
34
+ defaultValue,
35
+ height,
36
+ placeholder,
37
+ maxLength,
38
+ required,
39
+ errorSpacing,
40
+ ...props
41
+ },
42
+ ref,
43
+ ) => {
44
+ const {theme} = useContext(ApplicationContext);
45
+ const [focused, setFocused] = useState(false);
46
+ const [inputValue, setInputValue] = useState(defaultValue ?? '');
47
+ const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
43
48
 
44
- const onClearText = () => {
45
- inputRef?.current?.clear();
46
- _onChangeText('');
47
- };
49
+ const onClearText = () => {
50
+ inputRef?.current?.clear();
51
+ _onChangeText('');
52
+ };
48
53
 
49
- const _onChangeText = (text: string) => {
50
- onChangeText?.(text);
51
- setInputValue(text);
52
- };
54
+ const _onChangeText = (text: string) => {
55
+ onChangeText?.(text);
56
+ setInputValue(text);
57
+ };
53
58
 
54
- const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
55
- setFocused(true);
56
- onFocus?.(e);
57
- };
59
+ const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
60
+ setFocused(true);
61
+ onFocus?.(e);
62
+ };
58
63
 
59
- const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
60
- setFocused(false);
61
- onBlur?.(e);
62
- };
64
+ const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
65
+ setFocused(false);
66
+ onBlur?.(e);
67
+ };
63
68
 
64
- const renderCountingView = () => {
65
- return (
66
- <View style={styles.countingView}>
67
- <Text color={theme.colors.text.hint} typography={'description_xs'}>
68
- {`${inputValue.length}/${maxLength}`}
69
- </Text>
70
- </View>
71
- );
72
- };
73
- const renderInputView = () => {
74
- const disabledColor = theme.colors.text.disable;
75
- let textColor = theme.colors.text.default;
76
- let placeholderColor = theme.colors.text.hint;
69
+ const renderCountingView = () => {
70
+ return (
71
+ <View style={styles.countingView}>
72
+ <Text color={theme.colors.text.hint} typography={'description_xs'}>
73
+ {`${inputValue.length}/${maxLength}`}
74
+ </Text>
75
+ </View>
76
+ );
77
+ };
78
+ const renderInputView = () => {
79
+ const disabledColor = theme.colors.text.disable;
80
+ let textColor = theme.colors.text.default;
81
+ let placeholderColor = theme.colors.text.hint;
77
82
 
78
- if (disabled) {
79
- textColor = disabledColor;
80
- placeholderColor = disabledColor;
81
- }
83
+ if (disabled) {
84
+ textColor = disabledColor;
85
+ placeholderColor = disabledColor;
86
+ }
82
87
 
83
- return (
84
- <View
85
- style={[
86
- getBorderColor(focused, errorMessage, disabled),
87
- styles.textAreaWrapper,
88
- {
89
- height: height || DEFAULT_HEIGHT,
90
- backgroundColor: theme.colors.background.surface,
91
- },
92
- ]}>
93
- <FloatingView
94
- floatingValue={floatingValue}
95
- floatingIconColor={floatingIconColor}
96
- disabled={disabled}
97
- floatingIcon={floatingIcon}
98
- required={required}
99
- />
100
- <View style={styles.rowArea}>
101
- <View style={styles.textAreaView}>
102
- <TextInput
103
- {...props}
104
- accessibilityLabel={`TextInput`}
105
- ref={inputRef}
106
- editable={!disabled}
107
- textAlignVertical="top"
108
- style={[
109
- styles.textArea,
110
- {
111
- color: textColor,
112
- },
113
- ]}
114
- maxLength={maxLength}
115
- textBreakStrategy="highQuality"
116
- multiline={true}
117
- value={value}
118
- onChangeText={_onChangeText}
119
- onFocus={_onFocus}
120
- onBlur={_onBlur}
121
- placeholder={placeholder}
122
- selectionColor={theme.colors.primary}
123
- placeholderTextColor={placeholderColor}
124
- />
125
- </View>
126
- {focused && inputValue.length > 0 && (
127
- <TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
128
- <Icon
129
- source="24_navigation_close_circle_full"
130
- size={16}
131
- color={theme.colors.text.hint}
88
+ return (
89
+ <View
90
+ style={[
91
+ styles.textAreaWrapper,
92
+ {
93
+ height: height || DEFAULT_HEIGHT,
94
+ backgroundColor: theme.colors.background.surface,
95
+ },
96
+ getBorderColor(theme, focused, errorMessage, disabled),
97
+ ]}>
98
+ <FloatingView
99
+ floatingValue={floatingValue}
100
+ floatingIconColor={floatingIconColor}
101
+ disabled={disabled}
102
+ floatingIcon={floatingIcon}
103
+ required={required}
104
+ />
105
+ <View style={styles.rowArea}>
106
+ <View style={styles.textAreaView}>
107
+ <TextInput
108
+ {...props}
109
+ accessibilityLabel={`TextInput`}
110
+ ref={inputRef}
111
+ editable={!disabled}
112
+ textAlignVertical="top"
113
+ style={[
114
+ styles.textArea,
115
+ {
116
+ color: textColor,
117
+ },
118
+ ]}
119
+ maxLength={maxLength}
120
+ textBreakStrategy="highQuality"
121
+ multiline={true}
122
+ value={value}
123
+ onChangeText={_onChangeText}
124
+ onFocus={_onFocus}
125
+ onBlur={_onBlur}
126
+ placeholder={placeholder}
127
+ selectionColor={theme.colors.primary}
128
+ placeholderTextColor={placeholderColor}
132
129
  />
133
- </TouchableOpacity>
134
- )}
130
+ </View>
131
+ {focused && inputValue.length > 0 && (
132
+ <TouchableOpacity
133
+ style={styles.iconWrapper}
134
+ onPress={onClearText}>
135
+ <Icon
136
+ source="24_navigation_close_circle_full"
137
+ size={16}
138
+ color={theme.colors.text.hint}
139
+ />
140
+ </TouchableOpacity>
141
+ )}
142
+ </View>
143
+ {renderCountingView()}
135
144
  </View>
136
- {renderCountingView()}
145
+ );
146
+ };
147
+
148
+ return (
149
+ <View
150
+ style={styles.wrapper}
151
+ accessibilityLabel={`InputTextArea/${floatingValue}`}>
152
+ {renderInputView()}
153
+ <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
137
154
  </View>
138
155
  );
139
- };
140
-
141
- return (
142
- <View
143
- style={styles.wrapper}
144
- accessibilityLabel={`InputTextArea/${floatingValue}`}>
145
- {renderInputView()}
146
- <ErrorView errorMessage={errorMessage} />
147
- </View>
148
- );
149
- };
156
+ },
157
+ );
150
158
 
151
159
  InputTextArea.defaultProps = {
152
160
  maxLength: MAX_LENGTH,
package/Input/common.tsx CHANGED
@@ -5,6 +5,7 @@ import React, {FC, useContext} from 'react';
5
5
  import {ApplicationContext} from '../Application';
6
6
  import {Icon} from '../Icon';
7
7
  import {Styles} from '../Consts';
8
+ import {Theme} from '../Application/types';
8
9
 
9
10
  type FloatingViewProps = {
10
11
  floatingValue?: string;
@@ -18,12 +19,11 @@ export const DEFAULT_HEIGHT = 112;
18
19
  export const MAX_LENGTH = 300;
19
20
 
20
21
  export const getBorderColor = (
22
+ theme: Theme,
21
23
  focused: boolean,
22
24
  errorMessage?: string,
23
25
  disabled?: boolean,
24
26
  ) => {
25
- const {theme} = useContext(ApplicationContext);
26
-
27
27
  let borderColor = theme.colors.border.default;
28
28
 
29
29
  if (focused) {
@@ -47,7 +47,10 @@ export const getSizeStyle = (size?: 'small' | 'large') => {
47
47
  }
48
48
  return styles.container;
49
49
  };
50
- export const ErrorView: FC<{errorMessage?: string}> = ({errorMessage}) => {
50
+ export const ErrorView: FC<{errorMessage?: string; errorSpacing?: boolean}> = ({
51
+ errorMessage,
52
+ errorSpacing,
53
+ }) => {
51
54
  const {theme} = useContext(ApplicationContext);
52
55
  const errorColor = theme.colors.error.primary;
53
56
  if (errorMessage) {
@@ -66,7 +69,10 @@ export const ErrorView: FC<{errorMessage?: string}> = ({errorMessage}) => {
66
69
  </View>
67
70
  );
68
71
  }
69
- return null;
72
+ if (errorSpacing) {
73
+ return <View style={[styles.errorView, {height: 18}]} />;
74
+ }
75
+ return <View />;
70
76
  };
71
77
 
72
78
  export const FloatingView: FC<FloatingViewProps> = ({
package/Input/index.tsx CHANGED
@@ -52,6 +52,18 @@ export interface InputProps extends TextInputProps {
52
52
  * Defaults to `false` if not provided.
53
53
  */
54
54
  required?: boolean;
55
+
56
+ /**
57
+ * Optional. If `true`,
58
+ * include spacing when Input not have error message.
59
+ * Defaults to `false` if not provided.
60
+ */
61
+ errorSpacing?: boolean;
62
+
63
+ /**
64
+ * If true, the icon of input will use be show indicator loading.
65
+ */
66
+ loading?: boolean;
55
67
  }
56
68
 
57
69
  type InputPropsWithoutSizeAndIcon = Omit<
@@ -51,7 +51,7 @@ const GridSystem: React.FC<any> = ({
51
51
  bottom: Spacing.M,
52
52
  },
53
53
  ]}>
54
- {list.map((i, index) => {
54
+ {list.map((_, index) => {
55
55
  return (
56
56
  <View style={{flexDirection: 'row'}} key={index.toString()}>
57
57
  {index != -0 && <View style={{width: grid.gutterSize}} />}
package/Layout/Screen.tsx CHANGED
@@ -5,9 +5,8 @@ import React, {useContext, useEffect, useRef} from 'react';
5
5
  import {ScreenProps} from '../Application/types';
6
6
  import {Spacing, Styles} from '../Consts';
7
7
  import {Card, Section, validateChildren} from './index';
8
- import {ApplicationContext} from '../Application';
8
+ import {ApplicationContext, HeaderTitle} from '../Application';
9
9
  import Navigation from '../Application/Navigation';
10
- import {HeaderTitle} from '../Application/Components';
11
10
 
12
11
  const Screen: React.FC<ScreenProps> = ({
13
12
  children,
@@ -70,7 +69,6 @@ const Screen: React.FC<ScreenProps> = ({
70
69
  const stackNavigation = new Navigation(current?.getParent(), theme);
71
70
  stackNavigation?.setOptions({
72
71
  animatedValue: animatedValue.current,
73
- headerTransparent: true,
74
72
  });
75
73
  });
76
74
  }
@@ -130,8 +128,20 @@ const Screen: React.FC<ScreenProps> = ({
130
128
  </View>
131
129
  );
132
130
  });
131
+ } else {
132
+ const item: any = children;
133
+ const space = item?.props?.useMargin === false ? 0 : Spacing.M;
134
+ return (
135
+ <View
136
+ key={`ScreenItem`}
137
+ style={{
138
+ marginTop: space,
139
+ flex: item?.props?.expanded ? 1 : undefined,
140
+ }}>
141
+ {children}
142
+ </View>
143
+ );
133
144
  }
134
- return results;
135
145
  };
136
146
 
137
147
  return (
package/Layout/index.ts CHANGED
@@ -11,7 +11,7 @@ const GridContext = createContext<GridContextProps>({
11
11
  gutterSize: 12,
12
12
  margin: 12,
13
13
  sizePerSpan: 0,
14
- getSizeSpan: span => 0,
14
+ getSizeSpan: () => 0,
15
15
  });
16
16
 
17
17
  export {GridContext, Card, Section, GridSystem, validateChildren, Item};
package/Layout/utils.ts CHANGED
@@ -62,15 +62,12 @@ const useGridSystem = () => {
62
62
  );
63
63
 
64
64
  useEffect(() => {
65
- const subscription: any = Dimensions.addEventListener(
66
- 'change',
67
- ({window}: any) => {
68
- const newColumns = Dimensions.get('window').width > 600 ? 24 : 12;
69
- if (newColumns != numberOfColumns) {
70
- setNumberOfColumns(newColumns);
71
- }
72
- },
73
- );
65
+ const subscription: any = Dimensions.addEventListener('change', () => {
66
+ const newColumns = Dimensions.get('window').width > 600 ? 24 : 12;
67
+ if (newColumns != numberOfColumns) {
68
+ setNumberOfColumns(newColumns);
69
+ }
70
+ });
74
71
  return () => subscription?.remove();
75
72
  }, []);
76
73
 
@@ -1,38 +1,36 @@
1
1
  import React, {FC, useContext} from 'react';
2
- import {View, ViewProps} from 'react-native';
3
2
  import AnimatedLottieView from 'lottie-react-native';
4
3
  import animation from '../Assets/DotAnimation.json';
5
4
  import {ApplicationContext} from '../Application';
6
5
  import {hexToRGBA} from './utils';
6
+ import {LoaderProps} from './types';
7
7
 
8
- const DotLoader: FC<ViewProps> = ({style}) => {
8
+ const DotLoader: FC<LoaderProps> = ({color}) => {
9
9
  const {theme} = useContext(ApplicationContext);
10
10
 
11
11
  const arrayColor = [
12
- theme.colors.primary,
13
- theme.colors.secondary,
14
- theme.colors.primary,
12
+ color ?? theme.colors.primary,
13
+ theme.colors.background.surface,
14
+ color ?? theme.colors.primary,
15
15
  ];
16
16
 
17
- let source = animation;
18
- source.assets[0].layers[0].shapes[0].it.forEach(item => {
17
+ let source: any = animation;
18
+ source.assets[0].layers[0].shapes[0].it.forEach((item: any) => {
19
19
  if (item.ty === 'fl' && item.c) {
20
- item.c.k.forEach((fillItem, index) => {
20
+ item.c.k.forEach((fillItem: any, index: number) => {
21
21
  if (typeof fillItem !== 'number') {
22
- fillItem.s = hexToRGBA(arrayColor[index]);
22
+ fillItem.s = hexToRGBA(arrayColor[index] as string);
23
23
  }
24
24
  });
25
25
  }
26
26
  });
27
27
 
28
28
  return (
29
- <View style={style}>
30
- <AnimatedLottieView
31
- source={source}
32
- style={{width: 52, height: 18}}
33
- autoPlay
34
- />
35
- </View>
29
+ <AnimatedLottieView
30
+ source={source}
31
+ style={{width: 52, height: 18}}
32
+ autoPlay
33
+ />
36
34
  );
37
35
  };
38
36
 
package/Loader/Loader.tsx CHANGED
@@ -3,12 +3,11 @@ import {LoaderProps} from './types';
3
3
  import DotLoader from './DotLoader';
4
4
  import Spinner from './Spinner';
5
5
 
6
- const Loader: FC<LoaderProps> = ({type = 'dot', style}) => {
6
+ const Loader: FC<LoaderProps> = ({type = 'dot', ...props}) => {
7
7
  if (type === 'spinner') {
8
- return <Spinner style={style} />;
8
+ return <Spinner {...props} key={props.color} />;
9
9
  }
10
-
11
- return <DotLoader style={style} />;
10
+ return <DotLoader {...props} key={props.color} />;
12
11
  };
13
12
 
14
13
  export default Loader;
@@ -1,30 +1,28 @@
1
1
  import React, {FC, useContext} from 'react';
2
- import {View, ViewProps} from 'react-native';
3
2
  import AnimatedLottieView from 'lottie-react-native';
4
3
  import animation from '../Assets/SpinnerAnimation.json';
5
4
  import {hexToRGBA} from './utils';
6
5
  import {ApplicationContext} from '../Application';
6
+ import {LoaderProps} from './types';
7
7
 
8
- const Spinner: FC<ViewProps> = ({style}) => {
8
+ const Spinner: FC<LoaderProps> = ({color}) => {
9
9
  const {theme} = useContext(ApplicationContext);
10
10
 
11
- let source = animation;
12
- source.assets[0].layers.forEach(layer => {
13
- layer.shapes[0].it.forEach(item => {
11
+ let source: any = animation;
12
+ source.assets[0].layers.forEach((layer: any) => {
13
+ layer.shapes[0].it.forEach((item: any) => {
14
14
  if (item.ty === 'fl' && item.c) {
15
- item.c.k = hexToRGBA(theme.colors.primary);
15
+ item.c.k = hexToRGBA(color ?? theme.colors.primary);
16
16
  }
17
17
  });
18
18
  });
19
19
 
20
20
  return (
21
- <View style={style}>
22
- <AnimatedLottieView
23
- source={source}
24
- style={{width: 24, height: 24}}
25
- autoPlay
26
- />
27
- </View>
21
+ <AnimatedLottieView
22
+ source={source}
23
+ style={{width: 24, height: 24}}
24
+ autoPlay
25
+ />
28
26
  );
29
27
  };
30
28
 
package/Loader/types.ts CHANGED
@@ -2,10 +2,12 @@ import {ViewStyle} from 'react-native';
2
2
 
3
3
  export type LoaderProps = {
4
4
  type?: 'dot' | 'spinner';
5
+ color?: string;
5
6
  style?: ViewStyle | ViewStyle[];
6
7
  };
7
8
 
8
9
  export type ProgressBarProps = {
9
10
  percent: number;
11
+ color?: string;
10
12
  style?: ViewStyle | ViewStyle[];
11
13
  };
@@ -1,16 +1,14 @@
1
- import React, {FC, useContext} from 'react';
1
+ import React, {FC} from 'react';
2
2
  import {View} from 'react-native';
3
3
  import {ChildPaginationProps} from './types';
4
4
  import styles from './styles';
5
5
  import Dot from './Dot';
6
6
  import {Colors, Spacing} from '../Consts';
7
- import {ApplicationContext} from '../Application';
8
7
 
9
8
  const PaginationWhiteDot: FC<ChildPaginationProps> = ({
10
9
  dataLength = 2,
11
10
  activeIndex = 0,
12
11
  }) => {
13
- const {theme} = useContext(ApplicationContext);
14
12
  const renderDots = () => {
15
13
  const dots = [];
16
14
  for (let i = 0; i < dataLength; i++) {
package/Popup/types.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import {TextStyle} from 'react-native';
2
+ import React from 'react';
3
+
1
4
  export type PopupNotifyProps = {
2
5
  /**
3
6
  * `image`: Optional. Represents the URL or path of the image to be displayed in the PopupNotify component.
@@ -12,7 +15,7 @@ export type PopupNotifyProps = {
12
15
  /**
13
16
  * `description`: Represents the description text to be displayed in the PopupNotify component.
14
17
  */
15
- description: string;
18
+ description: string | React.ReactNode;
16
19
 
17
20
  /**
18
21
  * `information`: Optional. Represents additional information text to be displayed in the PopupNotify component.
@@ -67,4 +70,9 @@ type PopupAction = {
67
70
  onPress: () => void;
68
71
  };
69
72
 
73
+ export type HighlightText = {
74
+ text: string;
75
+ style: TextStyle;
76
+ };
77
+
70
78
  type PopupActionDirection = 'row' | 'column' | 'auto';
package/Radio/index.tsx CHANGED
@@ -39,7 +39,7 @@ const Radio: FC<RadioProps> = ({
39
39
 
40
40
  return (
41
41
  <TouchableOpacity
42
- accessibilityLabel={`Radio/${label}`}
42
+ accessibilityLabel={`Radio/${label}/${value}`}
43
43
  onPress={onChange}
44
44
  disabled={disabled}
45
45
  style={[
package/Text/index.tsx CHANGED
@@ -3,7 +3,6 @@ import {Text as RNText, TextProps as RNTextProps} from 'react-native';
3
3
  import styles from './styles';
4
4
  import {Typography, TypographyWeight} from './types';
5
5
  import {ApplicationContext} from '../Application';
6
- import {GridContext} from '../Layout';
7
6
  import {scaleSize} from './utils';
8
7
 
9
8
  const SFProText: TypographyWeight = {
@@ -51,22 +50,14 @@ export interface TextProps extends RNTextProps {
51
50
  * It can be any valid color string (e.g., hex, rgb, rgba, etc.).
52
51
  */
53
52
  color?: string;
54
-
55
- /**
56
- * Optional. Represents the width of the Text component in terms of span numbers.
57
- * It can be used to set a specific width for the text based on a predefined grid system.
58
- */
59
- widthSpan?: number;
60
53
  }
61
54
  const Text: React.FC<TextProps> = ({
62
55
  typography,
63
56
  color,
64
57
  children,
65
58
  style,
66
- widthSpan,
67
59
  ...rest
68
60
  }) => {
69
- const grid = useContext(GridContext);
70
61
  const {theme} = useContext(ApplicationContext);
71
62
 
72
63
  const getTypoStyle = (typo: Typography) => {
@@ -101,17 +92,11 @@ const Text: React.FC<TextProps> = ({
101
92
  };
102
93
 
103
94
  const textStyle = getTypoStyle(typography);
104
- const spanStyle = widthSpan ? {width: grid.getSizeSpan(widthSpan)} : {};
105
95
  return (
106
96
  <RNText
107
97
  {...rest}
108
98
  accessibilityLabel={`Text/${children}`}
109
- style={[
110
- style,
111
- textStyle,
112
- spanStyle,
113
- {color: color ?? theme.colors.text.default},
114
- ]}>
99
+ style={[style, textStyle, {color: color ?? theme.colors.text.default}]}>
115
100
  {children ?? ''}
116
101
  </RNText>
117
102
  );
package/Text/utils.ts CHANGED
@@ -6,7 +6,7 @@ const scaleSize = (size: number) => {
6
6
  const scaleRate = deviceWidth / DEFAULT_SCREEN_SIZE;
7
7
 
8
8
  if (scaleRate > 1) {
9
- return Math.min(Math.round(size * scaleRate), size + 5);
9
+ return Math.min(Math.round(size * scaleRate), size + 3);
10
10
  }
11
11
 
12
12
  return size;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.77.8-beta.03",
3
+ "version": "0.77.8-beta.05",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {