react-inlinesvg 4.2.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -34
- package/dist/cache-NLB60kAd.d.mts +142 -0
- package/dist/cache-NLB60kAd.d.ts +142 -0
- package/dist/index.d.mts +7 -73
- package/dist/index.d.ts +7 -73
- package/dist/index.js +258 -200
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +254 -204
- package/dist/index.mjs.map +1 -1
- package/dist/provider.d.mts +5 -3
- package/dist/provider.d.ts +5 -3
- package/dist/provider.js +187 -6
- package/dist/provider.js.map +1 -1
- package/dist/provider.mjs +176 -6
- package/dist/provider.mjs.map +1 -1
- package/package.json +25 -41
- package/src/index.tsx +29 -284
- package/src/modules/cache.ts +79 -59
- package/src/modules/helpers.ts +1 -9
- package/src/modules/hooks.tsx +6 -1
- package/src/modules/useInlineSVG.ts +272 -0
- package/src/modules/utils.ts +36 -1
- package/src/provider.tsx +10 -7
- package/src/types.ts +67 -1
- package/src/global.d.ts +0 -6
package/dist/index.mjs
CHANGED
|
@@ -4,16 +4,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
5
|
|
|
6
6
|
// src/index.tsx
|
|
7
|
-
import
|
|
8
|
-
cloneElement,
|
|
9
|
-
isValidElement,
|
|
10
|
-
useCallback,
|
|
11
|
-
useEffect as useEffect2,
|
|
12
|
-
useReducer,
|
|
13
|
-
useRef as useRef2,
|
|
14
|
-
useState
|
|
15
|
-
} from "react";
|
|
16
|
-
import convert2 from "react-from-dom";
|
|
7
|
+
import { cloneElement } from "react";
|
|
17
8
|
|
|
18
9
|
// src/config.ts
|
|
19
10
|
var CACHE_NAME = "react-inlinesvg";
|
|
@@ -70,11 +61,6 @@ async function request(url, options) {
|
|
|
70
61
|
}
|
|
71
62
|
return response.text();
|
|
72
63
|
}
|
|
73
|
-
function sleep(seconds = 1) {
|
|
74
|
-
return new Promise((resolve) => {
|
|
75
|
-
setTimeout(resolve, seconds * 1e3);
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
64
|
function supportsInlineSVG() {
|
|
79
65
|
if (!document) {
|
|
80
66
|
return false;
|
|
@@ -87,20 +73,16 @@ function supportsInlineSVG() {
|
|
|
87
73
|
|
|
88
74
|
// src/modules/cache.ts
|
|
89
75
|
var CacheStore = class {
|
|
90
|
-
constructor() {
|
|
76
|
+
constructor(options = {}) {
|
|
91
77
|
__publicField(this, "cacheApi");
|
|
92
78
|
__publicField(this, "cacheStore");
|
|
93
79
|
__publicField(this, "subscribers", []);
|
|
94
80
|
__publicField(this, "isReady", false);
|
|
81
|
+
const { name = CACHE_NAME, persistent = false } = options;
|
|
95
82
|
this.cacheStore = /* @__PURE__ */ new Map();
|
|
96
|
-
|
|
97
|
-
let usePersistentCache = false;
|
|
98
|
-
if (canUseDOM()) {
|
|
99
|
-
cacheName = window.REACT_INLINESVG_CACHE_NAME ?? CACHE_NAME;
|
|
100
|
-
usePersistentCache = !!window.REACT_INLINESVG_PERSISTENT_CACHE && "caches" in window;
|
|
101
|
-
}
|
|
83
|
+
const usePersistentCache = persistent && canUseDOM() && "caches" in window;
|
|
102
84
|
if (usePersistentCache) {
|
|
103
|
-
caches.open(
|
|
85
|
+
caches.open(name).then((cache) => {
|
|
104
86
|
this.cacheApi = cache;
|
|
105
87
|
}).catch((error) => {
|
|
106
88
|
console.error(`Failed to open cache: ${error.message}`);
|
|
@@ -124,12 +106,30 @@ var CacheStore = class {
|
|
|
124
106
|
onReady(callback) {
|
|
125
107
|
if (this.isReady) {
|
|
126
108
|
callback();
|
|
127
|
-
|
|
128
|
-
|
|
109
|
+
return () => {
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
this.subscribers.push(callback);
|
|
113
|
+
return () => {
|
|
114
|
+
const index = this.subscribers.indexOf(callback);
|
|
115
|
+
if (index >= 0) {
|
|
116
|
+
this.subscribers.splice(index, 1);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
waitForReady() {
|
|
121
|
+
if (this.isReady) {
|
|
122
|
+
return Promise.resolve();
|
|
129
123
|
}
|
|
124
|
+
return new Promise((resolve) => {
|
|
125
|
+
this.onReady(resolve);
|
|
126
|
+
});
|
|
130
127
|
}
|
|
131
128
|
async get(url, fetchOptions) {
|
|
132
|
-
await
|
|
129
|
+
await this.fetchAndCache(url, fetchOptions);
|
|
130
|
+
return this.cacheStore.get(url)?.content ?? "";
|
|
131
|
+
}
|
|
132
|
+
getContent(url) {
|
|
133
133
|
return this.cacheStore.get(url)?.content ?? "";
|
|
134
134
|
}
|
|
135
135
|
set(url, data) {
|
|
@@ -138,57 +138,44 @@ var CacheStore = class {
|
|
|
138
138
|
isCached(url) {
|
|
139
139
|
return this.cacheStore.get(url)?.status === STATUS.LOADED;
|
|
140
140
|
}
|
|
141
|
-
async
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
await this.handleLoading(url, async () => {
|
|
145
|
-
this.cacheStore.set(url, { content: "", status: STATUS.IDLE });
|
|
146
|
-
await this.fetchAndAddToInternalCache(url, fetchOptions);
|
|
147
|
-
});
|
|
148
|
-
return;
|
|
141
|
+
async fetchAndCache(url, fetchOptions) {
|
|
142
|
+
if (!this.isReady) {
|
|
143
|
+
await this.waitForReady();
|
|
149
144
|
}
|
|
150
|
-
if (!cache?.content) {
|
|
151
|
-
this.cacheStore.set(url, { content: "", status: STATUS.LOADING });
|
|
152
|
-
try {
|
|
153
|
-
const content = await request(url, fetchOptions);
|
|
154
|
-
this.cacheStore.set(url, { content, status: STATUS.LOADED });
|
|
155
|
-
} catch (error) {
|
|
156
|
-
this.cacheStore.set(url, { content: "", status: STATUS.FAILED });
|
|
157
|
-
throw error;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
async fetchAndAddToPersistentCache(url, fetchOptions) {
|
|
162
145
|
const cache = this.cacheStore.get(url);
|
|
163
146
|
if (cache?.status === STATUS.LOADED) {
|
|
164
147
|
return;
|
|
165
148
|
}
|
|
166
149
|
if (cache?.status === STATUS.LOADING) {
|
|
167
|
-
await this.handleLoading(url, async () => {
|
|
150
|
+
await this.handleLoading(url, fetchOptions?.signal || void 0, async () => {
|
|
168
151
|
this.cacheStore.set(url, { content: "", status: STATUS.IDLE });
|
|
169
|
-
await this.
|
|
152
|
+
await this.fetchAndCache(url, fetchOptions);
|
|
170
153
|
});
|
|
171
154
|
return;
|
|
172
155
|
}
|
|
173
156
|
this.cacheStore.set(url, { content: "", status: STATUS.LOADING });
|
|
174
|
-
const data = await this.cacheApi?.match(url);
|
|
175
|
-
if (data) {
|
|
176
|
-
const content = await data.text();
|
|
177
|
-
this.cacheStore.set(url, { content, status: STATUS.LOADED });
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
157
|
try {
|
|
181
|
-
await this.
|
|
182
|
-
const response = await this.cacheApi?.match(url);
|
|
183
|
-
const content = await response?.text() ?? "";
|
|
158
|
+
const content = this.cacheApi ? await this.fetchFromPersistentCache(url, fetchOptions) : await request(url, fetchOptions);
|
|
184
159
|
this.cacheStore.set(url, { content, status: STATUS.LOADED });
|
|
185
160
|
} catch (error) {
|
|
186
161
|
this.cacheStore.set(url, { content: "", status: STATUS.FAILED });
|
|
187
162
|
throw error;
|
|
188
163
|
}
|
|
189
164
|
}
|
|
190
|
-
async
|
|
165
|
+
async fetchFromPersistentCache(url, fetchOptions) {
|
|
166
|
+
const data = await this.cacheApi?.match(url);
|
|
167
|
+
if (data) {
|
|
168
|
+
return data.text();
|
|
169
|
+
}
|
|
170
|
+
await this.cacheApi?.add(new Request(url, fetchOptions));
|
|
171
|
+
const response = await this.cacheApi?.match(url);
|
|
172
|
+
return await response?.text() ?? "";
|
|
173
|
+
}
|
|
174
|
+
async handleLoading(url, signal, callback) {
|
|
191
175
|
for (let retryCount = 0; retryCount < CACHE_MAX_RETRIES; retryCount++) {
|
|
176
|
+
if (signal?.aborted) {
|
|
177
|
+
throw signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted.", "AbortError");
|
|
178
|
+
}
|
|
192
179
|
if (this.cacheStore.get(url)?.status !== STATUS.LOADING) {
|
|
193
180
|
return;
|
|
194
181
|
}
|
|
@@ -216,9 +203,21 @@ var CacheStore = class {
|
|
|
216
203
|
this.cacheStore.clear();
|
|
217
204
|
}
|
|
218
205
|
};
|
|
206
|
+
function sleep(seconds = 1) {
|
|
207
|
+
return new Promise((resolve) => {
|
|
208
|
+
setTimeout(resolve, seconds * 1e3);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// src/modules/useInlineSVG.ts
|
|
213
|
+
import { isValidElement, useCallback, useEffect as useEffect2, useReducer, useRef as useRef2 } from "react";
|
|
214
|
+
import convert2 from "react-from-dom";
|
|
219
215
|
|
|
220
216
|
// src/modules/hooks.tsx
|
|
221
217
|
import { useEffect, useRef } from "react";
|
|
218
|
+
function useMount(effect) {
|
|
219
|
+
useEffect(effect, []);
|
|
220
|
+
}
|
|
222
221
|
function usePrevious(state) {
|
|
223
222
|
const ref = useRef(void 0);
|
|
224
223
|
useEffect(() => {
|
|
@@ -229,6 +228,29 @@ function usePrevious(state) {
|
|
|
229
228
|
|
|
230
229
|
// src/modules/utils.ts
|
|
231
230
|
import convert from "react-from-dom";
|
|
231
|
+
function uniquifyStyleIds(svgText, hash, baseURL) {
|
|
232
|
+
const idMatches = svgText.matchAll(/\bid=(["'])([^"']+)\1/g);
|
|
233
|
+
const ids = [...new Set([...idMatches].map((m) => m[2]))];
|
|
234
|
+
if (!ids.length) {
|
|
235
|
+
return svgText;
|
|
236
|
+
}
|
|
237
|
+
ids.sort((a, b) => b.length - a.length);
|
|
238
|
+
return svgText.replace(/<style[^>]*>([\S\s]*?)<\/style>/gi, (fullMatch, cssContent) => {
|
|
239
|
+
let modified = cssContent;
|
|
240
|
+
for (const id of ids) {
|
|
241
|
+
const escaped = id.replace(/[$()*+.?[\\\]^{|}]/g, "\\$&");
|
|
242
|
+
modified = modified.replace(
|
|
243
|
+
new RegExp(`url\\((['"]?)#${escaped}\\1\\)`, "g"),
|
|
244
|
+
`url($1${baseURL}#${id}__${hash}$1)`
|
|
245
|
+
);
|
|
246
|
+
modified = modified.replace(
|
|
247
|
+
new RegExp(`#${escaped}(?![a-zA-Z0-9_-])`, "g"),
|
|
248
|
+
`#${id}__${hash}`
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
return fullMatch.replace(cssContent, modified);
|
|
252
|
+
});
|
|
253
|
+
}
|
|
232
254
|
function getNode(options) {
|
|
233
255
|
const {
|
|
234
256
|
baseURL,
|
|
@@ -241,7 +263,10 @@ function getNode(options) {
|
|
|
241
263
|
uniquifyIDs = false
|
|
242
264
|
} = options;
|
|
243
265
|
try {
|
|
244
|
-
|
|
266
|
+
let svgText = processSVG(content, preProcessor);
|
|
267
|
+
if (uniquifyIDs) {
|
|
268
|
+
svgText = uniquifyStyleIds(svgText, hash, baseURL ?? "");
|
|
269
|
+
}
|
|
245
270
|
const node = convert(svgText, { nodeOnly: true });
|
|
246
271
|
if (!node || !(node instanceof SVGSVGElement)) {
|
|
247
272
|
throw new Error("Could not convert the src to a DOM Node");
|
|
@@ -311,22 +336,30 @@ function updateSVGAttributes(node, options) {
|
|
|
311
336
|
return node;
|
|
312
337
|
}
|
|
313
338
|
|
|
314
|
-
// src/
|
|
315
|
-
|
|
316
|
-
function ReactInlineSVG(props) {
|
|
339
|
+
// src/modules/useInlineSVG.ts
|
|
340
|
+
function useInlineSVG(props, cacheStore2) {
|
|
317
341
|
const {
|
|
342
|
+
baseURL,
|
|
318
343
|
cacheRequests = true,
|
|
319
|
-
children = null,
|
|
320
344
|
description,
|
|
321
345
|
fetchOptions,
|
|
322
|
-
innerRef,
|
|
323
|
-
loader = null,
|
|
324
346
|
onError,
|
|
325
347
|
onLoad,
|
|
348
|
+
preProcessor,
|
|
326
349
|
src,
|
|
327
350
|
title,
|
|
328
|
-
uniqueHash
|
|
351
|
+
uniqueHash,
|
|
352
|
+
uniquifyIDs
|
|
329
353
|
} = props;
|
|
354
|
+
const hash = useRef2(uniqueHash ?? randomString(8));
|
|
355
|
+
const fetchOptionsRef = useRef2(fetchOptions);
|
|
356
|
+
const onErrorRef = useRef2(onError);
|
|
357
|
+
const onLoadRef = useRef2(onLoad);
|
|
358
|
+
const preProcessorRef = useRef2(preProcessor);
|
|
359
|
+
fetchOptionsRef.current = fetchOptions;
|
|
360
|
+
onErrorRef.current = onError;
|
|
361
|
+
onLoadRef.current = onLoad;
|
|
362
|
+
preProcessorRef.current = preProcessor;
|
|
330
363
|
const [state, setState] = useReducer(
|
|
331
364
|
(previousState2, nextState) => ({
|
|
332
365
|
...previousState2,
|
|
@@ -335,43 +368,71 @@ function ReactInlineSVG(props) {
|
|
|
335
368
|
{
|
|
336
369
|
content: "",
|
|
337
370
|
element: null,
|
|
338
|
-
isCached:
|
|
371
|
+
isCached: false,
|
|
339
372
|
status: STATUS.IDLE
|
|
373
|
+
},
|
|
374
|
+
(initial) => {
|
|
375
|
+
const cached = cacheRequests && cacheStore2.isCached(src);
|
|
376
|
+
if (!cached) {
|
|
377
|
+
return initial;
|
|
378
|
+
}
|
|
379
|
+
const cachedContent = cacheStore2.getContent(src);
|
|
380
|
+
try {
|
|
381
|
+
const node = getNode({
|
|
382
|
+
...props,
|
|
383
|
+
handleError: () => {
|
|
384
|
+
},
|
|
385
|
+
hash: hash.current,
|
|
386
|
+
content: cachedContent
|
|
387
|
+
});
|
|
388
|
+
if (!node) {
|
|
389
|
+
return { ...initial, content: cachedContent, isCached: true, status: STATUS.LOADED };
|
|
390
|
+
}
|
|
391
|
+
const convertedElement = convert2(node);
|
|
392
|
+
if (convertedElement && isValidElement(convertedElement)) {
|
|
393
|
+
return {
|
|
394
|
+
content: cachedContent,
|
|
395
|
+
element: convertedElement,
|
|
396
|
+
isCached: true,
|
|
397
|
+
status: STATUS.READY
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
} catch {
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
...initial,
|
|
404
|
+
content: cachedContent,
|
|
405
|
+
isCached: true,
|
|
406
|
+
status: STATUS.LOADED
|
|
407
|
+
};
|
|
340
408
|
}
|
|
341
409
|
);
|
|
342
410
|
const { content, element, isCached, status } = state;
|
|
343
411
|
const previousProps = usePrevious(props);
|
|
344
412
|
const previousState = usePrevious(state);
|
|
345
|
-
const hash = useRef2(uniqueHash ?? randomString(8));
|
|
346
413
|
const isActive = useRef2(false);
|
|
347
414
|
const isInitialized = useRef2(false);
|
|
348
|
-
const handleError = useCallback(
|
|
349
|
-
(error) => {
|
|
350
|
-
if (isActive.current) {
|
|
351
|
-
setState({
|
|
352
|
-
status: error.message === "Browser does not support SVG" ? STATUS.UNSUPPORTED : STATUS.FAILED
|
|
353
|
-
});
|
|
354
|
-
onError?.(error);
|
|
355
|
-
}
|
|
356
|
-
},
|
|
357
|
-
[onError]
|
|
358
|
-
);
|
|
359
|
-
const handleLoad = useCallback((loadedContent, hasCache = false) => {
|
|
415
|
+
const handleError = useCallback((error) => {
|
|
360
416
|
if (isActive.current) {
|
|
361
417
|
setState({
|
|
362
|
-
|
|
363
|
-
isCached: hasCache,
|
|
364
|
-
status: STATUS.LOADED
|
|
418
|
+
status: error.message === "Browser does not support SVG" ? STATUS.UNSUPPORTED : STATUS.FAILED
|
|
365
419
|
});
|
|
420
|
+
onErrorRef.current?.(error);
|
|
366
421
|
}
|
|
367
422
|
}, []);
|
|
368
|
-
const fetchContent = useCallback(async () => {
|
|
369
|
-
const responseContent = await request(src, fetchOptions);
|
|
370
|
-
handleLoad(responseContent);
|
|
371
|
-
}, [fetchOptions, handleLoad, src]);
|
|
372
423
|
const getElement = useCallback(() => {
|
|
373
424
|
try {
|
|
374
|
-
const node = getNode({
|
|
425
|
+
const node = getNode({
|
|
426
|
+
baseURL,
|
|
427
|
+
content,
|
|
428
|
+
description,
|
|
429
|
+
handleError,
|
|
430
|
+
hash: hash.current,
|
|
431
|
+
preProcessor: preProcessorRef.current,
|
|
432
|
+
src,
|
|
433
|
+
title,
|
|
434
|
+
uniquifyIDs
|
|
435
|
+
});
|
|
375
436
|
const convertedElement = convert2(node);
|
|
376
437
|
if (!convertedElement || !isValidElement(convertedElement)) {
|
|
377
438
|
throw new Error("Could not convert the src to a React element");
|
|
@@ -383,67 +444,32 @@ function ReactInlineSVG(props) {
|
|
|
383
444
|
} catch (error) {
|
|
384
445
|
handleError(error);
|
|
385
446
|
}
|
|
386
|
-
}, [content, handleError,
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
inlineSrc = dataURI[1] ? window.atob(dataURI[2]) : decodeURIComponent(dataURI[2]);
|
|
392
|
-
} else if (src.includes("<svg")) {
|
|
393
|
-
inlineSrc = src;
|
|
394
|
-
}
|
|
395
|
-
if (inlineSrc) {
|
|
396
|
-
handleLoad(inlineSrc);
|
|
397
|
-
return;
|
|
447
|
+
}, [baseURL, content, description, handleError, src, title, uniquifyIDs]);
|
|
448
|
+
useMount(() => {
|
|
449
|
+
isActive.current = true;
|
|
450
|
+
if (!canUseDOM() || isInitialized.current) {
|
|
451
|
+
return void 0;
|
|
398
452
|
}
|
|
399
453
|
try {
|
|
400
|
-
if (
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
454
|
+
if (status === STATUS.READY) {
|
|
455
|
+
onLoadRef.current?.(src, isCached);
|
|
456
|
+
} else if (status === STATUS.IDLE) {
|
|
457
|
+
if (!isSupportedEnvironment()) {
|
|
458
|
+
throw new Error("Browser does not support SVG");
|
|
459
|
+
}
|
|
460
|
+
if (!src) {
|
|
461
|
+
throw new Error("Missing src");
|
|
462
|
+
}
|
|
463
|
+
setState({ content: "", element: null, isCached: false, status: STATUS.LOADING });
|
|
405
464
|
}
|
|
406
465
|
} catch (error) {
|
|
407
466
|
handleError(error);
|
|
408
467
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
element: null,
|
|
415
|
-
isCached: false,
|
|
416
|
-
status: STATUS.LOADING
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
}, []);
|
|
420
|
-
useEffect2(
|
|
421
|
-
() => {
|
|
422
|
-
isActive.current = true;
|
|
423
|
-
if (!canUseDOM() || isInitialized.current) {
|
|
424
|
-
return void 0;
|
|
425
|
-
}
|
|
426
|
-
try {
|
|
427
|
-
if (status === STATUS.IDLE) {
|
|
428
|
-
if (!isSupportedEnvironment()) {
|
|
429
|
-
throw new Error("Browser does not support SVG");
|
|
430
|
-
}
|
|
431
|
-
if (!src) {
|
|
432
|
-
throw new Error("Missing src");
|
|
433
|
-
}
|
|
434
|
-
load();
|
|
435
|
-
}
|
|
436
|
-
} catch (error) {
|
|
437
|
-
handleError(error);
|
|
438
|
-
}
|
|
439
|
-
isInitialized.current = true;
|
|
440
|
-
return () => {
|
|
441
|
-
isActive.current = false;
|
|
442
|
-
};
|
|
443
|
-
},
|
|
444
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
445
|
-
[]
|
|
446
|
-
);
|
|
468
|
+
isInitialized.current = true;
|
|
469
|
+
return () => {
|
|
470
|
+
isActive.current = false;
|
|
471
|
+
};
|
|
472
|
+
});
|
|
447
473
|
useEffect2(() => {
|
|
448
474
|
if (!canUseDOM() || !previousProps) {
|
|
449
475
|
return;
|
|
@@ -453,14 +479,58 @@ function ReactInlineSVG(props) {
|
|
|
453
479
|
handleError(new Error("Missing src"));
|
|
454
480
|
return;
|
|
455
481
|
}
|
|
456
|
-
|
|
482
|
+
setState({ content: "", element: null, isCached: false, status: STATUS.LOADING });
|
|
457
483
|
}
|
|
458
|
-
}, [handleError,
|
|
484
|
+
}, [handleError, previousProps, src]);
|
|
459
485
|
useEffect2(() => {
|
|
460
|
-
if (status
|
|
486
|
+
if (status !== STATUS.LOADING) {
|
|
487
|
+
return void 0;
|
|
488
|
+
}
|
|
489
|
+
const controller = new AbortController();
|
|
490
|
+
let active = true;
|
|
491
|
+
(async () => {
|
|
492
|
+
try {
|
|
493
|
+
const dataURI = /^data:image\/svg[^,]*?(;base64)?,(.*)/.exec(src);
|
|
494
|
+
let inlineSrc;
|
|
495
|
+
if (dataURI) {
|
|
496
|
+
inlineSrc = dataURI[1] ? window.atob(dataURI[2]) : decodeURIComponent(dataURI[2]);
|
|
497
|
+
} else if (src.includes("<svg")) {
|
|
498
|
+
inlineSrc = src;
|
|
499
|
+
}
|
|
500
|
+
if (inlineSrc) {
|
|
501
|
+
if (active) {
|
|
502
|
+
setState({ content: inlineSrc, isCached: false, status: STATUS.LOADED });
|
|
503
|
+
}
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
const fetchParameters = { ...fetchOptionsRef.current, signal: controller.signal };
|
|
507
|
+
let loadedContent;
|
|
508
|
+
let hasCache = false;
|
|
509
|
+
if (cacheRequests) {
|
|
510
|
+
hasCache = cacheStore2.isCached(src);
|
|
511
|
+
loadedContent = await cacheStore2.get(src, fetchParameters);
|
|
512
|
+
} else {
|
|
513
|
+
loadedContent = await request(src, fetchParameters);
|
|
514
|
+
}
|
|
515
|
+
if (active) {
|
|
516
|
+
setState({ content: loadedContent, isCached: hasCache, status: STATUS.LOADED });
|
|
517
|
+
}
|
|
518
|
+
} catch (error) {
|
|
519
|
+
if (active && error.name !== "AbortError") {
|
|
520
|
+
handleError(error);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
})();
|
|
524
|
+
return () => {
|
|
525
|
+
active = false;
|
|
526
|
+
controller.abort();
|
|
527
|
+
};
|
|
528
|
+
}, [cacheRequests, cacheStore2, handleError, src, status]);
|
|
529
|
+
useEffect2(() => {
|
|
530
|
+
if (status === STATUS.LOADED && content) {
|
|
461
531
|
getElement();
|
|
462
532
|
}
|
|
463
|
-
}, [
|
|
533
|
+
}, [content, getElement, status]);
|
|
464
534
|
useEffect2(() => {
|
|
465
535
|
if (!canUseDOM() || !previousProps || previousProps.src !== src) {
|
|
466
536
|
return;
|
|
@@ -473,51 +543,50 @@ function ReactInlineSVG(props) {
|
|
|
473
543
|
if (!previousState) {
|
|
474
544
|
return;
|
|
475
545
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
if (previousState.status !== STATUS.LOADING) {
|
|
479
|
-
getContent();
|
|
480
|
-
}
|
|
481
|
-
break;
|
|
482
|
-
}
|
|
483
|
-
case STATUS.LOADED: {
|
|
484
|
-
if (previousState.status !== STATUS.LOADED) {
|
|
485
|
-
getElement();
|
|
486
|
-
}
|
|
487
|
-
break;
|
|
488
|
-
}
|
|
489
|
-
case STATUS.READY: {
|
|
490
|
-
if (previousState.status !== STATUS.READY) {
|
|
491
|
-
onLoad?.(src, isCached);
|
|
492
|
-
}
|
|
493
|
-
break;
|
|
494
|
-
}
|
|
546
|
+
if (status === STATUS.READY && previousState.status !== STATUS.READY) {
|
|
547
|
+
onLoadRef.current?.(src, isCached);
|
|
495
548
|
}
|
|
496
|
-
}, [
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
);
|
|
549
|
+
}, [isCached, previousState, src, status]);
|
|
550
|
+
return { element, status };
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// src/provider.tsx
|
|
554
|
+
import React, { createContext, useContext, useState } from "react";
|
|
555
|
+
var CacheContext = createContext(null);
|
|
556
|
+
function useCacheStore() {
|
|
557
|
+
return useContext(CacheContext);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// src/index.tsx
|
|
561
|
+
var cacheStore = new CacheStore();
|
|
562
|
+
function InlineSVG(props) {
|
|
563
|
+
const { children = null, innerRef, loader = null } = props;
|
|
564
|
+
const contextStore = useCacheStore();
|
|
565
|
+
const store = contextStore ?? cacheStore;
|
|
566
|
+
const { element, status } = useInlineSVG(props, store);
|
|
514
567
|
if (!canUseDOM()) {
|
|
515
568
|
return loader;
|
|
516
569
|
}
|
|
517
570
|
if (element) {
|
|
518
571
|
return cloneElement(element, {
|
|
519
572
|
ref: innerRef,
|
|
520
|
-
...
|
|
573
|
+
...omit(
|
|
574
|
+
props,
|
|
575
|
+
"baseURL",
|
|
576
|
+
"cacheRequests",
|
|
577
|
+
"children",
|
|
578
|
+
"description",
|
|
579
|
+
"fetchOptions",
|
|
580
|
+
"innerRef",
|
|
581
|
+
"loader",
|
|
582
|
+
"onError",
|
|
583
|
+
"onLoad",
|
|
584
|
+
"preProcessor",
|
|
585
|
+
"src",
|
|
586
|
+
"title",
|
|
587
|
+
"uniqueHash",
|
|
588
|
+
"uniquifyIDs"
|
|
589
|
+
)
|
|
521
590
|
});
|
|
522
591
|
}
|
|
523
592
|
if ([STATUS.UNSUPPORTED, STATUS.FAILED].includes(status)) {
|
|
@@ -525,25 +594,6 @@ function ReactInlineSVG(props) {
|
|
|
525
594
|
}
|
|
526
595
|
return loader;
|
|
527
596
|
}
|
|
528
|
-
function InlineSVG(props) {
|
|
529
|
-
if (!cacheStore) {
|
|
530
|
-
cacheStore = new CacheStore();
|
|
531
|
-
}
|
|
532
|
-
const { loader } = props;
|
|
533
|
-
const [isReady, setReady] = useState(cacheStore.isReady);
|
|
534
|
-
useEffect2(() => {
|
|
535
|
-
if (isReady) {
|
|
536
|
-
return;
|
|
537
|
-
}
|
|
538
|
-
cacheStore.onReady(() => {
|
|
539
|
-
setReady(true);
|
|
540
|
-
});
|
|
541
|
-
}, [isReady]);
|
|
542
|
-
if (!isReady) {
|
|
543
|
-
return loader;
|
|
544
|
-
}
|
|
545
|
-
return /* @__PURE__ */ React.createElement(ReactInlineSVG, { ...props });
|
|
546
|
-
}
|
|
547
597
|
export {
|
|
548
598
|
cacheStore,
|
|
549
599
|
InlineSVG as default
|