@momo-kits/foundation 0.89.6 → 0.92.1-beta.16

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.
@@ -4,9 +4,14 @@ import {PopupNotifyProps} from './types';
4
4
  import {Radius, Spacing, Styles} from '../Consts';
5
5
  import {Image} from '../Image';
6
6
  import {Text} from '../Text';
7
- import {ApplicationContext, MiniAppContext} from '../Application';
7
+ import {ApplicationContext} from '../Application';
8
8
  import {Button} from '../Button';
9
9
  import {Icon} from '../Icon';
10
+ import {getAccessibilityID} from '../Application/utils';
11
+
12
+ const {
13
+ MiniAppContext,
14
+ } = require('react-native/Libraries/Components/ScreenContext');
10
15
 
11
16
  const PopupNotify: React.FC<PopupNotifyProps> = ({
12
17
  id,
@@ -19,7 +24,7 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
19
24
  buttonDirection = 'row',
20
25
  onIconClose,
21
26
  }) => {
22
- const context = useContext(MiniAppContext);
27
+ const context = useContext<any>(MiniAppContext);
23
28
  const {theme, navigator, translate} = useContext(ApplicationContext);
24
29
  const [scrollContent, setScrollContent] = useState(false);
25
30
  const closeAction = useRef('touch_outside');
@@ -89,6 +94,7 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
89
94
  closeAction.current = 'button_action';
90
95
  onAction(secondary?.onPress);
91
96
  }}
97
+ accessibilityLabel={'btn_popup_cancel'}
92
98
  />
93
99
  </View>
94
100
  <View style={styles.buttonSpace} />
@@ -102,6 +108,7 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
102
108
  closeAction.current = 'button_action';
103
109
  onAction(primary.onPress);
104
110
  }}
111
+ accessibilityLabel={'btn_popup_allow'}
105
112
  />
106
113
  </View>
107
114
  </View>
