@momo-kits/avatar 0.0.48-rc.4 → 0.0.48

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/Avatar.js DELETED
@@ -1,699 +0,0 @@
1
- /* eslint-disable indent */
2
- import PropTypes from 'prop-types';
3
- import React, { Component } from 'react';
4
- import {
5
- View,
6
- StyleSheet,
7
- TouchableOpacity,
8
- Dimensions,
9
- Platform,
10
- } from 'react-native';
11
- import { get, isEqual } from 'lodash';
12
- import {
13
- ValueUtil,
14
- Colors,
15
- Text,
16
- IconSource,
17
- Image,
18
- ScaleSize,
19
- } from '@momo-kits/core';
20
-
21
- export const AvatarQuality = {
22
- low: 'low',
23
- medium: 'medium',
24
- high: 'high',
25
- };
26
-
27
- export const AvatarSize = {
28
- tiny: 'tiny',
29
- small: 'small',
30
- medium: 'medium',
31
- large: 'large',
32
- giant: 'giant',
33
- size8: 'size8',
34
- size24: 'size24',
35
- size36: 'size36',
36
- size44: 'size44',
37
- size48: 'size48',
38
- size52: 'size52',
39
- size56: 'size56',
40
- size64: 'size64',
41
- size72: 'size72',
42
- size80: 'size80',
43
- size88: 'size88',
44
- size96: 'size96',
45
- };
46
-
47
- const COLORS = [
48
- '#3683f3',
49
- '#ea63af',
50
- '#f94889',
51
- '#82b6da',
52
- '#2fc093',
53
- '#7b4a41',
54
- '#ff97bc',
55
- '#4130d7',
56
- '#c3c3c3',
57
- '#f7ae2f',
58
- '#b04595',
59
- '#57b748',
60
- '#ff8900',
61
- '#7841bf',
62
- '#be3f3e',
63
- '#c51515',
64
- '#8e6472',
65
- '#fed27d',
66
- '#ff6f5d',
67
- '#05b8ae',
68
- ];
69
-
70
- export const SubIconType = {
71
- momo: 'momo',
72
- online: 'online',
73
- key: 'key',
74
- none: 'none',
75
- };
76
-
77
- const styles = StyleSheet.create({
78
- container: {
79
- justifyContent: 'center',
80
- alignItems: 'center',
81
- },
82
- shortNameView: {
83
- justifyContent: 'center',
84
- alignItems: 'center',
85
-
86
- backgroundColor: Colors.very_light_pink_four,
87
- width: '100%',
88
- height: '100%',
89
- },
90
- shortNameText: {
91
- // fontSize: 17,
92
- color: Colors.pink_05_b,
93
- },
94
- shortNameTextCustom: {
95
- color: '#f6f6f6',
96
- },
97
- absolute: {
98
- position: 'absolute',
99
- top: 0,
100
- left: 0,
101
- right: 0,
102
- bottom: 0,
103
- },
104
- subIcon: {
105
- position: 'absolute',
106
- bottom: 0,
107
- right: 0,
108
- },
109
- subIconImage: {
110
- width: 22,
111
- height: 22,
112
- },
113
- subIconImageOnline: {
114
- backgroundColor: Colors.kiwi_green,
115
- borderColor: 'white',
116
- borderWidth: 1,
117
- },
118
- });
119
-
120
- const subIconSize = (width) => ({
121
- tiny: {
122
- width: 8,
123
- height: 8,
124
- borderRadius: 4,
125
- },
126
- small: {
127
- width: 10,
128
- height: 10,
129
- borderRadius: 5,
130
- },
131
- medium: {
132
- width: 12,
133
- height: 12,
134
- borderRadius: 6,
135
- },
136
- large: {
137
- width: 16,
138
- height: 16,
139
- borderRadius: 8,
140
- },
141
- size8: {
142
- width: 8,
143
- height: 8,
144
- borderRadius: 4,
145
- },
146
- size24: {
147
- width: 10,
148
- height: 10,
149
- borderRadius: 5,
150
- },
151
- size36: {
152
- width: 10,
153
- height: 10,
154
- borderRadius: 5,
155
- },
156
- size44: {
157
- width: 14,
158
- height: 14,
159
- borderRadius: 7,
160
- },
161
- size48: {
162
- width: 14,
163
- height: 14,
164
- borderRadius: 7,
165
- },
166
- size52: {
167
- width: 16,
168
- height: 16,
169
- borderRadius: 8,
170
- },
171
- size56: {
172
- width: 16,
173
- height: 16,
174
- borderRadius: 8,
175
- },
176
- size64: {
177
- width: 16,
178
- height: 16,
179
- borderRadius: 8,
180
- top: -2,
181
- left: -2,
182
- },
183
- size72: {
184
- width: 18,
185
- height: 18,
186
- borderRadius: 9,
187
- top: -3,
188
- left: -3,
189
- },
190
- size80: {
191
- width: 18,
192
- height: 18,
193
- borderRadius: 9,
194
- top: -3,
195
- left: -3,
196
- },
197
- size88: {
198
- width: 18,
199
- height: 18,
200
- borderRadius: 9,
201
- top: -4,
202
- left: -4,
203
- },
204
- size96: {
205
- width: 20,
206
- height: 20,
207
- borderRadius: 10,
208
- top: -4,
209
- left: -4,
210
- },
211
- giant: {
212
- top: -5,
213
- left: -5,
214
- width: 24,
215
- height: 24,
216
- borderRadius: 12,
217
- },
218
- });
219
-
220
- const avatarSize = (width) => ({
221
- tiny: {
222
- width: 16,
223
- height: 16,
224
- borderRadius: 8,
225
- },
226
- small: {
227
- width: 32,
228
- height: 32,
229
- borderRadius: 16,
230
- },
231
- medium: {
232
- width: 40,
233
- height: 40,
234
- borderRadius: 20,
235
- },
236
- large: {
237
- width: 60,
238
- height: 60,
239
- borderRadius: 30,
240
- },
241
- giant: {
242
- width: 120,
243
- height: 120,
244
- borderRadius: 60,
245
- },
246
- size8: {
247
- width: 8,
248
- height: 8,
249
- borderRadius: 4,
250
- },
251
- size24: {
252
- width: 24,
253
- height: 24,
254
- borderRadius: 12,
255
- },
256
- size36: {
257
- width: 36,
258
- height: 36,
259
- borderRadius: 18,
260
- },
261
- size44: {
262
- width: 44,
263
- height: 44,
264
- borderRadius: 22,
265
- },
266
- size48: {
267
- width: 48,
268
- height: 48,
269
- borderRadius: 24,
270
- },
271
- size52: {
272
- width: 52,
273
- height: 52,
274
- borderRadius: 26,
275
- },
276
- size56: {
277
- width: 56,
278
- height: 56,
279
- borderRadius: 28,
280
- },
281
- size64: {
282
- width: 64,
283
- height: 64,
284
- borderRadius: 32,
285
- },
286
- size72: {
287
- width: 72,
288
- height: 72,
289
- borderRadius: 36,
290
- },
291
- size80: {
292
- width: 80,
293
- height: 80,
294
- borderRadius: 40,
295
- },
296
- size88: {
297
- width: 88,
298
- height: 88,
299
- borderRadius: 44,
300
- },
301
- size96: {
302
- width: 96,
303
- height: 96,
304
- borderRadius: 48,
305
- },
306
- });
307
-
308
- const shortName = (width) => ({
309
- tiny: {
310
- fontSize: ScaleSize(5, width),
311
- },
312
- small: {
313
- fontSize: ScaleSize(11, width),
314
- },
315
- medium: {
316
- fontSize: ScaleSize(15, width),
317
- },
318
- middle: {
319
- fontSize: ScaleSize(16, width),
320
- },
321
- large: {
322
- fontSize: ScaleSize(20, width),
323
- },
324
- giant: {
325
- fontSize: ScaleSize(25, width),
326
- },
327
- });
328
-
329
- export default class Avatar extends Component {
330
- constructor(props) {
331
- super(props);
332
- this.color = props.custom
333
- ? this.getAvatarColor(props.name)
334
- : Colors.pink_10;
335
- this.state = {
336
- hideSource: false,
337
- ownUpdate: false,
338
- source: props.source,
339
- dimensions: {},
340
- };
341
- this.imageSource = '';
342
- }
343
-
344
- componentDidMount() {
345
- const { scaleSize } = this.props;
346
- if (scaleSize) {
347
- this.subscription = Dimensions.addEventListener(
348
- 'change',
349
- ({ window }) => {
350
- if (
351
- window?.height > 0 &&
352
- window?.width > 0 &&
353
- Platform.OS === 'android'
354
- ) {
355
- this.setState({ dimensions: window });
356
- }
357
- },
358
- );
359
- }
360
- }
361
-
362
- componentWillUnmount() {
363
- const { scaleSize } = this.props;
364
- if (scaleSize) {
365
- this.subscription?.remove?.();
366
- }
367
- }
368
-
369
- static getDerivedStateFromProps(nextProps, prevState) {
370
- if (prevState.ownUpdate) {
371
- return {
372
- ownUpdate: false,
373
- };
374
- }
375
- if (!isEqual(nextProps.source, prevState.source)) {
376
- return { source: nextProps.source, hideSource: false };
377
- }
378
- return null;
379
- }
380
-
381
- getContactShortName = (name) => {
382
- if (!name) return '';
383
- const shortNameList = name.split(' ', 2);
384
- const alphabet = [];
385
- shortNameList.forEach((n) => {
386
- if (n && n.length > 0) {
387
- alphabet.push(n[0].toString().toUpperCase());
388
- }
389
- });
390
- return alphabet.join('');
391
- };
392
-
393
- hashUrl(url) {
394
- let hash = 0;
395
- let char;
396
- if (url?.length === 0) return hash;
397
- for (let i = 0; i < url?.length; i++) {
398
- char = url?.charCodeAt(i);
399
- hash = (hash << 5) - hash + char;
400
- hash &= hash; // Convert to 32bit integer
401
- }
402
- return hash;
403
- }
404
-
405
- renderShortName = (name, avatarStyle, size, color) => {
406
- if (name) {
407
- const shortedName = this.getContactShortName(name);
408
- const shortNameStyle = this.mapShortNameStyle(size);
409
- return (
410
- <View
411
- style={[
412
- styles.shortNameView,
413
- avatarStyle,
414
- { backgroundColor: color },
415
- ]}>
416
- <Text.H4
417
- style={[
418
- this.props.custom
419
- ? styles.shortNameTextCustom
420
- : styles.shortNameText,
421
- shortNameStyle,
422
- ]}>
423
- {shortedName}
424
- </Text.H4>
425
- </View>
426
- );
427
- }
428
- return <View />;
429
- };
430
-
431
- isUrl(url) {
432
- const expression =
433
- /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/gi;
434
- return expression.test(url);
435
- }
436
-
437
- isValidImageUrl = (source) => {
438
- const validSource = source && source.uri && this.isUrl(source.uri);
439
- return validSource;
440
- };
441
-
442
- mapAvatarQuality = (url, quality) => {
443
- if (!quality || quality === AvatarQuality.medium) {
444
- return url;
445
- }
446
- if (quality === AvatarQuality.low) {
447
- return url.replace('.png', '_s64.png');
448
- }
449
- if (quality === AvatarQuality.high) {
450
- return url.replace('.png', '_s512.png');
451
- }
452
-
453
- return url;
454
- };
455
-
456
- mapStyleFromSize = (size) => {
457
- const { dimensions } = this.state;
458
- const avatarStyle = avatarSize(
459
- dimensions?.width > 0 ? dimensions?.width : null,
460
- ).small;
461
- if (typeof size === 'object') return size;
462
- if (avatarSize(dimensions?.width > 0 ? dimensions?.width : null)[size])
463
- return avatarSize(dimensions?.width > 0 ? dimensions?.width : null)[
464
- size
465
- ];
466
- return avatarStyle;
467
- };
468
-
469
- mapShortNameStyle = (size) => {
470
- let shortNameStyle = {};
471
- const { dimensions } = this.state;
472
- switch (size) {
473
- case AvatarSize.tiny: {
474
- shortNameStyle = shortName(
475
- dimensions?.width > 0 ? dimensions?.width : null,
476
- ).tiny;
477
- break;
478
- }
479
- case AvatarSize.small: {
480
- shortNameStyle = shortName(
481
- dimensions?.width > 0 ? dimensions?.width : null,
482
- ).small;
483
- break;
484
- }
485
- case AvatarSize.medium: {
486
- shortNameStyle = shortName(
487
- dimensions?.width > 0 ? dimensions?.width : null,
488
- ).medium;
489
- break;
490
- }
491
- case AvatarSize.size48: {
492
- shortNameStyle = shortName(dimensions?.width || null).middle;
493
- break;
494
- }
495
- case AvatarSize.large: {
496
- shortNameStyle = shortName(
497
- dimensions?.width > 0 ? dimensions?.width : null,
498
- ).large;
499
- break;
500
- }
501
- case AvatarSize.giant: {
502
- shortNameStyle = shortName(
503
- dimensions?.width > 0 ? dimensions?.width : null,
504
- ).giant;
505
- break;
506
- }
507
- default:
508
- shortNameStyle = shortName(
509
- dimensions?.width > 0 ? dimensions?.width : null,
510
- ).small;
511
- }
512
- return shortNameStyle;
513
- };
514
-
515
- mapSubIconSize = (size) => {
516
- const { dimensions } = this.state;
517
- const subIconStyle = subIconSize(
518
- dimensions?.width > 0 ? dimensions?.width : null,
519
- ).small;
520
- if (subIconSize(dimensions?.width > 0 ? dimensions?.width : null)[size])
521
- return subIconSize(
522
- dimensions?.width > 0 ? dimensions?.width : null,
523
- )[size];
524
- return subIconStyle;
525
- };
526
-
527
- extractSize = (avatarStyle) => {
528
- const { style } = this.props;
529
- const borderWidth = get(style, 'borderWidth', 1);
530
- const containerWidth = Math.round(avatarStyle.width + 2 + borderWidth);
531
- return {
532
- width: containerWidth,
533
- height: containerWidth,
534
- borderRadius: containerWidth / 2,
535
- borderWidth,
536
- borderColor: Colors.black_01,
537
- };
538
- };
539
-
540
- onLoadSourceError = (imageSource) => {
541
- if (this.imageSource?.uri !== imageSource?.uri) {
542
- this.imageSource = imageSource;
543
- this.setState({ hideSource: true, ownUpdate: true });
544
- }
545
- };
546
-
547
- renderSubIcon = () => {
548
- const { subIcon, size, subIconSource } = this.props;
549
- if ((!subIcon || subIcon === SubIconType.none) && !subIconSource)
550
- return <View />;
551
- const subIconSizeStyle = this.mapSubIconSize(size);
552
- const iconSource = ValueUtil.getImageSource(subIconSource);
553
- return (
554
- <View style={styles.subIcon}>
555
- {subIcon === SubIconType.momo ? (
556
- <Image
557
- style={[styles.subIconImage, subIconSizeStyle]}
558
- source={IconSource.ic_round_momo_tiny}
559
- />
560
- ) : (
561
- <View />
562
- )}
563
- {subIcon === SubIconType.online ? (
564
- <View
565
- style={[styles.subIconImageOnline, subIconSizeStyle]}
566
- />
567
- ) : (
568
- <View />
569
- )}
570
-
571
- {iconSource && subIconSource && !subIcon ? (
572
- <Image
573
- style={[styles.subIconImage, subIconSizeStyle]}
574
- source={iconSource}
575
- />
576
- ) : (
577
- <View />
578
- )}
579
- </View>
580
- );
581
- };
582
-
583
- getAvatarColor(name) {
584
- const shortName = this.getContactShortName(name);
585
- if (!shortName) return '#d5d6d6';
586
- const firstLetter = shortName[0].charCodeAt(0);
587
- let colorIndex = Number(firstLetter) % 26;
588
- if (colorIndex > 19) colorIndex = 25 - colorIndex;
589
- return COLORS[colorIndex];
590
- }
591
-
592
- onPress = () => {
593
- const { onPress } = this.props;
594
- if (onPress && typeof onPress === 'function') onPress();
595
- };
596
-
597
- render() {
598
- const {
599
- size,
600
- source,
601
- name,
602
- resizeMode,
603
- style,
604
- onPress,
605
- isShowLoading,
606
- loading,
607
- cached,
608
- extraPropsImage,
609
- quality,
610
- } = this.props;
611
- const { hideSource } = this.state;
612
- const avatarStyle = this.mapStyleFromSize(size);
613
- const containerSize = this.extractSize(avatarStyle);
614
- const imageSource = ValueUtil.getImageSource(source);
615
- const showName =
616
- typeof imageSource === 'object' &&
617
- Object.keys(imageSource).length === 0 &&
618
- typeof imageSource !== 'number';
619
- // add priority high for avatar
620
- if (imageSource?.uri) {
621
- imageSource.priority = 'high';
622
- imageSource.uri = this.mapAvatarQuality(imageSource.uri, quality);
623
- // if doest not have time query, set default cache time to 1 day
624
- if (!imageSource.uri?.includes('?') && cached) {
625
- const midnight = new Date().setHours(0, 0, 0, 0);
626
- imageSource.uri = `${imageSource.uri}?time=${midnight}`;
627
- }
628
- }
629
-
630
- const inner = (
631
- <View style={[styles.container, containerSize, style]}>
632
- {showName || hideSource ? (
633
- this.renderShortName(name, avatarStyle, size, this.color)
634
- ) : (
635
- <View />
636
- )}
637
- {this.isValidImageUrl(imageSource) && !hideSource ? (
638
- <Image
639
- cached={cached}
640
- loading={loading || isShowLoading}
641
- source={imageSource}
642
- onError={() => this.onLoadSourceError(imageSource)}
643
- style={avatarStyle}
644
- resizeMode={resizeMode}
645
- {...extraPropsImage}
646
- />
647
- ) : (
648
- <View />
649
- )}
650
- {this.renderSubIcon()}
651
- </View>
652
- );
653
- if (onPress) {
654
- return (
655
- <TouchableOpacity
656
- activeOpacity={onPress ? 0.5 : 1}
657
- onPress={this.onPress}>
658
- {inner}
659
- </TouchableOpacity>
660
- );
661
- }
662
- return inner;
663
- }
664
- }
665
-
666
- Avatar.propTypes = {
667
- name: PropTypes.string,
668
- resizeMode: PropTypes.string,
669
- quality: PropTypes.oneOf(['low', 'medium', 'high']),
670
- size: PropTypes.any,
671
- source: PropTypes.oneOfType([
672
- PropTypes.shape({ uri: PropTypes.string }),
673
- PropTypes.number,
674
- PropTypes.string,
675
- ]),
676
- subIcon: PropTypes.oneOf(['momo', 'online', 'key', 'none']),
677
- subIconSource: PropTypes.oneOfType([
678
- PropTypes.shape({ uri: PropTypes.string }),
679
- PropTypes.number,
680
- PropTypes.string,
681
- ]),
682
- style: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
683
- onPress: PropTypes.func,
684
- loading: PropTypes.bool,
685
- cached: PropTypes.bool,
686
- scaleSize: PropTypes.bool,
687
- extraPropsImage: PropTypes.object,
688
- number: PropTypes.string,
689
- custom: PropTypes.bool,
690
- };
691
-
692
- Avatar.defaultProps = {
693
- resizeMode: 'cover',
694
- cached: true,
695
- scaleSize: false,
696
- quality: 'medium',
697
- size: 'small',
698
- custom: false,
699
- };