react-native-vector-icons
Version:
Customizable Icons for React Native with support for NavBar/TabBar/ToolbarAndroid, image source and full styling.
236 lines (196 loc) • 5.99 kB
JavaScript
import React, { PureComponent } from 'react';
import { PixelRatio, Platform, processColor } from 'react-native';
import PropTypes from 'prop-types';
import createIconSet, {
DEFAULT_ICON_COLOR,
DEFAULT_ICON_SIZE,
NativeIconAPI,
} from './create-icon-set';
import ensureNativeModuleAvailable from './ensure-native-module-available';
export const FA5Style = {
regular: 0,
light: 1,
solid: 2,
brand: 3,
};
export function createFA5iconSet(glyphMap, metadata = {}, proVersion = false) {
const familyName = `Font Awesome 5 ${proVersion ? 'Pro' : 'Free'}`;
const metadataKeys = Object.keys(metadata);
function createFA5iconSubset(type, weight = '400', family = familyName) {
const fontFileID = proVersion ? `Pro_${type}` : type;
return createIconSet(glyphMap, family, `FontAwesome5_${fontFileID}.ttf`, {
fontWeight: Platform.OS === 'ios' ? weight : undefined,
});
}
const RegularSet = createFA5iconSubset('Regular');
const SolidSet = createFA5iconSubset('Solid', '700');
const LightSet = proVersion
? createFA5iconSubset('Light', '100')
: RegularSet;
const BrandsSet = createFA5iconSubset(
'Brands',
'400',
'Font Awesome 5 Brands'
);
function iconSetFromStyle(style) {
switch (style) {
case FA5Style.brand:
return BrandsSet;
case FA5Style.light:
return LightSet;
case FA5Style.solid:
return SolidSet;
default:
return RegularSet;
}
}
function iconSetFromFamily(family) {
switch (family) {
case 'brands':
return BrandsSet;
case 'regular':
return LightSet;
case 'solid':
return SolidSet;
default:
return RegularSet;
}
}
function styleFromProps(props) {
const { light, solid } = props;
if (light) return FA5Style.light;
if (solid) return FA5Style.solid;
return FA5Style.regular;
}
function styleToFamily(style) {
switch (style) {
case FA5Style.brand:
return 'brands';
case FA5Style.light:
return 'light';
case FA5Style.solid:
return 'solid';
default:
return 'regular';
}
}
function familyToStyle(family) {
switch (family) {
case 'brands':
return FA5Style.brand;
case 'light':
return FA5Style.light;
case 'solid':
return FA5Style.solid;
default:
return FA5Style.regular;
}
}
function fallbackForGlyph(glyph) {
for (let i = 0; i < metadataKeys.length; i += 1) {
const family = metadataKeys[i];
if (metadata[family].indexOf(glyph) !== -1) return family;
}
return 'regular';
}
function hasIconForStyle(glyph, style) {
const family = styleToFamily(style);
if (metadataKeys.indexOf(family) === -1) return false;
return metadata[family].indexOf(glyph) !== -1;
}
function getIconSetForProps(props) {
const { name } = props;
const style = styleFromProps(props);
if (hasIconForStyle(name, style)) return iconSetFromStyle(style);
const fallbackFamily = fallbackForGlyph(name);
return iconSetFromFamily(fallbackFamily);
}
function createFA5iconClass(baseClass, selectClass = iconSet => iconSet) {
class FA5iconClass extends PureComponent {
static propTypes = {
light: PropTypes.bool,
solid: PropTypes.bool,
};
static defaultProps = {
light: false,
solid: false,
};
render() {
const selectedIconSet = getIconSetForProps(this.props);
const SelectedIconClass = selectClass(selectedIconSet);
const { light, solid, ...restProps } = this.props;
return <SelectedIconClass {...restProps} />;
}
}
return FA5iconClass;
}
const Base = RegularSet;
const FA5icon = createFA5iconClass(Base);
FA5icon.Button = createFA5iconClass(Base.Button, iconSet => iconSet.Button);
FA5icon.TabBarItem = createFA5iconClass(
Base.TabBarItem,
iconSet => iconSet.TabBarItem
);
FA5icon.TabBarItemIOS = createFA5iconClass(
Base.TabBarItemIOS,
iconSet => iconSet.TabBarItemIOS
);
FA5icon.ToolbarAndroid = createFA5iconClass(
Base.ToolbarAndroid,
iconSet => iconSet.ToolbarAndroid
);
const imageSourceCache = {};
function getImageSource(
name,
size = DEFAULT_ICON_SIZE,
color = DEFAULT_ICON_COLOR,
type = FA5Style.regular
) {
ensureNativeModuleAvailable();
let style = type;
if (!hasIconForStyle(name, style)) {
const fallbackFamily = fallbackForGlyph(name);
style = familyToStyle(fallbackFamily);
}
if (Platform.OS === 'ios' && style !== FA5Style.brand) {
let glyph = glyphMap[name] || '?';
if (typeof glyph === 'number') {
glyph = String.fromCharCode(glyph);
}
const processedColor = processColor(color);
const cacheKey = `${glyph}:${size}:${processedColor}:${type}`;
const scale = PixelRatio.get();
return new Promise((resolve, reject) => {
const cached = imageSourceCache[cacheKey];
if (typeof cached !== 'undefined') {
if (!cached || cached instanceof Error) {
reject(cached);
} else {
resolve({ uri: cached, scale });
}
} else {
NativeIconAPI.getImageForFontAwesome5(
familyName,
glyph,
size,
style,
processedColor,
(err, image) => {
const error = typeof err === 'string' ? new Error(err) : err;
imageSourceCache[cacheKey] = image || error || false;
if (!error && image) {
resolve({ uri: image, scale });
} else {
reject(error);
}
}
);
}
});
}
const iconSet = iconSetFromStyle(style);
return iconSet.getImageSource(name, size, color);
}
FA5icon.getImageSource = getImageSource;
return FA5icon;
}