1 | import * as React from 'react';
|
2 | import {
|
3 | Image,
|
4 | I18nManager,
|
5 | Platform,
|
6 | ImageSourcePropType,
|
7 | } from 'react-native';
|
8 | import { Consumer as SettingsConsumer } from '../core/settings';
|
9 | import { accessibilityProps } from './MaterialCommunityIcon';
|
10 | import { withTheme } from '../core/theming';
|
11 |
|
12 | type IconSourceBase = string | ImageSourcePropType;
|
13 |
|
14 | export type IconSource =
|
15 | | IconSourceBase
|
16 | | Readonly<{ source: IconSourceBase; direction: 'rtl' | 'ltr' | 'auto' }>
|
17 | | ((props: IconProps & { color: string }) => React.ReactNode);
|
18 |
|
19 | type IconProps = {
|
20 | size: number;
|
21 | allowFontScaling?: boolean;
|
22 | };
|
23 |
|
24 | type Props = IconProps & {
|
25 | color?: string;
|
26 | source: any;
|
27 | /**
|
28 | * @optional
|
29 | */
|
30 | theme: ReactNativePaper.Theme;
|
31 | };
|
32 |
|
33 | const isImageSource = (source: any) =>
|
34 |
|
35 | (typeof source === 'object' &&
|
36 | source !== null &&
|
37 | Object.prototype.hasOwnProperty.call(source, 'uri') &&
|
38 | typeof source.uri === 'string') ||
|
39 |
|
40 | typeof source === 'number' ||
|
41 |
|
42 | (Platform.OS === 'web' &&
|
43 | typeof source === 'string' &&
|
44 | (source.startsWith('data:image') ||
|
45 | /\.(bmp|jpg|jpeg|png|gif|svg)$/.test(source)));
|
46 |
|
47 | const getIconId = (source: any) => {
|
48 | if (
|
49 | typeof source === 'object' &&
|
50 | source !== null &&
|
51 | Object.prototype.hasOwnProperty.call(source, 'uri') &&
|
52 | typeof source.uri === 'string'
|
53 | ) {
|
54 | return source.uri;
|
55 | }
|
56 |
|
57 | return source;
|
58 | };
|
59 |
|
60 | export const isValidIcon = (source: any) =>
|
61 | typeof source === 'string' ||
|
62 | typeof source === 'function' ||
|
63 | isImageSource(source);
|
64 |
|
65 | export const isEqualIcon = (a: any, b: any) =>
|
66 | a === b || getIconId(a) === getIconId(b);
|
67 |
|
68 | const Icon = ({ source, color, size, theme, ...rest }: Props) => {
|
69 | const direction =
|
70 | typeof source === 'object' && source.direction && source.source
|
71 | ? source.direction === 'auto'
|
72 | ? I18nManager.isRTL
|
73 | ? 'rtl'
|
74 | : 'ltr'
|
75 | : source.direction
|
76 | : null;
|
77 | const s =
|
78 | typeof source === 'object' && source.direction && source.source
|
79 | ? source.source
|
80 | : source;
|
81 | const iconColor = color || theme.colors.text;
|
82 |
|
83 | if (isImageSource(s)) {
|
84 | return (
|
85 | <Image
|
86 | {...rest}
|
87 | source={s}
|
88 | style={[
|
89 | {
|
90 | transform: [{ scaleX: direction === 'rtl' ? -1 : 1 }],
|
91 | },
|
92 |
|
93 | {
|
94 | width: size,
|
95 | height: size,
|
96 | tintColor: color,
|
97 | resizeMode: 'contain',
|
98 | },
|
99 | ]}
|
100 | {...accessibilityProps}
|
101 | />
|
102 | );
|
103 | } else if (typeof s === 'string') {
|
104 | return (
|
105 | <SettingsConsumer>
|
106 | {({ icon }) => {
|
107 | return icon({
|
108 | name: s,
|
109 | color: iconColor,
|
110 | size,
|
111 | direction,
|
112 | });
|
113 | }}
|
114 | </SettingsConsumer>
|
115 | );
|
116 | } else if (typeof s === 'function') {
|
117 | return s({ color: iconColor, size, direction });
|
118 | }
|
119 |
|
120 | return null;
|
121 | };
|
122 |
|
123 | export default withTheme(Icon);
|