react-inlinesvg
Version:
An SVG loader for React
229 lines (223 loc) • 7.62 kB
JavaScript
"use client";
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
// src/provider.tsx
var provider_exports = {};
__export(provider_exports, {
default: () => CacheProvider,
useCacheStore: () => useCacheStore
});
module.exports = __toCommonJS(provider_exports);
var import_react = __toESM(require("react"));
// src/config.ts
var CACHE_NAME = "react-inlinesvg";
var CACHE_MAX_RETRIES = 10;
var STATUS = {
IDLE: "idle",
LOADING: "loading",
LOADED: "loaded",
FAILED: "failed",
READY: "ready",
UNSUPPORTED: "unsupported"
};
// src/modules/helpers.ts
function canUseDOM() {
return !!(typeof window !== "undefined" && window.document?.createElement);
}
async function request(url, options) {
const response = await fetch(url, options);
const contentType = response.headers.get("content-type");
const [fileType] = (contentType ?? "").split(/ ?; ?/);
if (response.status > 299) {
throw new Error("Not found");
}
if (!["image/svg+xml", "text/plain"].some((d) => fileType.includes(d))) {
throw new Error(`Content type isn't valid: ${fileType}`);
}
return response.text();
}
// src/modules/cache.ts
var CacheStore = class {
constructor(options = {}) {
__publicField(this, "cacheApi");
__publicField(this, "cacheStore");
__publicField(this, "subscribers", []);
__publicField(this, "isReady", false);
const { name = CACHE_NAME, persistent = false } = options;
this.cacheStore = /* @__PURE__ */ new Map();
const usePersistentCache = persistent && canUseDOM() && "caches" in window;
if (usePersistentCache) {
caches.open(name).then((cache) => {
this.cacheApi = cache;
}).catch((error) => {
console.error(`Failed to open cache: ${error.message}`);
this.cacheApi = void 0;
}).finally(() => {
this.isReady = true;
const callbacks = [...this.subscribers];
this.subscribers.length = 0;
callbacks.forEach((callback) => {
try {
callback();
} catch (error) {
console.error(`Error in CacheStore subscriber callback: ${error.message}`);
}
});
});
} else {
this.isReady = true;
}
}
onReady(callback) {
if (this.isReady) {
callback();
return () => {
};
}
this.subscribers.push(callback);
return () => {
const index = this.subscribers.indexOf(callback);
if (index >= 0) {
this.subscribers.splice(index, 1);
}
};
}
waitForReady() {
if (this.isReady) {
return Promise.resolve();
}
return new Promise((resolve) => {
this.onReady(resolve);
});
}
async get(url, fetchOptions) {
await this.fetchAndCache(url, fetchOptions);
return this.cacheStore.get(url)?.content ?? "";
}
getContent(url) {
return this.cacheStore.get(url)?.content ?? "";
}
set(url, data) {
this.cacheStore.set(url, data);
}
isCached(url) {
return this.cacheStore.get(url)?.status === STATUS.LOADED;
}
async fetchAndCache(url, fetchOptions) {
if (!this.isReady) {
await this.waitForReady();
}
const cache = this.cacheStore.get(url);
if (cache?.status === STATUS.LOADED) {
return;
}
if (cache?.status === STATUS.LOADING) {
await this.handleLoading(url, fetchOptions?.signal || void 0, async () => {
this.cacheStore.set(url, { content: "", status: STATUS.IDLE });
await this.fetchAndCache(url, fetchOptions);
});
return;
}
this.cacheStore.set(url, { content: "", status: STATUS.LOADING });
try {
const content = this.cacheApi ? await this.fetchFromPersistentCache(url, fetchOptions) : await request(url, fetchOptions);
this.cacheStore.set(url, { content, status: STATUS.LOADED });
} catch (error) {
this.cacheStore.set(url, { content: "", status: STATUS.FAILED });
throw error;
}
}
async fetchFromPersistentCache(url, fetchOptions) {
const data = await this.cacheApi?.match(url);
if (data) {
return data.text();
}
await this.cacheApi?.add(new Request(url, fetchOptions));
const response = await this.cacheApi?.match(url);
return await response?.text() ?? "";
}
async handleLoading(url, signal, callback) {
for (let retryCount = 0; retryCount < CACHE_MAX_RETRIES; retryCount++) {
if (signal?.aborted) {
throw signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted.", "AbortError");
}
if (this.cacheStore.get(url)?.status !== STATUS.LOADING) {
return;
}
await sleep(0.1);
}
await callback();
}
keys() {
return [...this.cacheStore.keys()];
}
data() {
return [...this.cacheStore.entries()].map(([key, value]) => ({ [key]: value }));
}
async delete(url) {
if (this.cacheApi) {
await this.cacheApi.delete(url);
}
this.cacheStore.delete(url);
}
async clear() {
if (this.cacheApi) {
const keys = await this.cacheApi.keys();
await Promise.allSettled(keys.map((key) => this.cacheApi.delete(key)));
}
this.cacheStore.clear();
}
};
function sleep(seconds = 1) {
return new Promise((resolve) => {
setTimeout(resolve, seconds * 1e3);
});
}
// src/provider.tsx
var CacheContext = (0, import_react.createContext)(null);
function CacheProvider({ children, name }) {
const [store] = (0, import_react.useState)(() => new CacheStore({ name, persistent: true }));
return /* @__PURE__ */ import_react.default.createElement(CacheContext.Provider, { value: store }, children);
}
function useCacheStore() {
return (0, import_react.useContext)(CacheContext);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
useCacheStore
});
//# sourceMappingURL=provider.js.map
// fix-cjs-exports
if (module.exports.default) {
Object.assign(module.exports.default, module.exports);
module.exports = module.exports.default;
delete module.exports.default;
}