@arcblock/ux 2.10.17 → 2.10.19
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/NFTDisplay/demo/data/asset-state-bad-url.json +7 -0
- package/lib/NFTDisplay/demo/data/asset-state-did-space-svg.json +7 -0
- package/lib/NFTDisplay/displayApi.js +47 -0
- package/lib/NFTDisplay/index.js +19 -7
- package/package.json +5 -5
- package/src/NFTDisplay/displayApi.js +42 -0
- package/src/NFTDisplay/index.js +11 -3
@@ -0,0 +1,47 @@
|
|
1
|
+
import axios from 'axios';
|
2
|
+
import adapter from 'axios/lib/adapters/xhr.js';
|
3
|
+
const cache = new Map();
|
4
|
+
const EXPIRATION_TIME_MS = 10 * 60 * 1000; // 10 minutes
|
5
|
+
|
6
|
+
const cacheAdapterEnhancer = config => {
|
7
|
+
const {
|
8
|
+
url,
|
9
|
+
method
|
10
|
+
} = config;
|
11
|
+
const cacheKey = JSON.stringify({
|
12
|
+
url,
|
13
|
+
method
|
14
|
+
});
|
15
|
+
if (cache.has(cacheKey)) {
|
16
|
+
const cachedResult = cache.get(cacheKey);
|
17
|
+
if (Date.now() - cachedResult.timestamp < EXPIRATION_TIME_MS) {
|
18
|
+
if (cachedResult.error) {
|
19
|
+
return Promise.reject(cachedResult.error);
|
20
|
+
}
|
21
|
+
return Promise.resolve({
|
22
|
+
headers: cachedResult.headers
|
23
|
+
});
|
24
|
+
}
|
25
|
+
cache.delete(cacheKey);
|
26
|
+
}
|
27
|
+
return adapter(config).then(response => {
|
28
|
+
// cache headers
|
29
|
+
cache.set(cacheKey, {
|
30
|
+
headers: response.headers,
|
31
|
+
timestamp: Date.now()
|
32
|
+
});
|
33
|
+
return response;
|
34
|
+
}).catch(error => {
|
35
|
+
// cache error
|
36
|
+
cache.set(cacheKey, {
|
37
|
+
error,
|
38
|
+
timestamp: Date.now()
|
39
|
+
});
|
40
|
+
throw error;
|
41
|
+
});
|
42
|
+
};
|
43
|
+
const instance = axios.create({
|
44
|
+
adapter: cacheAdapterEnhancer,
|
45
|
+
timeout: 5000
|
46
|
+
});
|
47
|
+
export default instance;
|
package/lib/NFTDisplay/index.js
CHANGED
@@ -14,6 +14,7 @@ import InlineSvgEmbedder from './svg-embedder/inline-svg';
|
|
14
14
|
import DefaultLoading from './loading';
|
15
15
|
import DefaultBrokenImage from './broken';
|
16
16
|
import { styled } from '../Theme';
|
17
|
+
import displayApi from './displayApi';
|
17
18
|
|
18
19
|
/**
|
19
20
|
* 从 assetState 中获取 nft data, 兼容新旧两种类型的数据结构, 建议将该方法的返回值传入 NFTDisplay 组件的 data prop
|
@@ -138,13 +139,14 @@ function NFTDisplay({
|
|
138
139
|
// get url content type
|
139
140
|
const getUrlContentType = async () => {
|
140
141
|
try {
|
141
|
-
const response = await
|
142
|
-
|
143
|
-
|
144
|
-
|
142
|
+
const response = await displayApi({
|
143
|
+
url: getFullContentUrl({
|
144
|
+
useImageFilter: false,
|
145
|
+
t: 'nftdisplay'
|
146
|
+
}),
|
145
147
|
method: 'HEAD'
|
146
148
|
});
|
147
|
-
const contentType = response
|
149
|
+
const contentType = response?.headers?.get('Content-Type');
|
148
150
|
setState({
|
149
151
|
...state,
|
150
152
|
loadingUrlType: false,
|
@@ -152,6 +154,16 @@ function NFTDisplay({
|
|
152
154
|
});
|
153
155
|
} catch (error) {
|
154
156
|
console.error('Failed to fetch url content type', error);
|
157
|
+
// display an error message when timeout occurs to avoid repeated waiting.
|
158
|
+
if (error?.message?.includes('timeout')) {
|
159
|
+
setState({
|
160
|
+
...state,
|
161
|
+
loadingUrlType: false,
|
162
|
+
loading: false,
|
163
|
+
error: true
|
164
|
+
});
|
165
|
+
return;
|
166
|
+
}
|
155
167
|
setState({
|
156
168
|
...state,
|
157
169
|
loadingUrlType: false,
|
@@ -227,8 +239,8 @@ function NFTDisplay({
|
|
227
239
|
onErrorCapture: onError,
|
228
240
|
onLoad: onLoad,
|
229
241
|
style: {
|
230
|
-
width: '
|
231
|
-
height: '
|
242
|
+
width: '100%',
|
243
|
+
height: '100%',
|
232
244
|
pointerEvents: 'none'
|
233
245
|
}
|
234
246
|
}, url)
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@arcblock/ux",
|
3
|
-
"version": "2.10.
|
3
|
+
"version": "2.10.19",
|
4
4
|
"description": "Common used react components for arcblock products",
|
5
5
|
"keywords": [
|
6
6
|
"react",
|
@@ -54,12 +54,12 @@
|
|
54
54
|
"react": ">=18.2.0",
|
55
55
|
"react-router-dom": ">=6.22.3"
|
56
56
|
},
|
57
|
-
"gitHead": "
|
57
|
+
"gitHead": "0cbaed2d297aa7ee7e7ebbaf7ccbc029ee3e624b",
|
58
58
|
"dependencies": {
|
59
59
|
"@arcblock/did-motif": "^1.1.13",
|
60
|
-
"@arcblock/icons": "^2.10.
|
61
|
-
"@arcblock/nft-display": "^2.10.
|
62
|
-
"@arcblock/react-hooks": "^2.10.
|
60
|
+
"@arcblock/icons": "^2.10.19",
|
61
|
+
"@arcblock/nft-display": "^2.10.19",
|
62
|
+
"@arcblock/react-hooks": "^2.10.19",
|
63
63
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
64
64
|
"@fontsource/inter": "^5.0.16",
|
65
65
|
"@fontsource/ubuntu-mono": "^5.0.18",
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import axios from 'axios';
|
2
|
+
import adapter from 'axios/lib/adapters/xhr.js';
|
3
|
+
|
4
|
+
const cache = new Map();
|
5
|
+
const EXPIRATION_TIME_MS = 10 * 60 * 1000; // 10 minutes
|
6
|
+
|
7
|
+
const cacheAdapterEnhancer = (config) => {
|
8
|
+
const { url, method } = config;
|
9
|
+
const cacheKey = JSON.stringify({ url, method });
|
10
|
+
|
11
|
+
if (cache.has(cacheKey)) {
|
12
|
+
const cachedResult = cache.get(cacheKey);
|
13
|
+
if (Date.now() - cachedResult.timestamp < EXPIRATION_TIME_MS) {
|
14
|
+
if (cachedResult.error) {
|
15
|
+
return Promise.reject(cachedResult.error);
|
16
|
+
}
|
17
|
+
|
18
|
+
return Promise.resolve({ headers: cachedResult.headers });
|
19
|
+
}
|
20
|
+
|
21
|
+
cache.delete(cacheKey);
|
22
|
+
}
|
23
|
+
|
24
|
+
return adapter(config)
|
25
|
+
.then((response) => {
|
26
|
+
// cache headers
|
27
|
+
cache.set(cacheKey, { headers: response.headers, timestamp: Date.now() });
|
28
|
+
return response;
|
29
|
+
})
|
30
|
+
.catch((error) => {
|
31
|
+
// cache error
|
32
|
+
cache.set(cacheKey, { error, timestamp: Date.now() });
|
33
|
+
throw error;
|
34
|
+
});
|
35
|
+
};
|
36
|
+
|
37
|
+
const instance = axios.create({
|
38
|
+
adapter: cacheAdapterEnhancer,
|
39
|
+
timeout: 5000,
|
40
|
+
});
|
41
|
+
|
42
|
+
export default instance;
|
package/src/NFTDisplay/index.js
CHANGED
@@ -15,6 +15,7 @@ import InlineSvgEmbedder from './svg-embedder/inline-svg';
|
|
15
15
|
import DefaultLoading from './loading';
|
16
16
|
import DefaultBrokenImage from './broken';
|
17
17
|
import { styled } from '../Theme';
|
18
|
+
import displayApi from './displayApi';
|
18
19
|
|
19
20
|
/**
|
20
21
|
* 从 assetState 中获取 nft data, 兼容新旧两种类型的数据结构, 建议将该方法的返回值传入 NFTDisplay 组件的 data prop
|
@@ -134,13 +135,20 @@ function NFTDisplay({
|
|
134
135
|
// get url content type
|
135
136
|
const getUrlContentType = async () => {
|
136
137
|
try {
|
137
|
-
const response = await
|
138
|
+
const response = await displayApi({
|
139
|
+
url: getFullContentUrl({ useImageFilter: false, t: 'nftdisplay' }),
|
138
140
|
method: 'HEAD',
|
139
141
|
});
|
140
|
-
const contentType = response
|
142
|
+
const contentType = response?.headers?.get('Content-Type');
|
141
143
|
setState({ ...state, loadingUrlType: false, urlType: contentType });
|
142
144
|
} catch (error) {
|
143
145
|
console.error('Failed to fetch url content type', error);
|
146
|
+
// display an error message when timeout occurs to avoid repeated waiting.
|
147
|
+
if (error?.message?.includes('timeout')) {
|
148
|
+
setState({ ...state, loadingUrlType: false, loading: false, error: true });
|
149
|
+
return;
|
150
|
+
}
|
151
|
+
|
144
152
|
setState({ ...state, loadingUrlType: false, urlType: null });
|
145
153
|
}
|
146
154
|
};
|
@@ -201,7 +209,7 @@ function NFTDisplay({
|
|
201
209
|
data={url}
|
202
210
|
onErrorCapture={onError}
|
203
211
|
onLoad={onLoad}
|
204
|
-
style={{ width: '
|
212
|
+
style={{ width: '100%', height: '100%', pointerEvents: 'none' }}
|
205
213
|
/>
|
206
214
|
);
|
207
215
|
};
|