@vnaidin/react-native-cryptocurrency-icons
Version:
React Native cryptocurrency icons as PNG components
59 lines (58 loc) • 2.81 kB
JavaScript
/**
* Web entry point for @vnaidin/react-native-cryptocurrency-icons.
*
* This file is intentionally separate from the React Native entry (index.tsx)
* and has NO dependency on react-native. It exports:
* - `getCryptoIconUrl(symbol)` — returns a URL string suitable for <img src>
* - `CryptoIcon` — a lightweight React web component (<img> with fallback avatar)
*
* For bundlers that support `new URL(..., import.meta.url)` (Vite, webpack 5+),
* the PNG is resolved at build time and hashed into the output.
*
* The RN entry point (index.tsx / dist/index.js) is unaffected by this file.
*/
import React, { useState } from "react";
import { webIconsList } from "./webIconsList";
/**
* Returns a resolved URL string for the icon PNG, or `null` if the symbol
* is not in the known icon set. Works with Vite / webpack 5+ via
* `new URL(..., import.meta.url)`.
*/
export function getCryptoIconUrl(symbol) {
const key = symbol.toLowerCase();
if (!webIconsList.has(key))
return null;
return new URL(`../icons/128/${key}.png`, import.meta.url).href;
}
/**
* Returns true if a PNG icon exists for the given symbol.
*/
export function isCryptoIconSupported(symbol) {
return webIconsList.has(symbol.toLowerCase());
}
/**
* Returns all supported symbol strings.
*/
export function getSupportedSymbols() {
return [...webIconsList];
}
/**
* Lightweight web `<img>` component for cryptocurrency icons.
* Falls back to a colored letter-avatar when no icon is available or on error.
*/
export const CryptoIcon = React.memo(function CryptoIcon({ symbol, size = 32, className, style, alt, }) {
const url = getCryptoIconUrl(symbol);
const [errored, setErrored] = useState(false);
const rootStyle = Object.assign({ width: size, height: size, display: "inline-flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", overflow: "hidden", flexShrink: 0 }, style);
if (url && !errored) {
return (React.createElement("span", { className: className, style: rootStyle },
React.createElement("img", { src: url, alt: alt !== null && alt !== void 0 ? alt : symbol.toUpperCase(), width: size, height: size, onError: () => setErrored(true), style: { width: "100%", height: "100%", objectFit: "contain" } })));
}
// Fallback: letter avatar with a deterministic color derived from the symbol
const letter = symbol.slice(0, 2).toUpperCase();
const hue = symbol
.toLowerCase()
.split("")
.reduce((acc, c) => acc + c.charCodeAt(0), 0) % 360;
return (React.createElement("span", { className: className, style: Object.assign(Object.assign({}, rootStyle), { background: `hsl(${hue}, 55%, 38%)`, color: "#fff", fontSize: size * 0.32, fontWeight: 700, fontFamily: "sans-serif" }) }, letter));
});