iconista
Version:
Thousands of SVG icons with one React component
67 lines (66 loc) • 2.47 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const react_1 = tslib_1.__importDefault(require("react"));
const getUrl_1 = require("./getUrl");
const useRefMounted_1 = tslib_1.__importDefault(require("react-use/lib/useRefMounted"));
const { useEffect, useState, useRef } = react_1.default;
const cache = {};
const loadDoc = (url) => new Promise((resolve, reject) => {
const req = new XMLHttpRequest();
req.onreadystatechange = () => {
const { readyState, status, responseXML: doc } = req;
if (readyState !== 4)
return;
if (status !== 200)
return reject(new Error(`SVG loading HTTP ${status} error: ${url}`));
if (!doc)
return reject(new Error(`Could not load SVG Document: ${url}`));
resolve(doc);
};
req.open('GET', url, true);
req.send();
});
const Svg = ({ set, icon, getUrl = getUrl_1.getUrl, ...rest }) => {
const ref = useRef(null);
const refMounted = (0, useRefMounted_1.default)();
const [error, setError] = useState();
useEffect(() => {
const applyDoc = (doc) => {
const el = ref.current;
if (!el)
return;
const svg = doc.getRootNode().childNodes[0];
const { childNodes } = svg;
// Set SVG child nodes.
for (let i = 0; i < childNodes.length; i++)
el.appendChild(childNodes[i].cloneNode(true));
// Set SVG attributes.
for (let i = 0; i < svg.attributes.length; i++) {
const { name, value } = svg.attributes[i];
el.setAttribute(name, value);
}
};
const key = `${set}:${icon}`;
if (cache[key])
applyDoc(cache[key]);
else {
const url = getUrl({ set, icon });
loadDoc(url).then((doc) => {
if (!refMounted.current)
return;
applyDoc((cache[key] = doc));
}, (error) => {
if (!refMounted.current)
return;
setError(error);
});
}
}, [set, icon]);
if (error) {
const url = getUrl({ set, icon });
return react_1.default.createElement("img", { ...rest, src: url, title: error.message });
}
return react_1.default.createElement("svg", { ref: ref, ...rest });
};
exports.default = Svg;