react-inlinesvg 1.1.7 → 2.1.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 -15
- package/esm/helpers.d.ts +12 -0
- package/esm/helpers.js +38 -0
- package/esm/helpers.js.map +1 -0
- package/esm/index.d.ts +25 -0
- package/esm/index.js +356 -0
- package/esm/index.js.map +1 -0
- package/esm/types.d.ts +38 -0
- package/esm/types.js +2 -0
- package/esm/types.js.map +1 -0
- package/lib/helpers.d.ts +12 -10
- package/lib/helpers.js +24 -35
- package/lib/helpers.js.map +1 -1
- package/lib/index.d.ts +9 -48
- package/lib/index.js +67 -55
- package/lib/index.js.map +1 -1
- package/lib/types.d.ts +38 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/package.json +59 -53
- package/src/helpers.ts +20 -24
- package/src/index.tsx +77 -107
- package/src/types.ts +43 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-inlinesvg",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "An SVG loader for React",
|
|
5
5
|
"author": "Gil Barbara <gilbarbara@gmail.com>",
|
|
6
6
|
"contributors": [
|
|
@@ -18,83 +18,85 @@
|
|
|
18
18
|
},
|
|
19
19
|
"homepage": "https://github.com/gilbarbara/react-inlinesvg#readme",
|
|
20
20
|
"main": "lib/index.js",
|
|
21
|
+
"module": "esm/index.js",
|
|
21
22
|
"files": [
|
|
23
|
+
"esm",
|
|
22
24
|
"lib",
|
|
23
25
|
"src"
|
|
24
26
|
],
|
|
25
27
|
"types": "lib/index.d.ts",
|
|
28
|
+
"sideEffects": true,
|
|
26
29
|
"license": "MIT",
|
|
27
30
|
"keywords": [
|
|
28
31
|
"react",
|
|
29
32
|
"svg"
|
|
30
33
|
],
|
|
31
34
|
"peerDependencies": {
|
|
32
|
-
"react": "^16.
|
|
33
|
-
"react-dom": "^16.3.0"
|
|
35
|
+
"react": "^16.8.0"
|
|
34
36
|
},
|
|
35
37
|
"dependencies": {
|
|
36
38
|
"exenv": "^1.2.2",
|
|
37
|
-
"react-from-dom": "^0.2
|
|
39
|
+
"react-from-dom": "^0.4.2"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
42
|
"@gilbarbara/tsconfig": "^0.1.0",
|
|
41
|
-
"@size-limit/preset-small-lib": "^
|
|
42
|
-
"@types/enzyme": "^3.10.
|
|
43
|
-
"@types/enzyme-adapter-react-16": "^1.0.
|
|
43
|
+
"@size-limit/preset-small-lib": "^4.5.7",
|
|
44
|
+
"@types/enzyme": "^3.10.5",
|
|
45
|
+
"@types/enzyme-adapter-react-16": "^1.0.6",
|
|
44
46
|
"@types/exenv": "^1.2.0",
|
|
45
|
-
"@types/fetch-mock": "^7.3.
|
|
46
|
-
"@types/jest": "^
|
|
47
|
-
"@types/node": "^
|
|
48
|
-
"@types/node-fetch": "^2.5.
|
|
49
|
-
"@types/react": "^16.9.
|
|
50
|
-
"@types/react-dom": "^16.9.
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
47
|
+
"@types/fetch-mock": "^7.3.3",
|
|
48
|
+
"@types/jest": "^26.0.13",
|
|
49
|
+
"@types/node": "^14.6.4",
|
|
50
|
+
"@types/node-fetch": "^2.5.7",
|
|
51
|
+
"@types/react": "^16.9.49",
|
|
52
|
+
"@types/react-dom": "^16.9.8",
|
|
53
|
+
"@typescript-eslint/eslint-plugin": "^4.0.1",
|
|
54
|
+
"@typescript-eslint/parser": "^4.0.1",
|
|
55
|
+
"del-cli": "^3.0.1",
|
|
56
|
+
"enzyme": "^3.11.0",
|
|
57
|
+
"enzyme-adapter-react-16": "^1.15.4",
|
|
58
|
+
"eslint": "^7.8.1",
|
|
59
|
+
"eslint-config-airbnb": "^18.2.0",
|
|
60
|
+
"eslint-config-prettier": "^6.11.0",
|
|
61
|
+
"eslint-plugin-import": "^2.22.0",
|
|
62
|
+
"eslint-plugin-jsx-a11y": "^6.3.1",
|
|
63
|
+
"eslint-plugin-prettier": "^3.1.4",
|
|
64
|
+
"eslint-plugin-react": "^7.20.6",
|
|
65
|
+
"http-server": "^0.12.3",
|
|
66
|
+
"husky": "^4.2.5",
|
|
67
|
+
"jest": "^26.4.2",
|
|
68
|
+
"jest-chain": "^1.1.5",
|
|
69
|
+
"jest-enzyme": "^7.1.2",
|
|
70
|
+
"jest-extended": "^0.11.5",
|
|
71
|
+
"jest-fetch-mock": "^3.0.3",
|
|
72
|
+
"jest-watch-typeahead": "^0.6.1",
|
|
73
|
+
"node-fetch": "^2.6.1",
|
|
74
|
+
"prettier": "^2.1.1",
|
|
75
|
+
"react": "^16.13.1",
|
|
76
|
+
"react-dom": "^16.13.1",
|
|
66
77
|
"repo-tools": "^0.2.0",
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"ts-jest": "^24.1.0",
|
|
72
|
-
"ts-node": "^8.4.1",
|
|
73
|
-
"tslint": "^5.20.0",
|
|
74
|
-
"tslint-config-prettier": "^1.18.0",
|
|
75
|
-
"tslint-react": "^4.1.0",
|
|
76
|
-
"typescript": "^3.6.3"
|
|
78
|
+
"size-limit": "^4.5.7",
|
|
79
|
+
"start-server-and-test": "^1.11.3",
|
|
80
|
+
"ts-jest": "^26.3.0",
|
|
81
|
+
"typescript": "^4.0.2"
|
|
77
82
|
},
|
|
78
83
|
"scripts": {
|
|
79
|
-
"build": "npm run clean && npm run build:
|
|
80
|
-
"build:
|
|
81
|
-
"
|
|
82
|
-
"clean": "
|
|
83
|
-
"
|
|
84
|
+
"build": "npm run clean && npm run build:cjs && npm run build:esm",
|
|
85
|
+
"build:cjs": "tsc",
|
|
86
|
+
"build:esm": "tsc -m es6 --outDir esm",
|
|
87
|
+
"clean": "del lib/* && del esm/*",
|
|
88
|
+
"watch:cjs": "npm run build:cjs -- -w",
|
|
89
|
+
"watch:esm": "npm run build:esm -- -w",
|
|
90
|
+
"start": "http-server test/__fixtures__ -p 1337 --cors",
|
|
84
91
|
"test": "start-server-and-test start http://localhost:1337 test:coverage",
|
|
85
92
|
"test:coverage": "jest --coverage --bail",
|
|
86
93
|
"test:watch": "jest --watch --verbose",
|
|
87
|
-
"lint": "
|
|
94
|
+
"lint": "eslint --ext .ts,.tsx src test",
|
|
88
95
|
"format": "prettier \"**/*.{js,jsx,json,yml,yaml,css,less,scss,ts,tsx,md,graphql,mdx}\" --write",
|
|
89
|
-
"validate": "npm run lint && npm run test && npm run size",
|
|
90
|
-
"size": "
|
|
96
|
+
"validate": "npm run lint && npm run test && npm run build && npm run size",
|
|
97
|
+
"size": "size-limit",
|
|
91
98
|
"prepublishOnly": "npm run validate"
|
|
92
99
|
},
|
|
93
|
-
"browserslist": [
|
|
94
|
-
"> 0.2%",
|
|
95
|
-
"safari >= 9",
|
|
96
|
-
"ios >= 9"
|
|
97
|
-
],
|
|
98
100
|
"prettier": {
|
|
99
101
|
"jsxBracketSameLine": false,
|
|
100
102
|
"printWidth": 100,
|
|
@@ -104,12 +106,16 @@
|
|
|
104
106
|
"size-limit": [
|
|
105
107
|
{
|
|
106
108
|
"path": "./lib/index.js",
|
|
107
|
-
"limit": "8
|
|
109
|
+
"limit": "8 kB"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"path": "./esm/index.js",
|
|
113
|
+
"limit": "8 kB"
|
|
108
114
|
}
|
|
109
115
|
],
|
|
110
116
|
"husky": {
|
|
111
117
|
"hooks": {
|
|
112
|
-
"post-merge": "repo-tools
|
|
118
|
+
"post-merge": "repo-tools install-packages",
|
|
113
119
|
"pre-commit": "repo-tools check-remote && npm run validate"
|
|
114
120
|
}
|
|
115
121
|
}
|
package/src/helpers.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { canUseDOM as canUseDOMFlag } from 'exenv';
|
|
2
2
|
|
|
3
|
-
export const
|
|
3
|
+
export const STATUS = {
|
|
4
|
+
FAILED: 'failed',
|
|
5
|
+
LOADED: 'loaded',
|
|
6
|
+
LOADING: 'loading',
|
|
7
|
+
PENDING: 'pending',
|
|
8
|
+
READY: 'ready',
|
|
9
|
+
UNSUPPORTED: 'unsupported',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function canUseDOM(): boolean {
|
|
13
|
+
return canUseDOMFlag;
|
|
14
|
+
}
|
|
4
15
|
|
|
5
|
-
export
|
|
16
|
+
export function supportsInlineSVG(): boolean {
|
|
6
17
|
/* istanbul ignore next */
|
|
7
18
|
if (!document) {
|
|
8
19
|
return false;
|
|
@@ -10,30 +21,14 @@ export const supportsInlineSVG = () => {
|
|
|
10
21
|
|
|
11
22
|
const div = document.createElement('div');
|
|
12
23
|
div.innerHTML = '<svg />';
|
|
13
|
-
return div.firstChild && div.firstChild.namespaceURI === 'http://www.w3.org/2000/svg';
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
// tslint:disable-next-line:no-shadowed-variable
|
|
17
|
-
export class InlineSVGError extends Error {
|
|
18
|
-
public name: string;
|
|
19
|
-
public message: string;
|
|
20
|
-
public data?: object;
|
|
21
|
-
|
|
22
|
-
constructor(message: string, data?: object) {
|
|
23
|
-
super();
|
|
24
|
-
|
|
25
|
-
this.name = 'InlineSVGError';
|
|
26
|
-
this.message = message;
|
|
27
|
-
this.data = data;
|
|
28
|
-
|
|
29
|
-
return this;
|
|
30
|
-
}
|
|
24
|
+
return !!div.firstChild && div.firstChild.namespaceURI === 'http://www.w3.org/2000/svg';
|
|
31
25
|
}
|
|
32
26
|
|
|
33
|
-
export
|
|
34
|
-
supportsInlineSVG() && typeof window !== 'undefined' && window !== null;
|
|
27
|
+
export function isSupportedEnvironment(): boolean {
|
|
28
|
+
return supportsInlineSVG() && typeof window !== 'undefined' && window !== null;
|
|
29
|
+
}
|
|
35
30
|
|
|
36
|
-
export
|
|
31
|
+
export function randomString(length: number): string {
|
|
37
32
|
const letters = 'abcdefghijklmnopqrstuvwxyz';
|
|
38
33
|
const numbers = '1234567890';
|
|
39
34
|
const charset = `${letters}${letters.toUpperCase()}${numbers}`;
|
|
@@ -45,5 +40,6 @@ export const randomString = (length: number) => {
|
|
|
45
40
|
for (let i = 0; i < length; i++) {
|
|
46
41
|
R += randomCharacter(charset);
|
|
47
42
|
}
|
|
43
|
+
|
|
48
44
|
return R;
|
|
49
|
-
}
|
|
45
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -2,67 +2,13 @@ import * as React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import convert from 'react-from-dom';
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
export interface IProps {
|
|
8
|
-
baseURL?: string;
|
|
9
|
-
cacheRequests?: boolean;
|
|
10
|
-
children?: React.ReactNode;
|
|
11
|
-
description?: string;
|
|
12
|
-
loader?: React.ReactNode;
|
|
13
|
-
innerRef?: React.Ref<HTMLElement>;
|
|
14
|
-
onError?: (error: InlineSVGError | IFetchError) => void;
|
|
15
|
-
onLoad?: (src: string, isCached: boolean) => void;
|
|
16
|
-
preProcessor?: (code: string) => string;
|
|
17
|
-
src: string;
|
|
18
|
-
title?: string;
|
|
19
|
-
uniqueHash?: string;
|
|
20
|
-
uniquifyIDs?: boolean;
|
|
21
|
-
[key: string]: any;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface IState {
|
|
25
|
-
content: string;
|
|
26
|
-
element: React.ReactNode;
|
|
27
|
-
hasCache: boolean;
|
|
28
|
-
status: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface IFetchError extends Error {
|
|
32
|
-
code: string;
|
|
33
|
-
errno: string;
|
|
34
|
-
message: string;
|
|
35
|
-
type: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface IStorageItem {
|
|
39
|
-
content: string;
|
|
40
|
-
queue: any[];
|
|
41
|
-
status: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export const STATUS = {
|
|
45
|
-
FAILED: 'failed',
|
|
46
|
-
LOADED: 'loaded',
|
|
47
|
-
LOADING: 'loading',
|
|
48
|
-
PENDING: 'pending',
|
|
49
|
-
READY: 'ready',
|
|
50
|
-
UNSUPPORTED: 'unsupported',
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const cacheStore: { [key: string]: IStorageItem } = Object.create(null);
|
|
54
|
-
|
|
55
|
-
export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
56
|
-
public static defaultProps = {
|
|
57
|
-
cacheRequests: true,
|
|
58
|
-
uniquifyIDs: false,
|
|
59
|
-
};
|
|
5
|
+
import { STATUS, canUseDOM, isSupportedEnvironment, randomString } from './helpers';
|
|
6
|
+
import { FetchError, Props, State, StorageItem } from './types';
|
|
60
7
|
|
|
61
|
-
|
|
62
|
-
private _isMounted = false;
|
|
63
|
-
private readonly hash: string;
|
|
8
|
+
const cacheStore: { [key: string]: StorageItem } = Object.create(null);
|
|
64
9
|
|
|
65
|
-
|
|
10
|
+
export default class InlineSVG extends React.PureComponent<Props, State> {
|
|
11
|
+
constructor(props: Props) {
|
|
66
12
|
super(props);
|
|
67
13
|
|
|
68
14
|
this.state = {
|
|
@@ -75,11 +21,18 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
75
21
|
this.hash = props.uniqueHash || randomString(8);
|
|
76
22
|
}
|
|
77
23
|
|
|
78
|
-
|
|
79
|
-
|
|
24
|
+
private isActive = false;
|
|
25
|
+
private readonly hash: string;
|
|
26
|
+
|
|
27
|
+
public static defaultProps = {
|
|
28
|
+
cacheRequests: true,
|
|
29
|
+
uniquifyIDs: false,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
public componentDidMount(): void {
|
|
33
|
+
this.isActive = true;
|
|
80
34
|
|
|
81
35
|
if (!canUseDOM()) {
|
|
82
|
-
this.handleError(new InlineSVGError('No DOM'));
|
|
83
36
|
return;
|
|
84
37
|
}
|
|
85
38
|
|
|
@@ -91,12 +44,12 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
91
44
|
if (status === STATUS.PENDING) {
|
|
92
45
|
/* istanbul ignore else */
|
|
93
46
|
if (!isSupportedEnvironment()) {
|
|
94
|
-
throw new
|
|
47
|
+
throw new Error('Browser does not support SVG');
|
|
95
48
|
}
|
|
96
49
|
|
|
97
50
|
/* istanbul ignore else */
|
|
98
51
|
if (!src) {
|
|
99
|
-
throw new
|
|
52
|
+
throw new Error('Missing src');
|
|
100
53
|
}
|
|
101
54
|
|
|
102
55
|
this.load();
|
|
@@ -106,7 +59,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
106
59
|
}
|
|
107
60
|
}
|
|
108
61
|
|
|
109
|
-
public componentDidUpdate(prevProps:
|
|
62
|
+
public componentDidUpdate(prevProps: Props, prevState: State): void {
|
|
110
63
|
if (!canUseDOM()) {
|
|
111
64
|
return;
|
|
112
65
|
}
|
|
@@ -123,7 +76,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
123
76
|
|
|
124
77
|
if (prevProps.src !== src) {
|
|
125
78
|
if (!src) {
|
|
126
|
-
this.handleError(new
|
|
79
|
+
this.handleError(new Error('Missing src'));
|
|
127
80
|
return;
|
|
128
81
|
}
|
|
129
82
|
|
|
@@ -131,8 +84,8 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
131
84
|
}
|
|
132
85
|
}
|
|
133
86
|
|
|
134
|
-
public componentWillUnmount() {
|
|
135
|
-
this.
|
|
87
|
+
public componentWillUnmount(): void {
|
|
88
|
+
this.isActive = false;
|
|
136
89
|
}
|
|
137
90
|
|
|
138
91
|
private processSVG() {
|
|
@@ -157,20 +110,21 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
157
110
|
return node;
|
|
158
111
|
}
|
|
159
112
|
|
|
160
|
-
[...node.children].map(d => {
|
|
113
|
+
[...node.children].map((d) => {
|
|
161
114
|
if (d.attributes && d.attributes.length) {
|
|
162
|
-
const attributes = Object.values(d.attributes)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const match = a.value.match(/^url\((#[^)]+)/);
|
|
115
|
+
const attributes = Object.values(d.attributes).map((a) => {
|
|
116
|
+
const attr = a;
|
|
117
|
+
const match = a.value.match(/url\((.*?)\)/);
|
|
166
118
|
|
|
167
119
|
if (match && match[1]) {
|
|
168
|
-
|
|
120
|
+
attr.value = a.value.replace(match[0], `url(${baseURL}${match[1]}__${this.hash})`);
|
|
169
121
|
}
|
|
122
|
+
|
|
123
|
+
return attr;
|
|
170
124
|
});
|
|
171
125
|
|
|
172
|
-
replaceableAttributes.forEach(r => {
|
|
173
|
-
const attribute = attributes.find(a => a.name === r);
|
|
126
|
+
replaceableAttributes.forEach((r) => {
|
|
127
|
+
const attribute = attributes.find((a) => a.name === r);
|
|
174
128
|
|
|
175
129
|
if (attribute && !isDataValue(r, attribute.value)) {
|
|
176
130
|
attribute.value = `${attribute.value}__${this.hash}`;
|
|
@@ -179,7 +133,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
179
133
|
}
|
|
180
134
|
|
|
181
135
|
if (d.children.length) {
|
|
182
|
-
|
|
136
|
+
return this.updateSVGAttributes(d as SVGSVGElement);
|
|
183
137
|
}
|
|
184
138
|
|
|
185
139
|
return d;
|
|
@@ -196,7 +150,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
196
150
|
const node = convert(svgText, { nodeOnly: true });
|
|
197
151
|
|
|
198
152
|
if (!node || !(node instanceof SVGSVGElement)) {
|
|
199
|
-
throw new
|
|
153
|
+
throw new Error('Could not convert the src to a DOM Node');
|
|
200
154
|
}
|
|
201
155
|
|
|
202
156
|
const svg = this.updateSVGAttributes(node);
|
|
@@ -227,7 +181,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
227
181
|
|
|
228
182
|
return svg;
|
|
229
183
|
} catch (error) {
|
|
230
|
-
this.handleError(error);
|
|
184
|
+
return this.handleError(error);
|
|
231
185
|
}
|
|
232
186
|
}
|
|
233
187
|
|
|
@@ -237,7 +191,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
237
191
|
const element = convert(node);
|
|
238
192
|
|
|
239
193
|
if (!element || !React.isValidElement(element)) {
|
|
240
|
-
throw new
|
|
194
|
+
throw new Error('Could not convert the src to a React element');
|
|
241
195
|
}
|
|
242
196
|
|
|
243
197
|
this.setState({
|
|
@@ -245,13 +199,13 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
245
199
|
status: STATUS.READY,
|
|
246
200
|
});
|
|
247
201
|
} catch (error) {
|
|
248
|
-
this.handleError(new
|
|
202
|
+
this.handleError(new Error(error.message));
|
|
249
203
|
}
|
|
250
204
|
}
|
|
251
205
|
|
|
252
206
|
private load() {
|
|
253
207
|
/* istanbul ignore else */
|
|
254
|
-
if (this.
|
|
208
|
+
if (this.isActive) {
|
|
255
209
|
this.setState(
|
|
256
210
|
{
|
|
257
211
|
content: '',
|
|
@@ -265,7 +219,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
265
219
|
if (cache) {
|
|
266
220
|
/* istanbul ignore else */
|
|
267
221
|
if (cache.status === STATUS.LOADING) {
|
|
268
|
-
cache.queue.push(this.
|
|
222
|
+
cache.queue.push(this.handleCacheQueue);
|
|
269
223
|
} else if (cache.status === STATUS.LOADED) {
|
|
270
224
|
this.handleLoad(cache.content);
|
|
271
225
|
}
|
|
@@ -292,9 +246,19 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
292
246
|
}
|
|
293
247
|
}
|
|
294
248
|
|
|
249
|
+
private handleCacheQueue = (content: string | Error) => {
|
|
250
|
+
/* istanbul ignore else */
|
|
251
|
+
if (typeof content === 'string') {
|
|
252
|
+
this.handleLoad(content);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
this.handleError(content);
|
|
257
|
+
};
|
|
258
|
+
|
|
295
259
|
private handleLoad = (content: string) => {
|
|
296
260
|
/* istanbul ignore else */
|
|
297
|
-
if (this.
|
|
261
|
+
if (this.isActive) {
|
|
298
262
|
this.setState(
|
|
299
263
|
{
|
|
300
264
|
content,
|
|
@@ -305,19 +269,13 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
305
269
|
}
|
|
306
270
|
};
|
|
307
271
|
|
|
308
|
-
private handleError = (error:
|
|
272
|
+
private handleError = (error: Error | FetchError) => {
|
|
309
273
|
const { onError } = this.props;
|
|
310
274
|
const status =
|
|
311
275
|
error.message === 'Browser does not support SVG' ? STATUS.UNSUPPORTED : STATUS.FAILED;
|
|
312
276
|
|
|
313
277
|
/* istanbul ignore else */
|
|
314
|
-
if (
|
|
315
|
-
// tslint:disable-next-line:no-console
|
|
316
|
-
console.error(error);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/* istanbul ignore else */
|
|
320
|
-
if (this._isMounted) {
|
|
278
|
+
if (this.isActive) {
|
|
321
279
|
this.setState({ status }, () => {
|
|
322
280
|
/* istanbul ignore else */
|
|
323
281
|
if (typeof onError === 'function') {
|
|
@@ -336,21 +294,21 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
336
294
|
}
|
|
337
295
|
|
|
338
296
|
return fetch(src)
|
|
339
|
-
.then(response => {
|
|
297
|
+
.then((response) => {
|
|
340
298
|
const contentType = response.headers.get('content-type');
|
|
341
299
|
const [fileType] = (contentType || '').split(/ ?; ?/);
|
|
342
300
|
|
|
343
301
|
if (response.status > 299) {
|
|
344
|
-
throw new
|
|
302
|
+
throw new Error('Not found');
|
|
345
303
|
}
|
|
346
304
|
|
|
347
|
-
if (!['image/svg+xml', 'text/plain'].some(d => fileType.indexOf(d) >= 0)) {
|
|
348
|
-
throw new
|
|
305
|
+
if (!['image/svg+xml', 'text/plain'].some((d) => fileType.indexOf(d) >= 0)) {
|
|
306
|
+
throw new Error(`Content type isn't valid: ${fileType}`);
|
|
349
307
|
}
|
|
350
308
|
|
|
351
309
|
return response.text();
|
|
352
310
|
})
|
|
353
|
-
.then(content => {
|
|
311
|
+
.then((content) => {
|
|
354
312
|
this.handleLoad(content);
|
|
355
313
|
|
|
356
314
|
/* istanbul ignore else */
|
|
@@ -362,7 +320,7 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
362
320
|
cache.content = content;
|
|
363
321
|
cache.status = STATUS.LOADED;
|
|
364
322
|
|
|
365
|
-
cache.queue = cache.queue.filter((cb
|
|
323
|
+
cache.queue = cache.queue.filter((cb) => {
|
|
366
324
|
cb(content);
|
|
367
325
|
|
|
368
326
|
return false;
|
|
@@ -370,23 +328,29 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
370
328
|
}
|
|
371
329
|
}
|
|
372
330
|
})
|
|
373
|
-
.catch(error => {
|
|
331
|
+
.catch((error) => {
|
|
332
|
+
this.handleError(error);
|
|
333
|
+
|
|
374
334
|
/* istanbul ignore else */
|
|
375
335
|
if (cacheRequests) {
|
|
376
|
-
|
|
336
|
+
const cache = cacheStore[src];
|
|
337
|
+
|
|
338
|
+
/* istanbul ignore else */
|
|
339
|
+
if (cache) {
|
|
340
|
+
cache.queue.forEach((cb: (content: string) => void) => {
|
|
341
|
+
cb(error);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
delete cacheStore[src];
|
|
345
|
+
}
|
|
377
346
|
}
|
|
378
|
-
this.handleError(error);
|
|
379
347
|
});
|
|
380
348
|
} catch (error) {
|
|
381
|
-
this.handleError(new
|
|
349
|
+
return this.handleError(new Error(error.message));
|
|
382
350
|
}
|
|
383
351
|
};
|
|
384
352
|
|
|
385
|
-
public render() {
|
|
386
|
-
if (!canUseDOM()) {
|
|
387
|
-
return null;
|
|
388
|
-
}
|
|
389
|
-
|
|
353
|
+
public render(): React.ReactNode {
|
|
390
354
|
const { element, status } = this.state;
|
|
391
355
|
const {
|
|
392
356
|
baseURL,
|
|
@@ -405,6 +369,10 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
405
369
|
...rest
|
|
406
370
|
} = this.props;
|
|
407
371
|
|
|
372
|
+
if (!canUseDOM()) {
|
|
373
|
+
return loader;
|
|
374
|
+
}
|
|
375
|
+
|
|
408
376
|
if (element) {
|
|
409
377
|
return React.cloneElement(element as React.ReactElement, { ref: innerRef, ...rest });
|
|
410
378
|
}
|
|
@@ -416,3 +384,5 @@ export default class InlineSVG extends React.PureComponent<IProps, IState> {
|
|
|
416
384
|
return loader;
|
|
417
385
|
}
|
|
418
386
|
}
|
|
387
|
+
|
|
388
|
+
export * from './types';
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type Callback = (...args: any[]) => void;
|
|
4
|
+
|
|
5
|
+
export type ErrorCallback = (error: Error | FetchError) => void;
|
|
6
|
+
export type LoadCallback = (src: string, isCached: boolean) => void;
|
|
7
|
+
export type PreProcessorCallback = (code: string) => string;
|
|
8
|
+
|
|
9
|
+
export interface Props extends Omit<React.HTMLProps<SVGElement>, 'onLoad' | 'onError'> {
|
|
10
|
+
baseURL?: string;
|
|
11
|
+
cacheRequests?: boolean;
|
|
12
|
+
children?: React.ReactNode;
|
|
13
|
+
description?: string;
|
|
14
|
+
innerRef?: React.Ref<HTMLElement>;
|
|
15
|
+
loader?: React.ReactNode;
|
|
16
|
+
onError?: ErrorCallback;
|
|
17
|
+
onLoad?: LoadCallback;
|
|
18
|
+
preProcessor?: PreProcessorCallback;
|
|
19
|
+
src: string;
|
|
20
|
+
title?: string;
|
|
21
|
+
uniqueHash?: string;
|
|
22
|
+
uniquifyIDs?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface State {
|
|
26
|
+
content: string;
|
|
27
|
+
element: React.ReactNode;
|
|
28
|
+
hasCache: boolean;
|
|
29
|
+
status: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface FetchError extends Error {
|
|
33
|
+
code: string;
|
|
34
|
+
errno: string;
|
|
35
|
+
message: string;
|
|
36
|
+
type: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface StorageItem {
|
|
40
|
+
content: string;
|
|
41
|
+
queue: Callback[];
|
|
42
|
+
status: string;
|
|
43
|
+
}
|