react-inlinesvg 3.0.2 → 3.0.3
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 +5 -4
- package/esm/helpers.d.ts +7 -7
- package/esm/helpers.js +3 -3
- package/esm/helpers.js.map +1 -1
- package/esm/index.d.ts +6 -6
- package/esm/index.js +150 -107
- package/esm/index.js.map +1 -1
- package/esm/types.d.ts +5 -3
- package/lib/helpers.d.ts +7 -7
- package/lib/helpers.js +3 -3
- package/lib/helpers.js.map +1 -1
- package/lib/index.d.ts +6 -6
- package/lib/index.js +150 -107
- package/lib/index.js.map +1 -1
- package/lib/types.d.ts +5 -3
- package/package.json +19 -19
- package/src/helpers.ts +5 -5
- package/src/index.tsx +107 -114
- package/src/types.ts +7 -3
package/src/index.tsx
CHANGED
|
@@ -2,14 +2,14 @@ import * as React from 'react';
|
|
|
2
2
|
import convert from 'react-from-dom';
|
|
3
3
|
|
|
4
4
|
import { canUseDOM, isSupportedEnvironment, omit, randomString, STATUS } from './helpers';
|
|
5
|
-
import { FetchError, Props, State, StorageItem } from './types';
|
|
5
|
+
import { FetchError, Props, State, Status, StorageItem } from './types';
|
|
6
6
|
|
|
7
7
|
export const cacheStore: { [key: string]: StorageItem } = Object.create(null);
|
|
8
8
|
|
|
9
9
|
export default class InlineSVG extends React.PureComponent<Props, State> {
|
|
10
|
-
private isInitialized = false;
|
|
11
|
-
private isActive = false;
|
|
12
10
|
private readonly hash: string;
|
|
11
|
+
private isActive = false;
|
|
12
|
+
private isInitialized = false;
|
|
13
13
|
|
|
14
14
|
public static defaultProps = {
|
|
15
15
|
cacheRequests: true,
|
|
@@ -23,7 +23,7 @@ export default class InlineSVG extends React.PureComponent<Props, State> {
|
|
|
23
23
|
content: '',
|
|
24
24
|
element: null,
|
|
25
25
|
hasCache: !!props.cacheRequests && !!cacheStore[props.src],
|
|
26
|
-
status: STATUS.
|
|
26
|
+
status: STATUS.IDLE,
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
this.hash = props.uniqueHash || randomString(8);
|
|
@@ -41,7 +41,7 @@ export default class InlineSVG extends React.PureComponent<Props, State> {
|
|
|
41
41
|
|
|
42
42
|
try {
|
|
43
43
|
/* istanbul ignore else */
|
|
44
|
-
if (status === STATUS.
|
|
44
|
+
if (status === STATUS.IDLE) {
|
|
45
45
|
/* istanbul ignore else */
|
|
46
46
|
if (!isSupportedEnvironment()) {
|
|
47
47
|
throw new Error('Browser does not support SVG');
|
|
@@ -91,6 +91,24 @@ export default class InlineSVG extends React.PureComponent<Props, State> {
|
|
|
91
91
|
this.isActive = false;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
private getElement() {
|
|
95
|
+
try {
|
|
96
|
+
const node = this.getNode() as Node;
|
|
97
|
+
const element = convert(node);
|
|
98
|
+
|
|
99
|
+
if (!element || !React.isValidElement(element)) {
|
|
100
|
+
throw new Error('Could not convert the src to a React element');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
this.setState({
|
|
104
|
+
element,
|
|
105
|
+
status: STATUS.READY,
|
|
106
|
+
});
|
|
107
|
+
} catch (error: any) {
|
|
108
|
+
this.handleError(new Error(error.message));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
94
112
|
private getNode() {
|
|
95
113
|
const { description, title } = this.props;
|
|
96
114
|
|
|
@@ -138,38 +156,6 @@ export default class InlineSVG extends React.PureComponent<Props, State> {
|
|
|
138
156
|
}
|
|
139
157
|
}
|
|
140
158
|
|
|
141
|
-
private getElement() {
|
|
142
|
-
try {
|
|
143
|
-
const node = this.getNode() as Node;
|
|
144
|
-
const element = convert(node);
|
|
145
|
-
|
|
146
|
-
if (!element || !React.isValidElement(element)) {
|
|
147
|
-
throw new Error('Could not convert the src to a React element');
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
this.setState({
|
|
151
|
-
element,
|
|
152
|
-
status: STATUS.READY,
|
|
153
|
-
});
|
|
154
|
-
} catch (error: any) {
|
|
155
|
-
this.handleError(new Error(error.message));
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
private handleLoad = (content: string, hasCache = false) => {
|
|
160
|
-
/* istanbul ignore else */
|
|
161
|
-
if (this.isActive) {
|
|
162
|
-
this.setState(
|
|
163
|
-
{
|
|
164
|
-
content,
|
|
165
|
-
hasCache,
|
|
166
|
-
status: STATUS.LOADED,
|
|
167
|
-
},
|
|
168
|
-
this.getElement,
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
|
|
173
159
|
private handleError = (error: Error | FetchError) => {
|
|
174
160
|
const { onError } = this.props;
|
|
175
161
|
const status =
|
|
@@ -186,69 +172,17 @@ export default class InlineSVG extends React.PureComponent<Props, State> {
|
|
|
186
172
|
}
|
|
187
173
|
};
|
|
188
174
|
|
|
189
|
-
private
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
.
|
|
199
|
-
|
|
200
|
-
const [fileType] = (contentType || '').split(/ ?; ?/);
|
|
201
|
-
|
|
202
|
-
if (response.status > 299) {
|
|
203
|
-
throw new Error('Not found');
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (!['image/svg+xml', 'text/plain'].some(d => fileType.includes(d))) {
|
|
207
|
-
throw new Error(`Content type isn't valid: ${fileType}`);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return response.text();
|
|
211
|
-
})
|
|
212
|
-
.then(content => {
|
|
213
|
-
const { src: currentSrc } = this.props;
|
|
214
|
-
|
|
215
|
-
// the current src don't match the previous one, skipping...
|
|
216
|
-
if (src !== currentSrc) {
|
|
217
|
-
if (cacheStore[src].status === STATUS.LOADING) {
|
|
218
|
-
delete cacheStore[src];
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
this.handleLoad(content);
|
|
225
|
-
|
|
226
|
-
/* istanbul ignore else */
|
|
227
|
-
if (cacheRequests) {
|
|
228
|
-
const cache = cacheStore[src];
|
|
229
|
-
|
|
230
|
-
/* istanbul ignore else */
|
|
231
|
-
if (cache) {
|
|
232
|
-
cache.content = content;
|
|
233
|
-
cache.status = STATUS.LOADED;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
})
|
|
237
|
-
.catch(error => {
|
|
238
|
-
this.handleError(error);
|
|
239
|
-
|
|
240
|
-
/* istanbul ignore else */
|
|
241
|
-
if (cacheRequests) {
|
|
242
|
-
const cache = cacheStore[src];
|
|
243
|
-
|
|
244
|
-
/* istanbul ignore else */
|
|
245
|
-
if (cache) {
|
|
246
|
-
delete cacheStore[src];
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
} catch (error: any) {
|
|
251
|
-
return this.handleError(new Error(error.message));
|
|
175
|
+
private handleLoad = (content: string, hasCache = false) => {
|
|
176
|
+
/* istanbul ignore else */
|
|
177
|
+
if (this.isActive) {
|
|
178
|
+
this.setState(
|
|
179
|
+
{
|
|
180
|
+
content,
|
|
181
|
+
hasCache,
|
|
182
|
+
status: STATUS.LOADED,
|
|
183
|
+
},
|
|
184
|
+
this.getElement,
|
|
185
|
+
);
|
|
252
186
|
}
|
|
253
187
|
};
|
|
254
188
|
|
|
@@ -272,7 +206,7 @@ export default class InlineSVG extends React.PureComponent<Props, State> {
|
|
|
272
206
|
return;
|
|
273
207
|
}
|
|
274
208
|
|
|
275
|
-
const dataURI = src.match(
|
|
209
|
+
const dataURI = src.match(/^data:image\/svg[^,]*?(;base64)?,(.*)/u);
|
|
276
210
|
let inlineSrc;
|
|
277
211
|
|
|
278
212
|
if (dataURI) {
|
|
@@ -293,6 +227,76 @@ export default class InlineSVG extends React.PureComponent<Props, State> {
|
|
|
293
227
|
}
|
|
294
228
|
}
|
|
295
229
|
|
|
230
|
+
private processSVG() {
|
|
231
|
+
const { content } = this.state;
|
|
232
|
+
const { preProcessor } = this.props;
|
|
233
|
+
|
|
234
|
+
if (preProcessor) {
|
|
235
|
+
return preProcessor(content);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return content;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private request = async () => {
|
|
242
|
+
const { cacheRequests, fetchOptions, src } = this.props;
|
|
243
|
+
|
|
244
|
+
if (cacheRequests) {
|
|
245
|
+
cacheStore[src] = { content: '', status: STATUS.LOADING };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
const response = await fetch(src, fetchOptions);
|
|
250
|
+
const contentType = response.headers.get('content-type');
|
|
251
|
+
const [fileType] = (contentType || '').split(/ ?; ?/);
|
|
252
|
+
|
|
253
|
+
if (response.status > 299) {
|
|
254
|
+
throw new Error('Not found');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (!['image/svg+xml', 'text/plain'].some(d => fileType.includes(d))) {
|
|
258
|
+
throw new Error(`Content type isn't valid: ${fileType}`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const content: string = await response.text();
|
|
262
|
+
const { src: currentSrc } = this.props;
|
|
263
|
+
|
|
264
|
+
// the current src don't match the previous one, skipping...
|
|
265
|
+
if (src !== currentSrc) {
|
|
266
|
+
if (cacheStore[src].status === STATUS.LOADING) {
|
|
267
|
+
delete cacheStore[src];
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
this.handleLoad(content);
|
|
274
|
+
|
|
275
|
+
/* istanbul ignore else */
|
|
276
|
+
if (cacheRequests) {
|
|
277
|
+
const cache = cacheStore[src];
|
|
278
|
+
|
|
279
|
+
/* istanbul ignore else */
|
|
280
|
+
if (cache) {
|
|
281
|
+
cache.content = content;
|
|
282
|
+
cache.status = STATUS.LOADED;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
} catch (error: any) {
|
|
286
|
+
this.handleError(error);
|
|
287
|
+
|
|
288
|
+
/* istanbul ignore else */
|
|
289
|
+
if (cacheRequests) {
|
|
290
|
+
const cache = cacheStore[src];
|
|
291
|
+
|
|
292
|
+
/* istanbul ignore else */
|
|
293
|
+
if (cache) {
|
|
294
|
+
delete cacheStore[src];
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
296
300
|
private updateSVGAttributes(node: SVGSVGElement): SVGSVGElement {
|
|
297
301
|
const { baseURL = '', uniquifyIDs } = this.props;
|
|
298
302
|
const replaceableAttributes = ['id', 'href', 'xlink:href', 'xlink:role', 'xlink:arcrole'];
|
|
@@ -304,7 +308,7 @@ export default class InlineSVG extends React.PureComponent<Props, State> {
|
|
|
304
308
|
return node;
|
|
305
309
|
}
|
|
306
310
|
|
|
307
|
-
[...node.children].
|
|
311
|
+
[...node.children].forEach(d => {
|
|
308
312
|
if (d.attributes && d.attributes.length) {
|
|
309
313
|
const attributes = Object.values(d.attributes).map(a => {
|
|
310
314
|
const attribute = a;
|
|
@@ -336,17 +340,6 @@ export default class InlineSVG extends React.PureComponent<Props, State> {
|
|
|
336
340
|
return node;
|
|
337
341
|
}
|
|
338
342
|
|
|
339
|
-
private processSVG() {
|
|
340
|
-
const { content } = this.state;
|
|
341
|
-
const { preProcessor } = this.props;
|
|
342
|
-
|
|
343
|
-
if (preProcessor) {
|
|
344
|
-
return preProcessor(content);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
return content;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
343
|
public render(): React.ReactNode {
|
|
351
344
|
const { element, status } = this.state;
|
|
352
345
|
const { children = null, innerRef, loader = null } = this.props;
|
|
@@ -376,7 +369,7 @@ export default class InlineSVG extends React.PureComponent<Props, State> {
|
|
|
376
369
|
return React.cloneElement(element as React.ReactElement, { ref: innerRef, ...elementProps });
|
|
377
370
|
}
|
|
378
371
|
|
|
379
|
-
if ([STATUS.UNSUPPORTED, STATUS.FAILED].includes(status)) {
|
|
372
|
+
if (([STATUS.UNSUPPORTED, STATUS.FAILED] as Status[]).includes(status)) {
|
|
380
373
|
return children;
|
|
381
374
|
}
|
|
382
375
|
|
package/src/types.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
+
import { STATUS } from './helpers';
|
|
4
|
+
|
|
3
5
|
export type ErrorCallback = (error: Error | FetchError) => void;
|
|
4
6
|
export type LoadCallback = (src: string, isCached: boolean) => void;
|
|
5
|
-
export type PlainObject<T = unknown> = Record<string
|
|
7
|
+
export type PlainObject<T = unknown> = Record<string, T>;
|
|
6
8
|
export type PreProcessorCallback = (code: string) => string;
|
|
7
9
|
|
|
8
10
|
export interface Props extends Omit<React.SVGProps<SVGElement>, 'onLoad' | 'onError' | 'ref'> {
|
|
@@ -26,7 +28,7 @@ export interface State {
|
|
|
26
28
|
content: string;
|
|
27
29
|
element: React.ReactNode;
|
|
28
30
|
hasCache: boolean;
|
|
29
|
-
status:
|
|
31
|
+
status: Status;
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
export interface FetchError extends Error {
|
|
@@ -36,7 +38,9 @@ export interface FetchError extends Error {
|
|
|
36
38
|
type: string;
|
|
37
39
|
}
|
|
38
40
|
|
|
41
|
+
export type Status = (typeof STATUS)[keyof typeof STATUS];
|
|
42
|
+
|
|
39
43
|
export interface StorageItem {
|
|
40
44
|
content: string;
|
|
41
|
-
status:
|
|
45
|
+
status: Status;
|
|
42
46
|
}
|