react-inlinesvg
Version:
An SVG loader for React
1 lines • 13.2 kB
Source Map (JSON)
{"version":3,"file":"provider-B5LIZTJG.cjs","names":[],"sources":["../src/config.ts","../src/modules/helpers.ts","../src/modules/cache.ts","../src/provider.tsx"],"sourcesContent":["export const CACHE_NAME = 'react-inlinesvg';\nexport const CACHE_MAX_RETRIES = 10;\n\nexport const STATUS = {\n IDLE: 'idle',\n LOADING: 'loading',\n LOADED: 'loaded',\n FAILED: 'failed',\n READY: 'ready',\n UNSUPPORTED: 'unsupported',\n} as const;\n","function randomCharacter(character: string) {\n return character[Math.floor(Math.random() * character.length)];\n}\n\nexport function canUseDOM(): boolean {\n return !!(typeof window !== 'undefined' && window.document?.createElement);\n}\n\nexport function isSupportedEnvironment(): boolean {\n return supportsInlineSVG() && typeof window !== 'undefined' && window !== null;\n}\n\n/**\n * Remove properties from an object\n */\nexport function omit<T extends Record<string, unknown>, K extends keyof T>(\n input: T,\n ...filter: K[]\n): Omit<T, K> {\n const output: any = {};\n\n for (const key in input) {\n if ({}.hasOwnProperty.call(input, key) && !filter.includes(key as unknown as K)) {\n output[key] = input[key];\n }\n }\n\n return output as Omit<T, K>;\n}\n\nexport function randomString(length: number): string {\n const letters = 'abcdefghijklmnopqrstuvwxyz';\n const numbers = '1234567890';\n const charset = `${letters}${letters.toUpperCase()}${numbers}`;\n\n let R = '';\n\n for (let index = 0; index < length; index++) {\n R += randomCharacter(charset);\n }\n\n return R;\n}\n\nexport async function request(url: string, options?: RequestInit) {\n const response = await fetch(url, options);\n const contentType = response.headers.get('content-type');\n const [fileType] = (contentType ?? '').split(/ ?; ?/);\n\n if (response.status > 299) {\n throw new Error('Not found');\n }\n\n if (!['image/svg+xml', 'text/plain'].some(d => fileType.includes(d))) {\n throw new Error(`Content type isn't valid: ${fileType}`);\n }\n\n return response.text();\n}\n\nexport function supportsInlineSVG(): boolean {\n /* c8 ignore next 3 */\n if (!document) {\n return false;\n }\n\n const div = document.createElement('div');\n\n div.innerHTML = '<svg />';\n const svg = div.firstChild as SVGSVGElement;\n\n return !!svg && svg.namespaceURI === 'http://www.w3.org/2000/svg';\n}\n","import { CACHE_MAX_RETRIES, CACHE_NAME, STATUS } from '../config';\nimport { StorageItem } from '../types';\n\nimport { canUseDOM, request } from './helpers';\n\nexport interface CacheStoreOptions {\n name?: string;\n persistent?: boolean;\n}\n\nexport default class CacheStore {\n private cacheApi: Cache | undefined;\n private readonly cacheStore: Map<string, StorageItem>;\n private readonly subscribers: Array<() => void> = [];\n public isReady = false;\n\n constructor(options: CacheStoreOptions = {}) {\n const { name = CACHE_NAME, persistent = false } = options;\n\n this.cacheStore = new Map<string, StorageItem>();\n\n const usePersistentCache = persistent && canUseDOM() && 'caches' in window;\n\n if (usePersistentCache) {\n // eslint-disable-next-line promise/catch-or-return\n caches\n .open(name)\n .then(cache => {\n this.cacheApi = cache;\n })\n .catch(error => {\n // eslint-disable-next-line no-console\n console.error(`Failed to open cache: ${error.message}`);\n this.cacheApi = undefined;\n })\n .finally(() => {\n this.isReady = true;\n // Copy to avoid mutation issues\n const callbacks = [...this.subscribers];\n\n // Clear array efficiently\n this.subscribers.length = 0;\n\n callbacks.forEach(callback => {\n try {\n callback();\n } catch (error: any) {\n // eslint-disable-next-line no-console\n console.error(`Error in CacheStore subscriber callback: ${error.message}`);\n }\n });\n });\n } else {\n this.isReady = true;\n }\n }\n\n public onReady(callback: () => void): () => void {\n if (this.isReady) {\n callback();\n\n return () => {};\n }\n\n this.subscribers.push(callback);\n\n return () => {\n const index = this.subscribers.indexOf(callback);\n\n if (index >= 0) {\n this.subscribers.splice(index, 1);\n }\n };\n }\n\n private waitForReady(): Promise<void> {\n if (this.isReady) {\n return Promise.resolve();\n }\n\n return new Promise(resolve => {\n this.onReady(resolve);\n });\n }\n\n public async get(url: string, fetchOptions?: RequestInit) {\n await this.fetchAndCache(url, fetchOptions);\n\n return this.cacheStore.get(url)?.content ?? '';\n }\n\n public getContent(url: string): string {\n return this.cacheStore.get(url)?.content ?? '';\n }\n\n public set(url: string, data: StorageItem) {\n this.cacheStore.set(url, data);\n }\n\n public isCached(url: string) {\n return this.cacheStore.get(url)?.status === STATUS.LOADED;\n }\n\n private async fetchAndCache(url: string, fetchOptions?: RequestInit) {\n if (!this.isReady) {\n await this.waitForReady();\n }\n\n const cache = this.cacheStore.get(url);\n\n if (cache?.status === STATUS.LOADED) {\n return;\n }\n\n if (cache?.status === STATUS.LOADING) {\n await this.handleLoading(url, fetchOptions?.signal || undefined, async () => {\n this.cacheStore.set(url, { content: '', status: STATUS.IDLE });\n await this.fetchAndCache(url, fetchOptions);\n });\n\n const failed = this.cacheStore.get(url);\n\n if (failed?.status === STATUS.FAILED) {\n if (failed.error) {\n throw failed.error;\n }\n\n this.cacheStore.delete(url);\n await this.fetchAndCache(url, fetchOptions);\n }\n\n return;\n }\n\n this.cacheStore.set(url, { content: '', status: STATUS.LOADING });\n\n try {\n const content = this.cacheApi\n ? await this.fetchFromPersistentCache(url, fetchOptions)\n : await request(url, fetchOptions);\n\n this.cacheStore.set(url, { content, status: STATUS.LOADED });\n } catch (error: any) {\n const isAbort = error?.name === 'AbortError';\n\n this.cacheStore.set(url, {\n content: '',\n error: isAbort ? undefined : error,\n status: STATUS.FAILED,\n });\n throw error;\n }\n }\n\n private async fetchFromPersistentCache(url: string, fetchOptions?: RequestInit): Promise<string> {\n const data = await this.cacheApi?.match(url);\n\n if (data) {\n return data.text();\n }\n\n await this.cacheApi?.add(new Request(url, fetchOptions));\n\n const response = await this.cacheApi?.match(url);\n\n return (await response?.text()) ?? '';\n }\n\n private async handleLoading(\n url: string,\n signal: AbortSignal | undefined,\n callback: () => Promise<void>,\n ) {\n for (let retryCount = 0; retryCount < CACHE_MAX_RETRIES; retryCount++) {\n if (signal?.aborted) {\n throw signal.reason instanceof Error\n ? signal.reason\n : new DOMException('The operation was aborted.', 'AbortError');\n }\n\n if (this.cacheStore.get(url)?.status !== STATUS.LOADING) {\n return;\n }\n\n await sleep(0.1);\n }\n\n await callback();\n }\n\n public keys(): Array<string> {\n return [...this.cacheStore.keys()];\n }\n\n public data(): Array<Record<string, StorageItem>> {\n return [...this.cacheStore.entries()].map(([key, value]) => ({ [key]: value }));\n }\n\n public async delete(url: string) {\n if (this.cacheApi) {\n await this.cacheApi.delete(url);\n }\n\n this.cacheStore.delete(url);\n }\n\n public async clear() {\n if (this.cacheApi) {\n const keys = await this.cacheApi.keys();\n\n await Promise.allSettled(keys.map(key => this.cacheApi!.delete(key)));\n }\n\n this.cacheStore.clear();\n }\n}\n\nfunction sleep(seconds = 1) {\n return new Promise(resolve => {\n setTimeout(resolve, seconds * 1000);\n });\n}\n","import React, { createContext, ReactNode, useContext, useState } from 'react';\n\nimport CacheStore from './modules/cache';\n\nconst CacheContext = createContext<CacheStore | null>(null);\n\ninterface Props {\n children: ReactNode;\n name?: string;\n}\n\nexport default function CacheProvider({ children, name }: Props) {\n const [store] = useState(() => new CacheStore({ name, persistent: true }));\n\n return <CacheContext.Provider value={store}>{children}</CacheContext.Provider>;\n}\n\nexport function useCacheStore(): CacheStore | null {\n return useContext(CacheContext);\n}\n"],"mappings":"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"}