@momo-kits/avatar 0.73.3-beta.4 → 0.74.2-react-native.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.
- package/index.tsx +119 -0
- package/package.json +11 -10
- package/publish.sh +2 -3
- package/styles.ts +17 -0
- package/types.ts +52 -0
- package/Avatar.js +0 -408
- package/Avatar.web.js +0 -405
- package/index.js +0 -3
package/index.tsx
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import React, {FC, useContext} from 'react';
|
|
2
|
+
import {View} from 'react-native';
|
|
3
|
+
import {AvatarProps} from './types';
|
|
4
|
+
import {
|
|
5
|
+
ApplicationContext,
|
|
6
|
+
Colors,
|
|
7
|
+
Icon,
|
|
8
|
+
Image,
|
|
9
|
+
scaleSize,
|
|
10
|
+
Spacing,
|
|
11
|
+
Text,
|
|
12
|
+
} from '@momo-kits/foundation';
|
|
13
|
+
import styles from './styles';
|
|
14
|
+
|
|
15
|
+
const logo = 'https://static.momocdn.net/app/img/kits/logo_momo_circle.png';
|
|
16
|
+
const iconSupportDefault =
|
|
17
|
+
'https://static.momocdn.net/app/img/kits/_indicator.png';
|
|
18
|
+
|
|
19
|
+
const Avatar: FC<AvatarProps> = ({
|
|
20
|
+
size = 32,
|
|
21
|
+
name,
|
|
22
|
+
rounded = true,
|
|
23
|
+
showIconMomo = false,
|
|
24
|
+
showIconSupport = false,
|
|
25
|
+
iconSupport = iconSupportDefault,
|
|
26
|
+
image,
|
|
27
|
+
}) => {
|
|
28
|
+
const {theme} = useContext(ApplicationContext);
|
|
29
|
+
const borderRadius = rounded ? size / 2 : Spacing.XS;
|
|
30
|
+
|
|
31
|
+
const getShortName = (name: string) => {
|
|
32
|
+
const words = name.split(' ');
|
|
33
|
+
const lastTwoWords = words.slice(-2);
|
|
34
|
+
return lastTwoWords.map(word => word.charAt(0).toUpperCase()).join('');
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const getIconSize = () => {
|
|
38
|
+
switch (size) {
|
|
39
|
+
case 24: {
|
|
40
|
+
return 16;
|
|
41
|
+
}
|
|
42
|
+
case 32: {
|
|
43
|
+
return 16;
|
|
44
|
+
}
|
|
45
|
+
case 40: {
|
|
46
|
+
return 24;
|
|
47
|
+
}
|
|
48
|
+
case 48: {
|
|
49
|
+
return 32;
|
|
50
|
+
}
|
|
51
|
+
case 56: {
|
|
52
|
+
return 32;
|
|
53
|
+
}
|
|
54
|
+
case 72: {
|
|
55
|
+
return 40;
|
|
56
|
+
}
|
|
57
|
+
default: {
|
|
58
|
+
return 16;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const iconSize = getIconSize();
|
|
64
|
+
const shouldShowIconTop = showIconMomo && rounded;
|
|
65
|
+
const shouldShowIconBottom = showIconSupport && rounded;
|
|
66
|
+
const supportIconSize = {
|
|
67
|
+
width: getIconSize() / 2,
|
|
68
|
+
height: getIconSize() / 2,
|
|
69
|
+
borderRadius: getIconSize() / 4,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<View
|
|
74
|
+
style={[
|
|
75
|
+
styles.container,
|
|
76
|
+
{
|
|
77
|
+
width: scaleSize(size),
|
|
78
|
+
height: scaleSize(size),
|
|
79
|
+
backgroundColor: Colors.pink_09,
|
|
80
|
+
borderColor: theme.colors.border.default,
|
|
81
|
+
borderRadius: scaleSize(borderRadius),
|
|
82
|
+
},
|
|
83
|
+
]}>
|
|
84
|
+
{shouldShowIconTop && (
|
|
85
|
+
<Image
|
|
86
|
+
source={{uri: logo}}
|
|
87
|
+
style={[styles.icon, supportIconSize, {top: -1, right: -1}]}
|
|
88
|
+
/>
|
|
89
|
+
)}
|
|
90
|
+
{!!name && !image && (
|
|
91
|
+
<Text color={Colors.pink_03} typography={'description_xs_regular'}>
|
|
92
|
+
{getShortName(name)}
|
|
93
|
+
</Text>
|
|
94
|
+
)}
|
|
95
|
+
{!name && !image && (
|
|
96
|
+
<Icon size={iconSize} source={'basic_person'} color={Colors.pink_03} />
|
|
97
|
+
)}
|
|
98
|
+
{!!image && (
|
|
99
|
+
<Image
|
|
100
|
+
source={{uri: image}}
|
|
101
|
+
style={[
|
|
102
|
+
styles.image,
|
|
103
|
+
{
|
|
104
|
+
borderRadius,
|
|
105
|
+
},
|
|
106
|
+
]}
|
|
107
|
+
/>
|
|
108
|
+
)}
|
|
109
|
+
{shouldShowIconBottom && (
|
|
110
|
+
<Image
|
|
111
|
+
source={{uri: iconSupport}}
|
|
112
|
+
style={[styles.icon, supportIconSize, {bottom: -1, right: -1}]}
|
|
113
|
+
/>
|
|
114
|
+
)}
|
|
115
|
+
</View>
|
|
116
|
+
);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export {Avatar};
|
package/package.json
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@momo-kits/avatar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.74.2-react-native.1",
|
|
4
4
|
"private": false,
|
|
5
|
-
"main": "index.
|
|
6
|
-
"dependencies": {},
|
|
5
|
+
"main": "index.tsx",
|
|
7
6
|
"peerDependencies": {
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"react": "
|
|
11
|
-
"
|
|
12
|
-
"lodash": "^4.17.15"
|
|
7
|
+
"@momo-kits/foundation": "latest",
|
|
8
|
+
"react": "*",
|
|
9
|
+
"react-native": "*",
|
|
10
|
+
"prop-types": "15.7.2"
|
|
13
11
|
},
|
|
14
|
-
"devDependencies": {
|
|
15
|
-
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@momo-platform/versions": "4.1.11"
|
|
14
|
+
},
|
|
15
|
+
"license": "MoMo",
|
|
16
|
+
"dependencies": {}
|
|
16
17
|
}
|
package/publish.sh
CHANGED
|
@@ -9,7 +9,7 @@ VERSIONSTRING=( v$(jq .version package.json) )
|
|
|
9
9
|
VERSION=(${VERSIONSTRING//[\"]/})
|
|
10
10
|
echo VERSION: $VERSION
|
|
11
11
|
|
|
12
|
-
rsync -r --verbose --exclude '*.mdx' --exclude '*Demo.js' --exclude 'props-type.js' --exclude 'prop-types.js'
|
|
12
|
+
rsync -r --verbose --exclude '*.mdx' --exclude '*Demo.js' --exclude 'props-type.js' --exclude 'prop-types.js' ./* dist
|
|
13
13
|
|
|
14
14
|
# #babel component to dist
|
|
15
15
|
#babel ./dist -d dist --copy-files
|
|
@@ -25,5 +25,4 @@ npm publish --tag beta --access=public
|
|
|
25
25
|
cd ..
|
|
26
26
|
rm -rf dist
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
##curl -X POST -H 'Content-Type: application/json' 'https://chat.googleapis.com/v1/spaces/AAAAbP8987c/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=UGSFRvk_oYb9uGsAgs31bVvMm6jDkmD8zihGm3eyaQA%3D&threadKey=JoaXTEYaNNkl' -d '{"text": "@momo-kits/avatar new version release: '*"$VERSION"*' https://www.npmjs.com/package/@momo-kits/avatar"}'
|
|
28
|
+
##curl -X POST -H 'Content-Type: application/json' 'https://chat.googleapis.com/v1/spaces/AAAAbP8987c/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=UGSFRvk_oYb9uGsAgs31bVvMm6jDkmD8zihGm3eyaQA%3D&threadKey=JoaXTEYaNNkl' -d '{"text": "@momo-kits/bank new version release: '*"$VERSION"*' `https://www.npmjs.com/package/@momo-kits/avatar`"}'
|
package/styles.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {StyleSheet} from 'react-native';
|
|
2
|
+
export default StyleSheet.create({
|
|
3
|
+
icon: {
|
|
4
|
+
position: 'absolute',
|
|
5
|
+
overflow: 'hidden',
|
|
6
|
+
},
|
|
7
|
+
|
|
8
|
+
container: {
|
|
9
|
+
alignItems: 'center',
|
|
10
|
+
justifyContent: 'center',
|
|
11
|
+
borderWidth: 1,
|
|
12
|
+
},
|
|
13
|
+
image: {
|
|
14
|
+
width: '100%',
|
|
15
|
+
height: '100%',
|
|
16
|
+
},
|
|
17
|
+
});
|
package/types.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Predefined set of sizes for the avatar. The numbers represent pixel values.
|
|
3
|
+
*/
|
|
4
|
+
type AvatarSize = 24 | 32 | 40 | 48 | 56 | 72;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Props for the Avatar component, which displays an image or icon representing a user.
|
|
8
|
+
*/
|
|
9
|
+
export type AvatarProps = {
|
|
10
|
+
/**
|
|
11
|
+
* Optional. Specifies the size of the avatar from a set of predefined sizes.
|
|
12
|
+
* If not provided, the component may use a default size.
|
|
13
|
+
*/
|
|
14
|
+
size?: AvatarSize;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Optional. If `true`, the avatar will have rounded corners, providing a circular appearance.
|
|
18
|
+
* Defaults to `false` if not provided, resulting in a square or rectangular avatar.
|
|
19
|
+
*/
|
|
20
|
+
rounded?: boolean;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Optional. If `true`, an icon representing "Momo" will be displayed.
|
|
24
|
+
* This is specific to the use-case where the application requires a Momo icon.
|
|
25
|
+
* Defaults to `false` if not provided.
|
|
26
|
+
*/
|
|
27
|
+
showIconMomo?: boolean;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Optional. If `true`, a support icon will be displayed, suggesting this avatar is for support or helpdesk representation.
|
|
31
|
+
* Defaults to `false` if not provided.
|
|
32
|
+
*/
|
|
33
|
+
showIconSupport?: boolean;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Optional. Specifies the icon for support. This is used in conjunction with `showIconSupport`.
|
|
37
|
+
* If `showIconSupport` is `true` but no `iconSupport` is provided, a default icon may be used.
|
|
38
|
+
*/
|
|
39
|
+
iconSupport?: string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Optional. The name associated with the avatar. This could be the user’s full name,
|
|
43
|
+
* first name, or a username, depending on the implementation.
|
|
44
|
+
*/
|
|
45
|
+
name?: string;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Optional. The URL or local path of the image to be displayed as the avatar.
|
|
49
|
+
* If not provided, a placeholder or default avatar may be displayed.
|
|
50
|
+
*/
|
|
51
|
+
image?: string;
|
|
52
|
+
};
|
package/Avatar.js
DELETED
|
@@ -1,408 +0,0 @@
|
|
|
1
|
-
/* eslint-disable indent */
|
|
2
|
-
import {
|
|
3
|
-
Colors,
|
|
4
|
-
Image,
|
|
5
|
-
Radius,
|
|
6
|
-
ScaleSize,
|
|
7
|
-
Text,
|
|
8
|
-
ValueUtil,
|
|
9
|
-
} from '@momo-kits/core-v2';
|
|
10
|
-
import PropTypes from 'prop-types';
|
|
11
|
-
import React, {useState} from 'react';
|
|
12
|
-
import {StyleSheet, TouchableOpacity, View} from 'react-native';
|
|
13
|
-
|
|
14
|
-
const AvatarQuality = {
|
|
15
|
-
low: 'low',
|
|
16
|
-
medium: 'medium',
|
|
17
|
-
high: 'high',
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const styles = StyleSheet.create({
|
|
21
|
-
container: {
|
|
22
|
-
justifyContent: 'center',
|
|
23
|
-
alignItems: 'center',
|
|
24
|
-
},
|
|
25
|
-
shortNameView: {
|
|
26
|
-
backgroundColor: Colors.pink_09,
|
|
27
|
-
justifyContent: 'center',
|
|
28
|
-
alignItems: 'center',
|
|
29
|
-
borderWidth: 1,
|
|
30
|
-
borderColor: Colors.black_04,
|
|
31
|
-
},
|
|
32
|
-
shortNameText: {
|
|
33
|
-
// fontSize: 17,
|
|
34
|
-
color: Colors.pink_03,
|
|
35
|
-
},
|
|
36
|
-
shortNameTextCustom: {
|
|
37
|
-
color: '#f6f6f6',
|
|
38
|
-
},
|
|
39
|
-
absolute: {
|
|
40
|
-
position: 'absolute',
|
|
41
|
-
top: 0,
|
|
42
|
-
left: 0,
|
|
43
|
-
right: 0,
|
|
44
|
-
bottom: 0,
|
|
45
|
-
},
|
|
46
|
-
subIcon: {
|
|
47
|
-
position: 'absolute',
|
|
48
|
-
bottom: 0,
|
|
49
|
-
right: 0,
|
|
50
|
-
},
|
|
51
|
-
topIcon: {
|
|
52
|
-
position: 'absolute',
|
|
53
|
-
top: 0,
|
|
54
|
-
right: 0,
|
|
55
|
-
},
|
|
56
|
-
subIconImage: {
|
|
57
|
-
width: 22,
|
|
58
|
-
height: 22,
|
|
59
|
-
},
|
|
60
|
-
subIconImageOnline: {
|
|
61
|
-
backgroundColor: Colors.kiwi_green,
|
|
62
|
-
borderColor: 'white',
|
|
63
|
-
borderWidth: 1,
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const subIconSize = size => {
|
|
68
|
-
switch (size) {
|
|
69
|
-
case 'giant':
|
|
70
|
-
return {
|
|
71
|
-
width: 12,
|
|
72
|
-
height: 12,
|
|
73
|
-
borderRadius: 6,
|
|
74
|
-
};
|
|
75
|
-
case 'small':
|
|
76
|
-
return {
|
|
77
|
-
width: 8,
|
|
78
|
-
height: 8,
|
|
79
|
-
borderRadius: 4,
|
|
80
|
-
};
|
|
81
|
-
case 'medium':
|
|
82
|
-
return {
|
|
83
|
-
width: 12,
|
|
84
|
-
height: 12,
|
|
85
|
-
borderRadius: 6,
|
|
86
|
-
};
|
|
87
|
-
case 'large':
|
|
88
|
-
return {
|
|
89
|
-
width: 12,
|
|
90
|
-
height: 12,
|
|
91
|
-
borderRadius: 6,
|
|
92
|
-
};
|
|
93
|
-
default:
|
|
94
|
-
return {
|
|
95
|
-
width: 12,
|
|
96
|
-
height: 12,
|
|
97
|
-
borderRadius: 6,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const avatarSize = size => {
|
|
103
|
-
switch (size) {
|
|
104
|
-
case 'tiny':
|
|
105
|
-
return {
|
|
106
|
-
width: 24,
|
|
107
|
-
height: 24,
|
|
108
|
-
};
|
|
109
|
-
case 'small': {
|
|
110
|
-
return {
|
|
111
|
-
width: 32,
|
|
112
|
-
height: 32,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
case 'medium':
|
|
116
|
-
return {
|
|
117
|
-
width: 40,
|
|
118
|
-
height: 40,
|
|
119
|
-
};
|
|
120
|
-
case 'large':
|
|
121
|
-
return {
|
|
122
|
-
width: 56,
|
|
123
|
-
height: 56,
|
|
124
|
-
};
|
|
125
|
-
case 'giant':
|
|
126
|
-
return {
|
|
127
|
-
width: 72,
|
|
128
|
-
height: 72,
|
|
129
|
-
};
|
|
130
|
-
default:
|
|
131
|
-
return {
|
|
132
|
-
width: 40,
|
|
133
|
-
height: 40,
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
const shortName = size => {
|
|
139
|
-
switch (size) {
|
|
140
|
-
case 'tiny':
|
|
141
|
-
return {
|
|
142
|
-
fontSize: ScaleSize(10),
|
|
143
|
-
lineHeight: 16,
|
|
144
|
-
};
|
|
145
|
-
case 'small':
|
|
146
|
-
return {
|
|
147
|
-
fontSize: ScaleSize(15),
|
|
148
|
-
lineHeight: 22,
|
|
149
|
-
};
|
|
150
|
-
case 'medium':
|
|
151
|
-
return {
|
|
152
|
-
fontSize: ScaleSize(15),
|
|
153
|
-
lineHeight: 22,
|
|
154
|
-
};
|
|
155
|
-
case 'large':
|
|
156
|
-
return {
|
|
157
|
-
fontSize: ScaleSize(15),
|
|
158
|
-
lineHeight: 22,
|
|
159
|
-
};
|
|
160
|
-
case 'giant':
|
|
161
|
-
return {
|
|
162
|
-
fontSize: ScaleSize(15),
|
|
163
|
-
lineHeight: 22,
|
|
164
|
-
};
|
|
165
|
-
default:
|
|
166
|
-
return {
|
|
167
|
-
fontSize: ScaleSize(15),
|
|
168
|
-
lineHeight: 22,
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
const Avatar = ({
|
|
174
|
-
resizeMode,
|
|
175
|
-
cached,
|
|
176
|
-
quality,
|
|
177
|
-
size,
|
|
178
|
-
shape,
|
|
179
|
-
name,
|
|
180
|
-
source,
|
|
181
|
-
onPress,
|
|
182
|
-
style,
|
|
183
|
-
subIcon,
|
|
184
|
-
topIcon,
|
|
185
|
-
loading,
|
|
186
|
-
}) => {
|
|
187
|
-
const {width, height} = avatarSize(size);
|
|
188
|
-
const {fontSize, lineHeight} = shortName(size);
|
|
189
|
-
const {
|
|
190
|
-
width: iconWidth,
|
|
191
|
-
height: iconHeight,
|
|
192
|
-
borderRadius: iconRadius,
|
|
193
|
-
} = subIconSize(size);
|
|
194
|
-
|
|
195
|
-
const [imageSource, setImageSource] = useState(
|
|
196
|
-
ValueUtil.getImageSource(source),
|
|
197
|
-
);
|
|
198
|
-
const getContactShortName = name => {
|
|
199
|
-
if (!name) return '';
|
|
200
|
-
const shortNameList = name.split(' ', 2);
|
|
201
|
-
const alphabet = [];
|
|
202
|
-
shortNameList.forEach(n => {
|
|
203
|
-
if (n && n.length > 0) {
|
|
204
|
-
alphabet.push(n[0].toString().toUpperCase());
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
return alphabet.join('');
|
|
208
|
-
};
|
|
209
|
-
const isUrl = url => {
|
|
210
|
-
const expression =
|
|
211
|
-
/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/gi;
|
|
212
|
-
return expression.test(url);
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
const isValidImageUrl = source => {
|
|
216
|
-
return source && source.uri && isUrl(source.uri);
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
const mapAvatarQuality = (url, quality) => {
|
|
220
|
-
if (!quality || quality === AvatarQuality.medium) {
|
|
221
|
-
return url;
|
|
222
|
-
}
|
|
223
|
-
if (quality === AvatarQuality.low) {
|
|
224
|
-
return url.replace('.png', '_s64.png');
|
|
225
|
-
}
|
|
226
|
-
if (quality === AvatarQuality.high) {
|
|
227
|
-
return url.replace('.png', '_s512.png');
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return url;
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
const onLoadSourceError = source => {
|
|
234
|
-
setImageSource(source);
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
const renderSubIcon = () => {
|
|
238
|
-
// const subIconSizeStyle = this.mapSubIconSize(size);
|
|
239
|
-
if (subIcon && shape === 'circle' && size !== 'tiny') {
|
|
240
|
-
return (
|
|
241
|
-
<View
|
|
242
|
-
style={[
|
|
243
|
-
styles.subIcon,
|
|
244
|
-
size === 'large' && {
|
|
245
|
-
bottom: 2,
|
|
246
|
-
right: 2,
|
|
247
|
-
},
|
|
248
|
-
size === 'giant' && {
|
|
249
|
-
bottom: 4,
|
|
250
|
-
right: 4,
|
|
251
|
-
},
|
|
252
|
-
]}>
|
|
253
|
-
{typeof subIcon === 'string' ? (
|
|
254
|
-
<Image
|
|
255
|
-
source={subIcon}
|
|
256
|
-
style={[
|
|
257
|
-
{
|
|
258
|
-
width: iconWidth,
|
|
259
|
-
height: iconHeight,
|
|
260
|
-
borderRadius: iconRadius,
|
|
261
|
-
},
|
|
262
|
-
]}
|
|
263
|
-
/>
|
|
264
|
-
) : (
|
|
265
|
-
subIcon()
|
|
266
|
-
)}
|
|
267
|
-
</View>
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
const renderTopIcon = () => {
|
|
273
|
-
if (topIcon && shape === 'circle' && size !== 'tiny') {
|
|
274
|
-
return (
|
|
275
|
-
<View
|
|
276
|
-
style={[
|
|
277
|
-
styles.topIcon,
|
|
278
|
-
size === 'large' && {
|
|
279
|
-
top: 2,
|
|
280
|
-
right: 2,
|
|
281
|
-
},
|
|
282
|
-
size === 'giant' && {
|
|
283
|
-
top: 4,
|
|
284
|
-
right: 4,
|
|
285
|
-
},
|
|
286
|
-
]}>
|
|
287
|
-
<Image
|
|
288
|
-
source={topIcon}
|
|
289
|
-
style={[
|
|
290
|
-
{
|
|
291
|
-
width: iconWidth,
|
|
292
|
-
height: iconHeight,
|
|
293
|
-
borderRadius: iconRadius,
|
|
294
|
-
},
|
|
295
|
-
]}
|
|
296
|
-
/>
|
|
297
|
-
</View>
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
const onPressIcon = () => {
|
|
303
|
-
if (onPress && typeof onPress === 'function') onPress();
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
const renderShortName = () => {
|
|
307
|
-
if (name) {
|
|
308
|
-
const shortedName = getContactShortName(name);
|
|
309
|
-
// const shortNameStyle = mapShortNameStyle(size);
|
|
310
|
-
return (
|
|
311
|
-
<View
|
|
312
|
-
style={[
|
|
313
|
-
{
|
|
314
|
-
width,
|
|
315
|
-
height,
|
|
316
|
-
borderRadius: shape === 'circle' ? width / 2 : Radius.XS,
|
|
317
|
-
},
|
|
318
|
-
styles.shortNameView,
|
|
319
|
-
]}>
|
|
320
|
-
<Text
|
|
321
|
-
weight="regular"
|
|
322
|
-
style={{
|
|
323
|
-
fontSize,
|
|
324
|
-
lineHeight,
|
|
325
|
-
color: Colors.pink_03,
|
|
326
|
-
}}>
|
|
327
|
-
{shortedName}
|
|
328
|
-
</Text>
|
|
329
|
-
</View>
|
|
330
|
-
);
|
|
331
|
-
}
|
|
332
|
-
return <View />;
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
if (imageSource?.uri) {
|
|
336
|
-
imageSource.priority = 'high';
|
|
337
|
-
imageSource.uri = mapAvatarQuality(imageSource.uri, quality);
|
|
338
|
-
// if doest not have time query, set default cache time to 1 day
|
|
339
|
-
if (!imageSource.uri?.includes('?') && cached) {
|
|
340
|
-
const midnight = new Date().setHours(0, 0, 0, 0);
|
|
341
|
-
imageSource.uri = `${imageSource.uri}?time=${midnight}`;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
const renderImage = () => {
|
|
346
|
-
return (
|
|
347
|
-
<Image
|
|
348
|
-
cached={cached}
|
|
349
|
-
resizeMode={resizeMode}
|
|
350
|
-
onLoadSourceError={() => onLoadSourceError(source)}
|
|
351
|
-
source={source}
|
|
352
|
-
loading={loading}
|
|
353
|
-
style={[
|
|
354
|
-
{
|
|
355
|
-
width,
|
|
356
|
-
height,
|
|
357
|
-
borderRadius: shape === 'circle' ? width / 2 : Radius.XS,
|
|
358
|
-
},
|
|
359
|
-
]}
|
|
360
|
-
/>
|
|
361
|
-
);
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
return (
|
|
365
|
-
<TouchableOpacity
|
|
366
|
-
activeOpacity={onPress ? 0.5 : 1}
|
|
367
|
-
style={style}
|
|
368
|
-
onPress={onPressIcon}>
|
|
369
|
-
<View
|
|
370
|
-
style={{
|
|
371
|
-
alignSelf: 'baseline',
|
|
372
|
-
}}>
|
|
373
|
-
{!!imageSource && isValidImageUrl(imageSource)
|
|
374
|
-
? renderImage()
|
|
375
|
-
: renderShortName()}
|
|
376
|
-
{renderTopIcon()}
|
|
377
|
-
{renderSubIcon()}
|
|
378
|
-
</View>
|
|
379
|
-
</TouchableOpacity>
|
|
380
|
-
);
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
Avatar.propTypes = {
|
|
384
|
-
name: PropTypes.string,
|
|
385
|
-
quality: PropTypes.oneOf(['low', 'medium', 'high']),
|
|
386
|
-
size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large', 'giant']),
|
|
387
|
-
source: PropTypes.oneOfType([
|
|
388
|
-
PropTypes.shape({uri: PropTypes.string}),
|
|
389
|
-
PropTypes.number,
|
|
390
|
-
PropTypes.string,
|
|
391
|
-
]),
|
|
392
|
-
subIcon: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
|
393
|
-
topIcon: PropTypes.string,
|
|
394
|
-
|
|
395
|
-
style: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
|
396
|
-
onPress: PropTypes.func,
|
|
397
|
-
loading: PropTypes.bool,
|
|
398
|
-
shape: PropTypes.oneOf(['circle', 'square']),
|
|
399
|
-
};
|
|
400
|
-
|
|
401
|
-
Avatar.defaultProps = {
|
|
402
|
-
quality: 'medium',
|
|
403
|
-
size: 'small',
|
|
404
|
-
shape: 'circle',
|
|
405
|
-
name: '',
|
|
406
|
-
};
|
|
407
|
-
|
|
408
|
-
export default Avatar;
|
package/Avatar.web.js
DELETED
|
@@ -1,405 +0,0 @@
|
|
|
1
|
-
/* eslint-disable indent */
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import React, {useState} from 'react';
|
|
4
|
-
import {Image, StyleSheet, TouchableOpacity, View} from 'react-native';
|
|
5
|
-
import Colors from '../../core-v2/colors';
|
|
6
|
-
import Text from '../../core-v2/components/typography';
|
|
7
|
-
import {RFValueHorizontal as ScaleSize} from '../../core-v2/components/typography/reponsiveSize';
|
|
8
|
-
import ValueUtil from '../../core/utils/ValueUtil';
|
|
9
|
-
import Radius from '../../core-v2/radius';
|
|
10
|
-
|
|
11
|
-
const AvatarQuality = {
|
|
12
|
-
low: 'low',
|
|
13
|
-
medium: 'medium',
|
|
14
|
-
high: 'high',
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const styles = StyleSheet.create({
|
|
18
|
-
container: {
|
|
19
|
-
justifyContent: 'center',
|
|
20
|
-
alignItems: 'center',
|
|
21
|
-
},
|
|
22
|
-
shortNameView: {
|
|
23
|
-
backgroundColor: Colors.pink_09,
|
|
24
|
-
justifyContent: 'center',
|
|
25
|
-
alignItems: 'center',
|
|
26
|
-
borderWidth: 1,
|
|
27
|
-
borderColor: Colors.black_04,
|
|
28
|
-
},
|
|
29
|
-
shortNameText: {
|
|
30
|
-
// fontSize: 17,
|
|
31
|
-
color: Colors.pink_03,
|
|
32
|
-
},
|
|
33
|
-
shortNameTextCustom: {
|
|
34
|
-
color: '#f6f6f6',
|
|
35
|
-
},
|
|
36
|
-
absolute: {
|
|
37
|
-
position: 'absolute',
|
|
38
|
-
top: 0,
|
|
39
|
-
left: 0,
|
|
40
|
-
right: 0,
|
|
41
|
-
bottom: 0,
|
|
42
|
-
},
|
|
43
|
-
subIcon: {
|
|
44
|
-
position: 'absolute',
|
|
45
|
-
bottom: 0,
|
|
46
|
-
right: 0,
|
|
47
|
-
},
|
|
48
|
-
topIcon: {
|
|
49
|
-
position: 'absolute',
|
|
50
|
-
top: 0,
|
|
51
|
-
right: 0,
|
|
52
|
-
},
|
|
53
|
-
subIconImage: {
|
|
54
|
-
width: 22,
|
|
55
|
-
height: 22,
|
|
56
|
-
},
|
|
57
|
-
subIconImageOnline: {
|
|
58
|
-
backgroundColor: Colors.kiwi_green,
|
|
59
|
-
borderColor: 'white',
|
|
60
|
-
borderWidth: 1,
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
const subIconSize = size => {
|
|
65
|
-
switch (size) {
|
|
66
|
-
case 'giant':
|
|
67
|
-
return {
|
|
68
|
-
width: 12,
|
|
69
|
-
height: 12,
|
|
70
|
-
borderRadius: 6,
|
|
71
|
-
};
|
|
72
|
-
case 'small':
|
|
73
|
-
return {
|
|
74
|
-
width: 8,
|
|
75
|
-
height: 8,
|
|
76
|
-
borderRadius: 4,
|
|
77
|
-
};
|
|
78
|
-
case 'medium':
|
|
79
|
-
return {
|
|
80
|
-
width: 12,
|
|
81
|
-
height: 12,
|
|
82
|
-
borderRadius: 6,
|
|
83
|
-
};
|
|
84
|
-
case 'large':
|
|
85
|
-
return {
|
|
86
|
-
width: 12,
|
|
87
|
-
height: 12,
|
|
88
|
-
borderRadius: 6,
|
|
89
|
-
};
|
|
90
|
-
default:
|
|
91
|
-
return {
|
|
92
|
-
width: 12,
|
|
93
|
-
height: 12,
|
|
94
|
-
borderRadius: 6,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
const avatarSize = size => {
|
|
100
|
-
switch (size) {
|
|
101
|
-
case 'tiny':
|
|
102
|
-
return {
|
|
103
|
-
width: 24,
|
|
104
|
-
height: 24,
|
|
105
|
-
};
|
|
106
|
-
case 'small': {
|
|
107
|
-
return {
|
|
108
|
-
width: 32,
|
|
109
|
-
height: 32,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
case 'medium':
|
|
113
|
-
return {
|
|
114
|
-
width: 40,
|
|
115
|
-
height: 40,
|
|
116
|
-
};
|
|
117
|
-
case 'large':
|
|
118
|
-
return {
|
|
119
|
-
width: 56,
|
|
120
|
-
height: 56,
|
|
121
|
-
};
|
|
122
|
-
case 'giant':
|
|
123
|
-
return {
|
|
124
|
-
width: 72,
|
|
125
|
-
height: 72,
|
|
126
|
-
};
|
|
127
|
-
default:
|
|
128
|
-
return {
|
|
129
|
-
width: 40,
|
|
130
|
-
height: 40,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
const shortName = size => {
|
|
136
|
-
switch (size) {
|
|
137
|
-
case 'tiny':
|
|
138
|
-
return {
|
|
139
|
-
fontSize: ScaleSize(10),
|
|
140
|
-
lineHeight: 16,
|
|
141
|
-
};
|
|
142
|
-
case 'small':
|
|
143
|
-
return {
|
|
144
|
-
fontSize: ScaleSize(15),
|
|
145
|
-
lineHeight: 22,
|
|
146
|
-
};
|
|
147
|
-
case 'medium':
|
|
148
|
-
return {
|
|
149
|
-
fontSize: ScaleSize(15),
|
|
150
|
-
lineHeight: 22,
|
|
151
|
-
};
|
|
152
|
-
case 'large':
|
|
153
|
-
return {
|
|
154
|
-
fontSize: ScaleSize(15),
|
|
155
|
-
lineHeight: 22,
|
|
156
|
-
};
|
|
157
|
-
case 'giant':
|
|
158
|
-
return {
|
|
159
|
-
fontSize: ScaleSize(15),
|
|
160
|
-
lineHeight: 22,
|
|
161
|
-
};
|
|
162
|
-
default:
|
|
163
|
-
return {
|
|
164
|
-
fontSize: ScaleSize(15),
|
|
165
|
-
lineHeight: 22,
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
const Avatar = ({
|
|
171
|
-
resizeMode,
|
|
172
|
-
cached,
|
|
173
|
-
quality,
|
|
174
|
-
size,
|
|
175
|
-
shape,
|
|
176
|
-
name,
|
|
177
|
-
source,
|
|
178
|
-
onPress,
|
|
179
|
-
style,
|
|
180
|
-
subIcon,
|
|
181
|
-
topIcon,
|
|
182
|
-
loading,
|
|
183
|
-
}) => {
|
|
184
|
-
const {width, height} = avatarSize(size);
|
|
185
|
-
const {fontSize, lineHeight} = shortName(size);
|
|
186
|
-
const {
|
|
187
|
-
width: iconWidth,
|
|
188
|
-
height: iconHeight,
|
|
189
|
-
borderRadius: iconRadius,
|
|
190
|
-
} = subIconSize(size);
|
|
191
|
-
|
|
192
|
-
const [imageSource, setImageSource] = useState(
|
|
193
|
-
ValueUtil.getImageSource(source),
|
|
194
|
-
);
|
|
195
|
-
const getContactShortName = name => {
|
|
196
|
-
if (!name) return '';
|
|
197
|
-
const shortNameList = name.split(' ', 2);
|
|
198
|
-
const alphabet = [];
|
|
199
|
-
shortNameList.forEach(n => {
|
|
200
|
-
if (n && n.length > 0) {
|
|
201
|
-
alphabet.push(n[0].toString().toUpperCase());
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
return alphabet.join('');
|
|
205
|
-
};
|
|
206
|
-
const isUrl = url => {
|
|
207
|
-
const expression =
|
|
208
|
-
/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/gi;
|
|
209
|
-
return expression.test(url);
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
const isValidImageUrl = source => {
|
|
213
|
-
return source && source.uri && isUrl(source.uri);
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
const mapAvatarQuality = (url, quality) => {
|
|
217
|
-
if (!quality || quality === AvatarQuality.medium) {
|
|
218
|
-
return url;
|
|
219
|
-
}
|
|
220
|
-
if (quality === AvatarQuality.low) {
|
|
221
|
-
return url.replace('.png', '_s64.png');
|
|
222
|
-
}
|
|
223
|
-
if (quality === AvatarQuality.high) {
|
|
224
|
-
return url.replace('.png', '_s512.png');
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return url;
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
const onLoadSourceError = source => {
|
|
231
|
-
setImageSource(source);
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
const renderSubIcon = () => {
|
|
235
|
-
// const subIconSizeStyle = this.mapSubIconSize(size);
|
|
236
|
-
if (subIcon && shape === 'circle' && size !== 'tiny') {
|
|
237
|
-
return (
|
|
238
|
-
<View
|
|
239
|
-
style={[
|
|
240
|
-
styles.subIcon,
|
|
241
|
-
size === 'large' && {
|
|
242
|
-
bottom: 2,
|
|
243
|
-
right: 2,
|
|
244
|
-
},
|
|
245
|
-
size === 'giant' && {
|
|
246
|
-
bottom: 4,
|
|
247
|
-
right: 4,
|
|
248
|
-
},
|
|
249
|
-
]}>
|
|
250
|
-
{typeof subIcon === 'string' ? (
|
|
251
|
-
<Image
|
|
252
|
-
source={subIcon}
|
|
253
|
-
style={[
|
|
254
|
-
{
|
|
255
|
-
width: iconWidth,
|
|
256
|
-
height: iconHeight,
|
|
257
|
-
borderRadius: iconRadius,
|
|
258
|
-
},
|
|
259
|
-
]}
|
|
260
|
-
/>
|
|
261
|
-
) : (
|
|
262
|
-
subIcon()
|
|
263
|
-
)}
|
|
264
|
-
</View>
|
|
265
|
-
);
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
const renderTopIcon = () => {
|
|
270
|
-
if (topIcon && shape === 'circle' && size !== 'tiny') {
|
|
271
|
-
return (
|
|
272
|
-
<View
|
|
273
|
-
style={[
|
|
274
|
-
styles.topIcon,
|
|
275
|
-
size === 'large' && {
|
|
276
|
-
top: 2,
|
|
277
|
-
right: 2,
|
|
278
|
-
},
|
|
279
|
-
size === 'giant' && {
|
|
280
|
-
top: 4,
|
|
281
|
-
right: 4,
|
|
282
|
-
},
|
|
283
|
-
]}>
|
|
284
|
-
<Image
|
|
285
|
-
source={topIcon}
|
|
286
|
-
style={[
|
|
287
|
-
{
|
|
288
|
-
width: iconWidth,
|
|
289
|
-
height: iconHeight,
|
|
290
|
-
borderRadius: iconRadius,
|
|
291
|
-
},
|
|
292
|
-
]}
|
|
293
|
-
/>
|
|
294
|
-
</View>
|
|
295
|
-
);
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
const onPressIcon = () => {
|
|
300
|
-
if (onPress && typeof onPress === 'function') onPress();
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
const renderShortName = () => {
|
|
304
|
-
if (name) {
|
|
305
|
-
const shortedName = getContactShortName(name);
|
|
306
|
-
// const shortNameStyle = mapShortNameStyle(size);
|
|
307
|
-
return (
|
|
308
|
-
<View
|
|
309
|
-
style={[
|
|
310
|
-
{
|
|
311
|
-
width,
|
|
312
|
-
height,
|
|
313
|
-
borderRadius: shape === 'circle' ? width / 2 : Radius.XS,
|
|
314
|
-
},
|
|
315
|
-
styles.shortNameView,
|
|
316
|
-
]}>
|
|
317
|
-
<Text
|
|
318
|
-
weight="regular"
|
|
319
|
-
style={{
|
|
320
|
-
fontSize,
|
|
321
|
-
lineHeight,
|
|
322
|
-
color: Colors.pink_03,
|
|
323
|
-
}}>
|
|
324
|
-
{shortedName}
|
|
325
|
-
</Text>
|
|
326
|
-
</View>
|
|
327
|
-
);
|
|
328
|
-
}
|
|
329
|
-
return <View />;
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
if (imageSource?.uri) {
|
|
333
|
-
imageSource.priority = 'high';
|
|
334
|
-
imageSource.uri = mapAvatarQuality(imageSource.uri, quality);
|
|
335
|
-
// if doest not have time query, set default cache time to 1 day
|
|
336
|
-
if (!imageSource.uri?.includes('?') && cached) {
|
|
337
|
-
const midnight = new Date().setHours(0, 0, 0, 0);
|
|
338
|
-
imageSource.uri = `${imageSource.uri}?time=${midnight}`;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
const renderImage = () => {
|
|
343
|
-
return (
|
|
344
|
-
<Image
|
|
345
|
-
cached={cached}
|
|
346
|
-
resizeMode={resizeMode}
|
|
347
|
-
onLoadSourceError={() => onLoadSourceError(source)}
|
|
348
|
-
source={source}
|
|
349
|
-
loading={loading}
|
|
350
|
-
style={[
|
|
351
|
-
{
|
|
352
|
-
width,
|
|
353
|
-
height,
|
|
354
|
-
borderRadius: shape === 'circle' ? width / 2 : Radius.XS,
|
|
355
|
-
},
|
|
356
|
-
]}
|
|
357
|
-
/>
|
|
358
|
-
);
|
|
359
|
-
};
|
|
360
|
-
|
|
361
|
-
return (
|
|
362
|
-
<TouchableOpacity
|
|
363
|
-
activeOpacity={onPress ? 0.5 : 1}
|
|
364
|
-
style={style}
|
|
365
|
-
onPress={onPressIcon}>
|
|
366
|
-
<View
|
|
367
|
-
style={{
|
|
368
|
-
alignSelf: 'baseline',
|
|
369
|
-
}}>
|
|
370
|
-
{!!imageSource && isValidImageUrl(imageSource)
|
|
371
|
-
? renderImage()
|
|
372
|
-
: renderShortName()}
|
|
373
|
-
{renderTopIcon()}
|
|
374
|
-
{renderSubIcon()}
|
|
375
|
-
</View>
|
|
376
|
-
</TouchableOpacity>
|
|
377
|
-
);
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
Avatar.propTypes = {
|
|
381
|
-
name: PropTypes.string,
|
|
382
|
-
quality: PropTypes.oneOf(['low', 'medium', 'high']),
|
|
383
|
-
size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large', 'giant']),
|
|
384
|
-
source: PropTypes.oneOfType([
|
|
385
|
-
PropTypes.shape({uri: PropTypes.string}),
|
|
386
|
-
PropTypes.number,
|
|
387
|
-
PropTypes.string,
|
|
388
|
-
]),
|
|
389
|
-
subIcon: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
|
390
|
-
topIcon: PropTypes.string,
|
|
391
|
-
|
|
392
|
-
style: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
|
393
|
-
onPress: PropTypes.func,
|
|
394
|
-
loading: PropTypes.bool,
|
|
395
|
-
shape: PropTypes.oneOf(['circle', 'square']),
|
|
396
|
-
};
|
|
397
|
-
|
|
398
|
-
Avatar.defaultProps = {
|
|
399
|
-
quality: 'medium',
|
|
400
|
-
size: 'small',
|
|
401
|
-
shape: 'circle',
|
|
402
|
-
name: '',
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
export default Avatar;
|
package/index.js
DELETED