react-inlinesvg 4.1.8 → 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 +284 -202
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +280 -206
- 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 -261
- package/src/modules/cache.ts +100 -70
- 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 +69 -3
- 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,26 +73,31 @@ 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}`);
|
|
89
|
+
this.cacheApi = void 0;
|
|
107
90
|
}).finally(() => {
|
|
108
91
|
this.isReady = true;
|
|
109
|
-
this.subscribers
|
|
92
|
+
const callbacks = [...this.subscribers];
|
|
93
|
+
this.subscribers.length = 0;
|
|
94
|
+
callbacks.forEach((callback) => {
|
|
95
|
+
try {
|
|
96
|
+
callback();
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.error(`Error in CacheStore subscriber callback: ${error.message}`);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
110
101
|
});
|
|
111
102
|
} else {
|
|
112
103
|
this.isReady = true;
|
|
@@ -115,12 +106,30 @@ var CacheStore = class {
|
|
|
115
106
|
onReady(callback) {
|
|
116
107
|
if (this.isReady) {
|
|
117
108
|
callback();
|
|
118
|
-
|
|
119
|
-
|
|
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();
|
|
120
123
|
}
|
|
124
|
+
return new Promise((resolve) => {
|
|
125
|
+
this.onReady(resolve);
|
|
126
|
+
});
|
|
121
127
|
}
|
|
122
128
|
async get(url, fetchOptions) {
|
|
123
|
-
await
|
|
129
|
+
await this.fetchAndCache(url, fetchOptions);
|
|
130
|
+
return this.cacheStore.get(url)?.content ?? "";
|
|
131
|
+
}
|
|
132
|
+
getContent(url) {
|
|
124
133
|
return this.cacheStore.get(url)?.content ?? "";
|
|
125
134
|
}
|
|
126
135
|
set(url, data) {
|
|
@@ -129,64 +138,50 @@ var CacheStore = class {
|
|
|
129
138
|
isCached(url) {
|
|
130
139
|
return this.cacheStore.get(url)?.status === STATUS.LOADED;
|
|
131
140
|
}
|
|
132
|
-
async
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
await this.handleLoading(url, async () => {
|
|
136
|
-
this.cacheStore.set(url, { content: "", status: STATUS.IDLE });
|
|
137
|
-
await this.fetchAndAddToInternalCache(url, fetchOptions);
|
|
138
|
-
});
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
if (!cache?.content) {
|
|
142
|
-
this.cacheStore.set(url, { content: "", status: STATUS.LOADING });
|
|
143
|
-
try {
|
|
144
|
-
const content = await request(url, fetchOptions);
|
|
145
|
-
this.cacheStore.set(url, { content, status: STATUS.LOADED });
|
|
146
|
-
} catch (error) {
|
|
147
|
-
this.cacheStore.set(url, { content: "", status: STATUS.FAILED });
|
|
148
|
-
throw error;
|
|
149
|
-
}
|
|
141
|
+
async fetchAndCache(url, fetchOptions) {
|
|
142
|
+
if (!this.isReady) {
|
|
143
|
+
await this.waitForReady();
|
|
150
144
|
}
|
|
151
|
-
}
|
|
152
|
-
async fetchAndAddToPersistentCache(url, fetchOptions) {
|
|
153
145
|
const cache = this.cacheStore.get(url);
|
|
154
146
|
if (cache?.status === STATUS.LOADED) {
|
|
155
147
|
return;
|
|
156
148
|
}
|
|
157
149
|
if (cache?.status === STATUS.LOADING) {
|
|
158
|
-
await this.handleLoading(url, async () => {
|
|
150
|
+
await this.handleLoading(url, fetchOptions?.signal || void 0, async () => {
|
|
159
151
|
this.cacheStore.set(url, { content: "", status: STATUS.IDLE });
|
|
160
|
-
await this.
|
|
152
|
+
await this.fetchAndCache(url, fetchOptions);
|
|
161
153
|
});
|
|
162
154
|
return;
|
|
163
155
|
}
|
|
164
156
|
this.cacheStore.set(url, { content: "", status: STATUS.LOADING });
|
|
165
|
-
const data = await this.cacheApi?.match(url);
|
|
166
|
-
if (data) {
|
|
167
|
-
const content = await data.text();
|
|
168
|
-
this.cacheStore.set(url, { content, status: STATUS.LOADED });
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
157
|
try {
|
|
172
|
-
await this.
|
|
173
|
-
const response = await this.cacheApi?.match(url);
|
|
174
|
-
const content = await response?.text() ?? "";
|
|
158
|
+
const content = this.cacheApi ? await this.fetchFromPersistentCache(url, fetchOptions) : await request(url, fetchOptions);
|
|
175
159
|
this.cacheStore.set(url, { content, status: STATUS.LOADED });
|
|
176
160
|
} catch (error) {
|
|
177
161
|
this.cacheStore.set(url, { content: "", status: STATUS.FAILED });
|
|
178
162
|
throw error;
|
|
179
163
|
}
|
|
180
164
|
}
|
|
181
|
-
async
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
retryCount += 1;
|
|
165
|
+
async fetchFromPersistentCache(url, fetchOptions) {
|
|
166
|
+
const data = await this.cacheApi?.match(url);
|
|
167
|
+
if (data) {
|
|
168
|
+
return data.text();
|
|
186
169
|
}
|
|
187
|
-
|
|
188
|
-
|
|
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) {
|
|
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
|
+
}
|
|
179
|
+
if (this.cacheStore.get(url)?.status !== STATUS.LOADING) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
await sleep(0.1);
|
|
189
183
|
}
|
|
184
|
+
await callback();
|
|
190
185
|
}
|
|
191
186
|
keys() {
|
|
192
187
|
return [...this.cacheStore.keys()];
|
|
@@ -203,16 +198,26 @@ var CacheStore = class {
|
|
|
203
198
|
async clear() {
|
|
204
199
|
if (this.cacheApi) {
|
|
205
200
|
const keys = await this.cacheApi.keys();
|
|
206
|
-
|
|
207
|
-
await this.cacheApi.delete(key);
|
|
208
|
-
}
|
|
201
|
+
await Promise.allSettled(keys.map((key) => this.cacheApi.delete(key)));
|
|
209
202
|
}
|
|
210
203
|
this.cacheStore.clear();
|
|
211
204
|
}
|
|
212
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";
|
|
213
215
|
|
|
214
216
|
// src/modules/hooks.tsx
|
|
215
217
|
import { useEffect, useRef } from "react";
|
|
218
|
+
function useMount(effect) {
|
|
219
|
+
useEffect(effect, []);
|
|
220
|
+
}
|
|
216
221
|
function usePrevious(state) {
|
|
217
222
|
const ref = useRef(void 0);
|
|
218
223
|
useEffect(() => {
|
|
@@ -223,6 +228,29 @@ function usePrevious(state) {
|
|
|
223
228
|
|
|
224
229
|
// src/modules/utils.ts
|
|
225
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
|
+
}
|
|
226
254
|
function getNode(options) {
|
|
227
255
|
const {
|
|
228
256
|
baseURL,
|
|
@@ -235,7 +263,10 @@ function getNode(options) {
|
|
|
235
263
|
uniquifyIDs = false
|
|
236
264
|
} = options;
|
|
237
265
|
try {
|
|
238
|
-
|
|
266
|
+
let svgText = processSVG(content, preProcessor);
|
|
267
|
+
if (uniquifyIDs) {
|
|
268
|
+
svgText = uniquifyStyleIds(svgText, hash, baseURL ?? "");
|
|
269
|
+
}
|
|
239
270
|
const node = convert(svgText, { nodeOnly: true });
|
|
240
271
|
if (!node || !(node instanceof SVGSVGElement)) {
|
|
241
272
|
throw new Error("Could not convert the src to a DOM Node");
|
|
@@ -305,22 +336,30 @@ function updateSVGAttributes(node, options) {
|
|
|
305
336
|
return node;
|
|
306
337
|
}
|
|
307
338
|
|
|
308
|
-
// src/
|
|
309
|
-
|
|
310
|
-
function ReactInlineSVG(props) {
|
|
339
|
+
// src/modules/useInlineSVG.ts
|
|
340
|
+
function useInlineSVG(props, cacheStore2) {
|
|
311
341
|
const {
|
|
342
|
+
baseURL,
|
|
312
343
|
cacheRequests = true,
|
|
313
|
-
children = null,
|
|
314
344
|
description,
|
|
315
345
|
fetchOptions,
|
|
316
|
-
innerRef,
|
|
317
|
-
loader = null,
|
|
318
346
|
onError,
|
|
319
347
|
onLoad,
|
|
348
|
+
preProcessor,
|
|
320
349
|
src,
|
|
321
350
|
title,
|
|
322
|
-
uniqueHash
|
|
351
|
+
uniqueHash,
|
|
352
|
+
uniquifyIDs
|
|
323
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;
|
|
324
363
|
const [state, setState] = useReducer(
|
|
325
364
|
(previousState2, nextState) => ({
|
|
326
365
|
...previousState2,
|
|
@@ -329,43 +368,71 @@ function ReactInlineSVG(props) {
|
|
|
329
368
|
{
|
|
330
369
|
content: "",
|
|
331
370
|
element: null,
|
|
332
|
-
isCached:
|
|
371
|
+
isCached: false,
|
|
333
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
|
+
};
|
|
334
408
|
}
|
|
335
409
|
);
|
|
336
410
|
const { content, element, isCached, status } = state;
|
|
337
411
|
const previousProps = usePrevious(props);
|
|
338
412
|
const previousState = usePrevious(state);
|
|
339
|
-
const hash = useRef2(uniqueHash ?? randomString(8));
|
|
340
413
|
const isActive = useRef2(false);
|
|
341
414
|
const isInitialized = useRef2(false);
|
|
342
|
-
const handleError = useCallback(
|
|
343
|
-
(error) => {
|
|
344
|
-
if (isActive.current) {
|
|
345
|
-
setState({
|
|
346
|
-
status: error.message === "Browser does not support SVG" ? STATUS.UNSUPPORTED : STATUS.FAILED
|
|
347
|
-
});
|
|
348
|
-
onError?.(error);
|
|
349
|
-
}
|
|
350
|
-
},
|
|
351
|
-
[onError]
|
|
352
|
-
);
|
|
353
|
-
const handleLoad = useCallback((loadedContent, hasCache = false) => {
|
|
415
|
+
const handleError = useCallback((error) => {
|
|
354
416
|
if (isActive.current) {
|
|
355
417
|
setState({
|
|
356
|
-
|
|
357
|
-
isCached: hasCache,
|
|
358
|
-
status: STATUS.LOADED
|
|
418
|
+
status: error.message === "Browser does not support SVG" ? STATUS.UNSUPPORTED : STATUS.FAILED
|
|
359
419
|
});
|
|
420
|
+
onErrorRef.current?.(error);
|
|
360
421
|
}
|
|
361
422
|
}, []);
|
|
362
|
-
const fetchContent = useCallback(async () => {
|
|
363
|
-
const responseContent = await request(src, fetchOptions);
|
|
364
|
-
handleLoad(responseContent);
|
|
365
|
-
}, [fetchOptions, handleLoad, src]);
|
|
366
423
|
const getElement = useCallback(() => {
|
|
367
424
|
try {
|
|
368
|
-
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
|
+
});
|
|
369
436
|
const convertedElement = convert2(node);
|
|
370
437
|
if (!convertedElement || !isValidElement(convertedElement)) {
|
|
371
438
|
throw new Error("Could not convert the src to a React element");
|
|
@@ -375,124 +442,151 @@ function ReactInlineSVG(props) {
|
|
|
375
442
|
status: STATUS.READY
|
|
376
443
|
});
|
|
377
444
|
} catch (error) {
|
|
378
|
-
handleError(
|
|
379
|
-
}
|
|
380
|
-
}, [content, handleError,
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
inlineSrc = dataURI[1] ? window.atob(dataURI[2]) : decodeURIComponent(dataURI[2]);
|
|
386
|
-
} else if (src.includes("<svg")) {
|
|
387
|
-
inlineSrc = src;
|
|
388
|
-
}
|
|
389
|
-
if (inlineSrc) {
|
|
390
|
-
handleLoad(inlineSrc);
|
|
391
|
-
return;
|
|
445
|
+
handleError(error);
|
|
446
|
+
}
|
|
447
|
+
}, [baseURL, content, description, handleError, src, title, uniquifyIDs]);
|
|
448
|
+
useMount(() => {
|
|
449
|
+
isActive.current = true;
|
|
450
|
+
if (!canUseDOM() || isInitialized.current) {
|
|
451
|
+
return void 0;
|
|
392
452
|
}
|
|
393
453
|
try {
|
|
394
|
-
if (
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
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 });
|
|
399
464
|
}
|
|
400
465
|
} catch (error) {
|
|
401
466
|
handleError(error);
|
|
402
467
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
});
|
|
468
|
+
isInitialized.current = true;
|
|
469
|
+
return () => {
|
|
470
|
+
isActive.current = false;
|
|
471
|
+
};
|
|
472
|
+
});
|
|
473
|
+
useEffect2(() => {
|
|
474
|
+
if (!canUseDOM() || !previousProps) {
|
|
475
|
+
return;
|
|
412
476
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
if (!canUseDOM() || isInitialized.current) {
|
|
418
|
-
return () => void 0;
|
|
477
|
+
if (previousProps.src !== src) {
|
|
478
|
+
if (!src) {
|
|
479
|
+
handleError(new Error("Missing src"));
|
|
480
|
+
return;
|
|
419
481
|
}
|
|
482
|
+
setState({ content: "", element: null, isCached: false, status: STATUS.LOADING });
|
|
483
|
+
}
|
|
484
|
+
}, [handleError, previousProps, src]);
|
|
485
|
+
useEffect2(() => {
|
|
486
|
+
if (status !== STATUS.LOADING) {
|
|
487
|
+
return void 0;
|
|
488
|
+
}
|
|
489
|
+
const controller = new AbortController();
|
|
490
|
+
let active = true;
|
|
491
|
+
(async () => {
|
|
420
492
|
try {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
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 });
|
|
427
503
|
}
|
|
428
|
-
|
|
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 });
|
|
429
517
|
}
|
|
430
518
|
} catch (error) {
|
|
431
|
-
|
|
519
|
+
if (active && error.name !== "AbortError") {
|
|
520
|
+
handleError(error);
|
|
521
|
+
}
|
|
432
522
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
[]
|
|
440
|
-
);
|
|
523
|
+
})();
|
|
524
|
+
return () => {
|
|
525
|
+
active = false;
|
|
526
|
+
controller.abort();
|
|
527
|
+
};
|
|
528
|
+
}, [cacheRequests, cacheStore2, handleError, src, status]);
|
|
441
529
|
useEffect2(() => {
|
|
442
|
-
if (
|
|
443
|
-
|
|
530
|
+
if (status === STATUS.LOADED && content) {
|
|
531
|
+
getElement();
|
|
444
532
|
}
|
|
445
|
-
|
|
533
|
+
}, [content, getElement, status]);
|
|
534
|
+
useEffect2(() => {
|
|
535
|
+
if (!canUseDOM() || !previousProps || previousProps.src !== src) {
|
|
446
536
|
return;
|
|
447
537
|
}
|
|
448
|
-
if (previousProps.
|
|
449
|
-
if (!src) {
|
|
450
|
-
handleError(new Error("Missing src"));
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
load();
|
|
454
|
-
} else if (previousProps.title !== title || previousProps.description !== description) {
|
|
538
|
+
if (previousProps.title !== title || previousProps.description !== description) {
|
|
455
539
|
getElement();
|
|
456
540
|
}
|
|
457
|
-
}, [description, getElement,
|
|
541
|
+
}, [description, getElement, previousProps, src, title]);
|
|
458
542
|
useEffect2(() => {
|
|
459
543
|
if (!previousState) {
|
|
460
544
|
return;
|
|
461
545
|
}
|
|
462
|
-
if (
|
|
463
|
-
|
|
464
|
-
}
|
|
465
|
-
if (previousState.status !== STATUS.LOADED && status === STATUS.LOADED) {
|
|
466
|
-
getElement();
|
|
546
|
+
if (status === STATUS.READY && previousState.status !== STATUS.READY) {
|
|
547
|
+
onLoadRef.current?.(src, isCached);
|
|
467
548
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
"uniqueHash",
|
|
487
|
-
"uniquifyIDs"
|
|
488
|
-
);
|
|
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);
|
|
489
567
|
if (!canUseDOM()) {
|
|
490
568
|
return loader;
|
|
491
569
|
}
|
|
492
570
|
if (element) {
|
|
493
571
|
return cloneElement(element, {
|
|
494
572
|
ref: innerRef,
|
|
495
|
-
...
|
|
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
|
+
)
|
|
496
590
|
});
|
|
497
591
|
}
|
|
498
592
|
if ([STATUS.UNSUPPORTED, STATUS.FAILED].includes(status)) {
|
|
@@ -500,26 +594,6 @@ function ReactInlineSVG(props) {
|
|
|
500
594
|
}
|
|
501
595
|
return loader;
|
|
502
596
|
}
|
|
503
|
-
function InlineSVG(props) {
|
|
504
|
-
if (!cacheStore) {
|
|
505
|
-
cacheStore = new CacheStore();
|
|
506
|
-
}
|
|
507
|
-
const { loader } = props;
|
|
508
|
-
const hasCallback = useRef2(false);
|
|
509
|
-
const [isReady, setReady] = useState(cacheStore.isReady);
|
|
510
|
-
useEffect2(() => {
|
|
511
|
-
if (!hasCallback.current) {
|
|
512
|
-
cacheStore.onReady(() => {
|
|
513
|
-
setReady(true);
|
|
514
|
-
});
|
|
515
|
-
hasCallback.current = true;
|
|
516
|
-
}
|
|
517
|
-
}, []);
|
|
518
|
-
if (!isReady) {
|
|
519
|
-
return loader;
|
|
520
|
-
}
|
|
521
|
-
return /* @__PURE__ */ React.createElement(ReactInlineSVG, { ...props });
|
|
522
|
-
}
|
|
523
597
|
export {
|
|
524
598
|
cacheStore,
|
|
525
599
|
InlineSVG as default
|