@@ -111,6 +118,7 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
111
118
  return (
112
119
  <View style={Styles.columnCenter}>
113
120
  <Button
121
+ accessibilityLabel={'btn_popup_allow'}
114
122
  title={primary.title}
115
123
  size="medium"
116
124
  onPress={() => {
@@ -122,6 +130,7 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
122
130
  <>
123
131
  <View style={styles.buttonSpace} />
124
132
  <Button
133
+ accessibilityLabel={'btn_popup_cancel'}
125
134
  title={secondary?.title}
126
135
  type="text"
127
136
  size="medium"
@@ -157,6 +166,7 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
157
166
  const buildCloseIcon = () => {
158
167
  return (
159
168
  <TouchableOpacity
169
+ {...getAccessibilityID?.('ic_popup_close')}
160
170
  style={styles.iconCloseContainer}
161
171
  onPress={() => {
162
172
  closeAction.current = 'icon_close';
@@ -182,6 +192,7 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
182
192
 
183
193
  return (
184
194
  <View
195
+ {...getAccessibilityID?.(`pu_${context.code}_notify`)}
185
196
  style={[
186
197
  styles.container,
187
198
  {backgroundColor: theme.colors.background.surface},
@@ -1,17 +1,22 @@
1
1
  import React, {useContext, useEffect, useRef} from 'react';
2
2
  import {StyleSheet, TouchableOpacity, View} from 'react-native';
3
3
  import {PopupPromotionProps} from './types';
4
- import {ApplicationContext, MiniAppContext} from '../Application';
4
+ import {ApplicationContext} from '../Application';
5
5
  import {Image} from '../Image';
6
6
  import {Radius, Spacing} from '../Consts';
7
7
  import {Icon} from '../Icon';
8
+ import {getAccessibilityID} from '../Application/utils';
9
+
10
+ const {
11
+ MiniAppContext,
12
+ } = require('react-native/Libraries/Components/ScreenContext');
8
13
 
9
14
  const PopupPromotion: React.FC<PopupPromotionProps> = ({
10
15
  id,
11
16
  image,
12
17
  onIconClose,
13
18
  }) => {
14
- const context = useContext(MiniAppContext);
19
+ const context = useContext<any>(MiniAppContext);
15
20
  const {theme, navigator} = useContext(ApplicationContext);
16
21
  const closeAction = useRef('touch_outside');
17
22
 
@@ -49,7 +54,9 @@ const PopupPromotion: React.FC<PopupPromotionProps> = ({
49
54
  */
50
55
  const buildCloseIcon = () => {
51
56
  return (
52
- <View style={styles.iconCloseContainer}>
57
+ <View
58
+ {...getAccessibilityID?.('ic_popup_close')}
59
+ style={styles.iconCloseContainer}>
53
60
  <TouchableOpacity
54
61
  onPress={() => {
55
62
  closeAction.current = 'icon_close';
@@ -77,7 +84,7 @@ const PopupPromotion: React.FC<PopupPromotionProps> = ({
77
84
  };
78
85
 
79
86
  return (
80
- <View>
87
+ <View {...getAccessibilityID?.(`pu_${context.code}_promotion`)}>
81
88
  <Image
82
89
  source={{
83
90
  uri: image,
package/Radio/index.tsx CHANGED
@@ -6,6 +6,16 @@ import {Text} from '../Text';
6
6
  import styles from './styles';
7
7
  import {ApplicationContext} from '../Application';
8
8
  import {Spacing} from '../Consts';
9
+ import {
10
+ cleanNameForTracking,
11
+ formatNameLength,
12
+ getAccessibilityID,
13
+ } from '../Application/utils';
14
+
15
+ const {
16
+ ScreenContext,
17
+ MiniAppContext,
18
+ } = require('react-native/Libraries/Components/ScreenContext');
9
19
 
10
20
  const Radio: FC<RadioProps> = ({
11
21
  value,
@@ -14,8 +24,12 @@ const Radio: FC<RadioProps> = ({
14
24
  onChange,
15
25
  label,
16
26
  style,
27
+ params,
28
+ componentId,
17
29
  }) => {
30
+ const {appId, code} = useContext<any>(MiniAppContext);
18
31
  const {theme} = useContext(ApplicationContext);
32
+ const screenInfo = useContext<any>(ScreenContext);
19
33
  const selected = value === groupValue;
20
34
  let disabledStyle = {};
21
35
  let checkBoxStyle = {
@@ -37,27 +51,46 @@ const Radio: FC<RadioProps> = ({
37
51
  };
38
52
  }
39
53
 
54
+ const accessibilityID = getAccessibilityID?.(
55
+ `${appId}/${code}/${screenInfo.screenName}/rdo_${cleanNameForTracking(
56
+ label,
57
+ )}_${selected}`,
58
+ );
59
+
40
60
  return (
41
- <TouchableOpacity
42
- onPress={onChange}
43
- disabled={disabled}
44
- style={[
45
- style,
46
- {
47
- flexDirection: 'row',
48
- alignItems: 'center',
49
- },
50
- ]}>
51
- <View
61
+ <ScreenContext.Provider
62
+ value={{
63
+ ...screenInfo,
64
+ componentName: 'Button',
65
+ params,
66
+ state: disabled ? 'disabled' : 'enabled',
67
+ componentId,
68
+ componentLabel: formatNameLength(label || ''),
69
+ componentValue: value,
70
+ action: 'click',
71
+ }}>
72
+ <TouchableOpacity
73
+ {...accessibilityID}
74
+ onPress={onChange}
75
+ disabled={disabled}
52
76
  style={[
53
- styles.radio,
54
- checkBoxStyle,
55
- disabledStyle,
56
- {marginRight: label ? Spacing.XS : 0},
57
- ]}
58
- />
59
- {!!label && <Text typography={'body_default_regular'}>{label}</Text>}
60
- </TouchableOpacity>
77
+ style,
78
+ {
79
+ flexDirection: 'row',
80
+ alignItems: 'center',
81
+ },
82
+ ]}>
83
+ <View
84
+ style={[
85
+ styles.radio,
86
+ checkBoxStyle,
87
+ disabledStyle,
88
+ {marginRight: label ? Spacing.XS : 0},
89
+ ]}
90
+ />
91
+ {!!label && <Text typography={'body_default_regular'}>{label}</Text>}
92
+ </TouchableOpacity>
93
+ </ScreenContext.Provider>
61
94
  );
62
95
  };
63
96
 
package/Radio/types.ts CHANGED
@@ -35,4 +35,9 @@ export type RadioProps = {
35
35
  * Accepts an object of style properties.
36
36
  */
37
37
  style?: ViewStyle;
38
+
39
+
40
+ params?: any
41
+
42
+ componentId?: string
38
43
  };
package/Switch/index.tsx CHANGED
@@ -1,11 +1,20 @@
1
- import React, {FC} from 'react';
1
+ import React, {FC, useContext} from 'react';
2
2
  import {TouchableOpacity, View} from 'react-native';
3
3
  import {SwitchProps} from './types';
4
4
  import styles from './styles';
5
5
  import {Colors} from '../Consts';
6
+ import {getAccessibilityID} from '../Application/utils';
7
+
8
+ const {
9
+ ScreenContext,
10
+ MiniAppContext,
11
+ } = require('react-native/Libraries/Components/ScreenContext');
6
12
 
7
13
  const Switch: FC<SwitchProps> = props => {
8
- const {value, onChange, disabled, style} = props;
14
+ const {appId, code} = useContext<any>(MiniAppContext);
15
+ const {value, onChange, disabled, style, params, componentId} = props;
16
+ const screenInfo = useContext<any>(ScreenContext);
17
+
9
18
  const circleBackgroundColor = value ? Colors.black_01 : Colors.black_03;
10
19
  const circleAlign = value ? 'flex-end' : 'flex-start';
11
20
 
@@ -14,19 +23,35 @@ const Switch: FC<SwitchProps> = props => {
14
23
  backgroundColor = value ? Colors.green_09 : Colors.black_05;
15
24
  }
16
25
 
26
+ const accessibilityID = getAccessibilityID?.(
27
+ `${appId}/${code}/${screenInfo.screenName}/swt_${value}`,
28
+ );
29
+
17
30
  return (
18
- <TouchableOpacity
19
- disabled={disabled}
20
- onPress={() => onChange?.(!value)}
21
- style={[
22
- style,
23
- styles.container,
24
- {backgroundColor, alignItems: circleAlign},
25
- ]}>
26
- <View style={[styles.circle, {backgroundColor: circleBackgroundColor}]}>
27
- <View style={[styles.circleSmall, {backgroundColor}]} />
28
- </View>
29
- </TouchableOpacity>
31
+ <ScreenContext.Provider
32
+ value={{
33
+ ...screenInfo,
34
+ componentName: 'Button',
35
+ params,
36
+ state: disabled ? 'disabled' : 'enabled',
37
+ componentId,
38
+ componentValue: value,
39
+ action: 'click',
40
+ }}>
41
+ <TouchableOpacity
42
+ {...accessibilityID}
43
+ disabled={disabled}
44
+ onPress={() => onChange?.(!value)}
45
+ style={[
46
+ style,
47
+ styles.container,
48
+ {backgroundColor, alignItems: circleAlign},
49
+ ]}>
50
+ <View style={[styles.circle, {backgroundColor: circleBackgroundColor}]}>
51
+ <View style={[styles.circleSmall, {backgroundColor}]} />
52
+ </View>
53
+ </TouchableOpacity>
54
+ </ScreenContext.Provider>
30
55
  );
31
56
  };
32
57
 
package/Switch/types.ts CHANGED
@@ -23,4 +23,8 @@ export type SwitchProps = {
23
23
  * Accepts an object of style properties.
24
24
  */
25
25
  style?: ViewStyle;
26
+
27
+ params?: any
28
+
29
+ componentId?: string
26
30
  };
package/Text/index.tsx CHANGED
@@ -52,6 +52,21 @@ export interface TextProps extends RNTextProps {
52
52
  color?: string;
53
53
  }
54
54
 
55
+ const deprecatedValues: Typography[] = [
56
+ 'headline_default',
57
+ 'headline_l',
58
+ 'headline_xl',
59
+ 'title_default',
60
+ 'title_xs',
61
+ 'title_s',
62
+ 'header_default',
63
+ 'paragraph_default',
64
+ 'paragraph_bold',
65
+ 'paragraph_italic',
66
+ 'label_xxs',
67
+ 'action_s',
68
+ ];
69
+
55
70
  const Text: React.FC<TextProps> = ({
56
71
  typography = 'body_default_regular',
57
72
  color,
@@ -95,6 +110,13 @@ const Text: React.FC<TextProps> = ({
95
110
  };
96
111
 
97
112
  const textStyle = getTypoStyle(typography);
113
+
114
+ if (deprecatedValues.includes(typography)) {
115
+ console.warn(
116
+ `Warning: The typography value "${typography}" is deprecated.`,
117
+ );
118
+ }
119
+
98
120
  return (
99
121
  <RNText
100
122
  {...rest}
package/Text/styles.ts CHANGED
@@ -5,7 +5,7 @@ export default {
5
5
  header_s_semibold: {fontSize: 14, lineHeight: 20, fontWeight: '600'},
6
6
  header_xs_semibold: {fontSize: 12, lineHeight: 18, fontWeight: '600'},
7
7
  body_default_regular: {fontSize: 14, lineHeight: 20, fontWeight: '400'},
8
- body_regularstrikethrought: {
8
+ body_default_regularstrikethrought: {
9
9
  fontSize: 14,
10
10
  lineHeight: 20,
11
11
  fontWeight: '400',
package/Text/types.ts CHANGED
@@ -14,13 +14,31 @@ export type TypographyWeight = {
14
14
  };
15
15
 
16
16
  export type Typography =
17
+ /**
18
+ * @deprecated
19
+ **/
20
+ | 'headline_default'
21
+ | 'headline_l'
22
+ | 'headline_xl'
23
+ | 'title_default'
24
+ | 'title_xs'
25
+ | 'title_s'
26
+ | 'header_default'
27
+ | 'paragraph_default'
28
+ | 'paragraph_bold'
29
+ | 'paragraph_italic'
30
+ | 'label_xxs'
31
+ | 'action_s'
32
+ /**
33
+ * end
34
+ **/
17
35
  | 'headline_default_bold'
18
36
  | 'header_m_bold'
19
37
  | 'header_default_bold'
20
38
  | 'header_s_semibold'
21
39
  | 'header_xs_semibold'
22
40
  | 'body_default_regular'
23
- | 'body_regularstrikethrought'
41
+ | 'body_default_regularstrikethrought'
24
42
  | 'description_default_regular'
25
43
  | 'description_default_regularstrikethrought'
26
44
  | 'description_xs_regular'
package/Title/index.tsx CHANGED
@@ -1,129 +1,175 @@
1
1
  import React, {FC, useContext, useState} from 'react';
2
- import {
3
- LayoutChangeEvent,
4
- NativeSyntheticEvent,
5
- Text as RNText,
6
- TextLayoutEventData,
7
- TouchableOpacity,
8
- View,
9
- } from 'react-native';
10
- import {TitleProps} from './types';
11
- import {Icon} from '../Icon';
2
+ import {Text as RNText, TouchableOpacity, View, ViewStyle} from 'react-native';
12
3
  import styles from './styles';
13
- import {ApplicationContext} from '../Application';
14
- import {Colors, Spacing} from '../Consts';
4
+ import {Icon} from '../Icon';
15
5
  import {scaleSize, Text} from '../Text';
6
+ import {ApplicationContext} from '../Application';
7
+ import {Badge} from '../Badge';
8
+ import {Typography} from '../Text/types';
9
+ import {TitleProps} from './types';
10
+ import {Colors} from '../Consts';
16
11
 
17
12
  const Title: FC<TitleProps> = ({
18
- size = 'large',
19
- type = 'section',
20
- onPressAction,
21
- actionTitle,
22
13
  title = 'Title',
23
- titleFlex = true,
24
- showAction = true,
14
+ type = 'section',
15
+ size = 'medium',
25
16
  icon,
26
17
  description,
27
- usePadding = true,
18
+ iconColor = null,
19
+ iconAlign = 'top',
20
+ showRightAction = false,
21
+ showTrailingAction = false,
22
+ badgeLabel,
23
+ buttonTitle,
24
+ onPressRightAction = () => {},
25
+ buttonSize = 'small',
26
+ textOnly = false,
28
27
  }) => {
29
28
  const {theme} = useContext(ApplicationContext);
30
- const [containerWidth, setContainerWidth] = useState(0);
31
- const [textLines, setTextLines] = useState(0);
32
- const typeStyle =
33
- type === 'screen' ? styles.screen : styles[`${type}_${size}`];
34
- const titleWeight = type === 'screen' ? 'Semibold' : 'Bold';
35
- const marginStyle =
36
- type === 'section' && usePadding ? {marginTop: Spacing.S} : {};
37
- const numberOfLines = type === 'section' ? 1 : 2;
29
+ const [badgeWidth, setBadgeWidth] = useState(0);
30
+ const [contentWidth, setContentWidth] = useState(0);
31
+ const styleSheet: {
32
+ [key: string]: any;
33
+ } = styles;
34
+ const typography = `${type}_${size}`;
35
+ const isSection = type === 'section';
36
+ const numberOfLines = showTrailingAction || !!badgeLabel ? 1 : 2;
37
+ const buttonTypo: Typography =
38
+ buttonSize === 'small' ? 'action_xs_bold' : 'action_s_bold';
39
+ const flexStyle = showTrailingAction && {maxWidth: '70%'};
38
40
 
39
- const renderAction = () => {
40
- return !!actionTitle && titleFlex ? (
41
- <TouchableOpacity onPress={onPressAction}>
42
- <Text typography={'action_s_bold'} color={theme.colors.primary}>
43
- {actionTitle}
44
- </Text>
45
- </TouchableOpacity>
46
- ) : (
47
- <TouchableOpacity
48
- style={[
49
- {backgroundColor: theme.colors.primary + '0F'},
50
- styles.actionIcon,
51
- {width: scaleSize(22), height: scaleSize(22)},
52
- ]}
53
- onPress={onPressAction}>
54
- <Icon
55
- size={scaleSize(22)}
56
- color={theme.colors.primary}
57
- source={'arrow_chevron_right_small'}
58
- />
59
- </TouchableOpacity>
41
+ const renderIcon = () => {
42
+ if (!icon) return null;
43
+
44
+ let iconStyle: ViewStyle = {
45
+ justifyContent: 'flex-start',
46
+ };
47
+
48
+ if (iconAlign === 'middle') {
49
+ iconStyle = {justifyContent: 'center'};
50
+ }
51
+
52
+ if (iconAlign === 'bottom') {
53
+ iconStyle = {justifyContent: 'flex-end'};
54
+ }
55
+
56
+ return (
57
+ <View style={[styles.iconView, iconStyle]}>
58
+ <Icon color={iconColor} source={icon} />
59
+ </View>
60
60
  );
61
61
  };
62
62
 
63
- const renderSemiAction = () => {
64
- if (textLines > 1) return null;
63
+ const renderContent = () => {
65
64
  return (
66
- <TouchableOpacity
67
- style={[
68
- {backgroundColor: Colors.black_06},
69
- styles.actionIcon,
70
- {width: scaleSize(18), height: scaleSize(18)},
71
- ]}
72
- onPress={onPressAction}>
73
- <Icon
74
- size={scaleSize(18)}
75
- color={theme.colors.text.default}
76
- source={'arrow_chevron_right_small'}
77
- />
78
- </TouchableOpacity>
65
+ <View style={styles.contentView}>
66
+ <View
67
+ onLayout={e => {
68
+ setContentWidth(e.nativeEvent.layout.width);
69
+ }}
70
+ style={[styles.iconLeftView, flexStyle]}>
71
+ <RNText
72
+ numberOfLines={numberOfLines}
73
+ style={[
74
+ styleSheet[typography],
75
+ styles.title,
76
+ {maxWidth: contentWidth - badgeWidth},
77
+ ]}>
78
+ {title}
79
+ </RNText>
80
+ {badgeLabel && (
81
+ <View
82
+ onLayout={e => {
83
+ setBadgeWidth(e.nativeEvent.layout.width);
84
+ }}
85
+ style={{
86
+ alignItems: 'center',
87
+ }}>
88
+ <Badge style={styles.badge} label={badgeLabel} />
89
+ </View>
90
+ )}
91
+ {renderActionLeft()}
92
+ </View>
93
+ <Text
94
+ color={theme.colors.text.secondary}
95
+ typography={'description_default_regular'}>
96
+ {description}
97
+ </Text>
98
+ </View>
79
99
  );
80
100
  };
81
- const onLayout = (e: LayoutChangeEvent) => {
82
- setContainerWidth(e.nativeEvent.layout.width);
83
- };
84
101
 
85
- const onTextLayout = (e: NativeSyntheticEvent<TextLayoutEventData>) => {
86
- setTextLines(e.nativeEvent.lines.length);
102
+ const renderActionLeft = () => {
103
+ return (
104
+ <View style={styles.iconLeftView}>
105
+ {showTrailingAction && !showRightAction && (
106
+ <View
107
+ style={[
108
+ styles.iconLeft,
109
+ {
110
+ backgroundColor: isSection
111
+ ? Colors.black_06 + '99'
112
+ : Colors.black_06 + '4D',
113
+ },
114
+ ]}>
115
+ <Icon
116
+ source={'arrow_chevron_right_small'}
117
+ size={scaleSize(18)}
118
+ color={theme.colors.text.default}
119
+ />
120
+ </View>
121
+ )}
122
+ </View>
123
+ );
87
124
  };
88
125
 
89
- return (
90
- <View onLayout={onLayout} style={[styles.wrapper, marginStyle]}>
91
- {!!icon && type !== 'screen' && (
92
- <Icon style={styles.icon} source={icon} />
93
- )}
94
- <View style={{flex: 1, flexDirection: 'row'}}>
95
- <View style={styles.textContent}>
126
+ const renderActionRight = () => {
127
+ if (!showRightAction || showTrailingAction) return false;
128
+
129
+ return (
130
+ <View>
131
+ {!buttonTitle ? (
96
132
  <View
97
- style={{
98
- flexDirection: 'row',
99
- maxWidth: containerWidth - scaleSize(22),
100
- }}>
101
- <RNText
102
- onTextLayout={onTextLayout}
103
- numberOfLines={numberOfLines}
104
- style={[
105
- typeStyle,
106
- {
107
- fontFamily: `${theme.font}-${titleWeight}`,
108
- color: theme.colors.text.default,
109
- marginRight: Spacing.S,
110
- },
111
- ]}>
112
- {title}
113
- </RNText>
114
- {!titleFlex && renderSemiAction()}
133
+ style={[
134
+ styles.iconRight,
135
+ {
136
+ backgroundColor: theme.colors.primary + '0F',
137
+ },
138
+ ]}>
139
+ <Icon
140
+ source={'arrow_chevron_right_small'}
141
+ size={scaleSize(22)}
142
+ color={theme.colors.primary}
143
+ />
115
144
  </View>
116
- {!!description && type !== 'screen' && (
117
- <Text
118
- numberOfLines={1}
119
- typography={'description_default_regular'}
120
- color={theme.colors.text.secondary}>
121
- {description}
145
+ ) : (
146
+ <TouchableOpacity onPress={onPressRightAction}>
147
+ <Text color={theme.colors.primary} typography={buttonTypo}>
148
+ {buttonTitle}
122
149
  </Text>
123
- )}
124
- </View>
125
- {showAction && titleFlex && type !== 'screen' && renderAction()}
150
+ </TouchableOpacity>
151
+ )}
126
152
  </View>
153
+ );
154
+ };
155
+
156
+ if (textOnly) {
157
+ return (
158
+ <View style={isSection && styles.margin}>
159
+ <RNText
160
+ numberOfLines={numberOfLines}
161
+ style={[styleSheet[typography], styles.title]}>
162
+ {title}
163
+ </RNText>
164
+ </View>
165
+ );
166
+ }
167
+
168
+ return (
169
+ <View style={[styles.wrapper, isSection && styles.margin]}>
170
+ {renderIcon()}
171
+ {renderContent()}
172
+ {renderActionRight()}
127
173
  </View>
128
174
  );
129
175
  };