haiku-react-ui 1.0.0 → 1.0.1
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/dist/index.cjs +1854 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +1846 -17
- package/dist/index.js.map +1 -1
- package/dist/styles.css +27 -0
- package/dist/styles.css.map +1 -1
- package/package.json +78 -66
package/dist/index.js
CHANGED
|
@@ -1,15 +1,1404 @@
|
|
|
1
1
|
import { cva } from 'class-variance-authority';
|
|
2
2
|
import { clsx } from 'clsx';
|
|
3
3
|
import { twMerge } from 'tailwind-merge';
|
|
4
|
-
import { Icon } from '@iconify/react';
|
|
5
|
-
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
6
4
|
import * as React2 from 'react';
|
|
7
|
-
import { useState, useId, useRef, useCallback
|
|
5
|
+
import { forwardRef, useState, useEffect, createElement, useId, useRef, useCallback } from 'react';
|
|
6
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
8
7
|
|
|
9
8
|
// src/components/Button/button.tsx
|
|
10
9
|
function cn(...inputs) {
|
|
11
10
|
return twMerge(clsx(inputs));
|
|
12
11
|
}
|
|
12
|
+
function getIconsTree(data, names) {
|
|
13
|
+
const icons = data.icons;
|
|
14
|
+
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
|
|
15
|
+
const resolved = /* @__PURE__ */ Object.create(null);
|
|
16
|
+
function resolve(name) {
|
|
17
|
+
if (icons[name]) return resolved[name] = [];
|
|
18
|
+
if (!(name in resolved)) {
|
|
19
|
+
resolved[name] = null;
|
|
20
|
+
const parent = aliases[name] && aliases[name].parent;
|
|
21
|
+
const value = parent && resolve(parent);
|
|
22
|
+
if (value) resolved[name] = [parent].concat(value);
|
|
23
|
+
}
|
|
24
|
+
return resolved[name];
|
|
25
|
+
}
|
|
26
|
+
Object.keys(icons).concat(Object.keys(aliases)).forEach(resolve);
|
|
27
|
+
return resolved;
|
|
28
|
+
}
|
|
29
|
+
var defaultIconDimensions = Object.freeze({
|
|
30
|
+
left: 0,
|
|
31
|
+
top: 0,
|
|
32
|
+
width: 16,
|
|
33
|
+
height: 16
|
|
34
|
+
});
|
|
35
|
+
var defaultIconTransformations = Object.freeze({
|
|
36
|
+
rotate: 0,
|
|
37
|
+
vFlip: false,
|
|
38
|
+
hFlip: false
|
|
39
|
+
});
|
|
40
|
+
var defaultIconProps = Object.freeze({
|
|
41
|
+
...defaultIconDimensions,
|
|
42
|
+
...defaultIconTransformations
|
|
43
|
+
});
|
|
44
|
+
var defaultExtendedIconProps = Object.freeze({
|
|
45
|
+
...defaultIconProps,
|
|
46
|
+
body: "",
|
|
47
|
+
hidden: false
|
|
48
|
+
});
|
|
49
|
+
function mergeIconTransformations(obj1, obj2) {
|
|
50
|
+
const result = {};
|
|
51
|
+
if (!obj1.hFlip !== !obj2.hFlip) result.hFlip = true;
|
|
52
|
+
if (!obj1.vFlip !== !obj2.vFlip) result.vFlip = true;
|
|
53
|
+
const rotate = ((obj1.rotate || 0) + (obj2.rotate || 0)) % 4;
|
|
54
|
+
if (rotate) result.rotate = rotate;
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
function mergeIconData(parent, child) {
|
|
58
|
+
const result = mergeIconTransformations(parent, child);
|
|
59
|
+
for (const key in defaultExtendedIconProps) if (key in defaultIconTransformations) {
|
|
60
|
+
if (key in parent && !(key in result)) result[key] = defaultIconTransformations[key];
|
|
61
|
+
} else if (key in child) result[key] = child[key];
|
|
62
|
+
else if (key in parent) result[key] = parent[key];
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
function internalGetIconData(data, name, tree) {
|
|
66
|
+
const icons = data.icons;
|
|
67
|
+
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
|
|
68
|
+
let currentProps = {};
|
|
69
|
+
function parse(name$1) {
|
|
70
|
+
currentProps = mergeIconData(icons[name$1] || aliases[name$1], currentProps);
|
|
71
|
+
}
|
|
72
|
+
parse(name);
|
|
73
|
+
tree.forEach(parse);
|
|
74
|
+
return mergeIconData(data, currentProps);
|
|
75
|
+
}
|
|
76
|
+
function parseIconSet(data, callback) {
|
|
77
|
+
const names = [];
|
|
78
|
+
if (typeof data !== "object" || typeof data.icons !== "object") return names;
|
|
79
|
+
if (data.not_found instanceof Array) data.not_found.forEach((name) => {
|
|
80
|
+
callback(name, null);
|
|
81
|
+
names.push(name);
|
|
82
|
+
});
|
|
83
|
+
const tree = getIconsTree(data);
|
|
84
|
+
for (const name in tree) {
|
|
85
|
+
const item = tree[name];
|
|
86
|
+
if (item) {
|
|
87
|
+
callback(name, internalGetIconData(data, name, item));
|
|
88
|
+
names.push(name);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return names;
|
|
92
|
+
}
|
|
93
|
+
var optionalPropertyDefaults = {
|
|
94
|
+
provider: "",
|
|
95
|
+
aliases: {},
|
|
96
|
+
not_found: {},
|
|
97
|
+
...defaultIconDimensions
|
|
98
|
+
};
|
|
99
|
+
function checkOptionalProps(item, defaults) {
|
|
100
|
+
for (const prop in defaults) if (prop in item && typeof item[prop] !== typeof defaults[prop]) return false;
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
function quicklyValidateIconSet(obj) {
|
|
104
|
+
if (typeof obj !== "object" || obj === null) return null;
|
|
105
|
+
const data = obj;
|
|
106
|
+
if (typeof data.prefix !== "string" || !obj.icons || typeof obj.icons !== "object") return null;
|
|
107
|
+
if (!checkOptionalProps(obj, optionalPropertyDefaults)) return null;
|
|
108
|
+
const icons = data.icons;
|
|
109
|
+
for (const name in icons) {
|
|
110
|
+
const icon = icons[name];
|
|
111
|
+
if (!name || typeof icon.body !== "string" || !checkOptionalProps(icon, defaultExtendedIconProps)) return null;
|
|
112
|
+
}
|
|
113
|
+
const aliases = data.aliases || /* @__PURE__ */ Object.create(null);
|
|
114
|
+
for (const name in aliases) {
|
|
115
|
+
const icon = aliases[name];
|
|
116
|
+
const parent = icon.parent;
|
|
117
|
+
if (!name || typeof parent !== "string" || !icons[parent] && !aliases[parent] || !checkOptionalProps(icon, defaultExtendedIconProps)) return null;
|
|
118
|
+
}
|
|
119
|
+
return data;
|
|
120
|
+
}
|
|
121
|
+
var dataStorage = /* @__PURE__ */ Object.create(null);
|
|
122
|
+
function newStorage(provider, prefix) {
|
|
123
|
+
return {
|
|
124
|
+
provider,
|
|
125
|
+
prefix,
|
|
126
|
+
icons: /* @__PURE__ */ Object.create(null),
|
|
127
|
+
missing: /* @__PURE__ */ new Set()
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function getStorage(provider, prefix) {
|
|
131
|
+
const providerStorage = dataStorage[provider] || (dataStorage[provider] = /* @__PURE__ */ Object.create(null));
|
|
132
|
+
return providerStorage[prefix] || (providerStorage[prefix] = newStorage(provider, prefix));
|
|
133
|
+
}
|
|
134
|
+
function addIconSet(storage2, data) {
|
|
135
|
+
if (!quicklyValidateIconSet(data)) return [];
|
|
136
|
+
return parseIconSet(data, (name, icon) => {
|
|
137
|
+
if (icon) storage2.icons[name] = icon;
|
|
138
|
+
else storage2.missing.add(name);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
function addIconToStorage(storage2, name, icon) {
|
|
142
|
+
try {
|
|
143
|
+
if (typeof icon.body === "string") {
|
|
144
|
+
storage2.icons[name] = { ...icon };
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
} catch (err) {
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
var matchIconName = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
152
|
+
var stringToIcon = (value, validate, allowSimpleName, provider = "") => {
|
|
153
|
+
const colonSeparated = value.split(":");
|
|
154
|
+
if (value.slice(0, 1) === "@") {
|
|
155
|
+
if (colonSeparated.length < 2 || colonSeparated.length > 3) return null;
|
|
156
|
+
provider = colonSeparated.shift().slice(1);
|
|
157
|
+
}
|
|
158
|
+
if (colonSeparated.length > 3 || !colonSeparated.length) return null;
|
|
159
|
+
if (colonSeparated.length > 1) {
|
|
160
|
+
const name$1 = colonSeparated.pop();
|
|
161
|
+
const prefix = colonSeparated.pop();
|
|
162
|
+
const result = {
|
|
163
|
+
provider: colonSeparated.length > 0 ? colonSeparated[0] : provider,
|
|
164
|
+
prefix,
|
|
165
|
+
name: name$1
|
|
166
|
+
};
|
|
167
|
+
return validate && !validateIconName(result) ? null : result;
|
|
168
|
+
}
|
|
169
|
+
const name = colonSeparated[0];
|
|
170
|
+
const dashSeparated = name.split("-");
|
|
171
|
+
if (dashSeparated.length > 1) {
|
|
172
|
+
const result = {
|
|
173
|
+
provider,
|
|
174
|
+
prefix: dashSeparated.shift(),
|
|
175
|
+
name: dashSeparated.join("-")
|
|
176
|
+
};
|
|
177
|
+
return validate && !validateIconName(result) ? null : result;
|
|
178
|
+
}
|
|
179
|
+
if (allowSimpleName && provider === "") {
|
|
180
|
+
const result = {
|
|
181
|
+
provider,
|
|
182
|
+
prefix: "",
|
|
183
|
+
name
|
|
184
|
+
};
|
|
185
|
+
return validate && !validateIconName(result, allowSimpleName) ? null : result;
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
};
|
|
189
|
+
var validateIconName = (icon, allowSimpleName) => {
|
|
190
|
+
if (!icon) return false;
|
|
191
|
+
return !!((allowSimpleName && icon.prefix === "" || !!icon.prefix) && !!icon.name);
|
|
192
|
+
};
|
|
193
|
+
var simpleNames = false;
|
|
194
|
+
function allowSimpleNames(allow) {
|
|
195
|
+
if (typeof allow === "boolean") simpleNames = allow;
|
|
196
|
+
return simpleNames;
|
|
197
|
+
}
|
|
198
|
+
function getIconData(name) {
|
|
199
|
+
const icon = typeof name === "string" ? stringToIcon(name, true, simpleNames) : name;
|
|
200
|
+
if (icon) {
|
|
201
|
+
const storage2 = getStorage(icon.provider, icon.prefix);
|
|
202
|
+
const iconName = icon.name;
|
|
203
|
+
return storage2.icons[iconName] || (storage2.missing.has(iconName) ? null : void 0);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function addIcon(name, data) {
|
|
207
|
+
const icon = stringToIcon(name, true, simpleNames);
|
|
208
|
+
if (!icon) return false;
|
|
209
|
+
const storage2 = getStorage(icon.provider, icon.prefix);
|
|
210
|
+
if (data) return addIconToStorage(storage2, icon.name, data);
|
|
211
|
+
else {
|
|
212
|
+
storage2.missing.add(icon.name);
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function addCollection(data, provider) {
|
|
217
|
+
if (typeof data !== "object") return false;
|
|
218
|
+
if (typeof provider !== "string") provider = data.provider || "";
|
|
219
|
+
if (simpleNames && !provider && !data.prefix) {
|
|
220
|
+
let added = false;
|
|
221
|
+
if (quicklyValidateIconSet(data)) {
|
|
222
|
+
data.prefix = "";
|
|
223
|
+
parseIconSet(data, (name, icon) => {
|
|
224
|
+
if (addIcon(name, icon)) added = true;
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return added;
|
|
228
|
+
}
|
|
229
|
+
const prefix = data.prefix;
|
|
230
|
+
if (!validateIconName({
|
|
231
|
+
prefix,
|
|
232
|
+
name: "a"
|
|
233
|
+
})) return false;
|
|
234
|
+
const storage2 = getStorage(provider, prefix);
|
|
235
|
+
return !!addIconSet(storage2, data);
|
|
236
|
+
}
|
|
237
|
+
var defaultIconSizeCustomisations = Object.freeze({
|
|
238
|
+
width: null,
|
|
239
|
+
height: null
|
|
240
|
+
});
|
|
241
|
+
var defaultIconCustomisations = Object.freeze({
|
|
242
|
+
...defaultIconSizeCustomisations,
|
|
243
|
+
...defaultIconTransformations
|
|
244
|
+
});
|
|
245
|
+
var unitsSplit = /(-?[0-9.]*[0-9]+[0-9.]*)/g;
|
|
246
|
+
var unitsTest = /^-?[0-9.]*[0-9]+[0-9.]*$/g;
|
|
247
|
+
function calculateSize(size, ratio, precision) {
|
|
248
|
+
if (ratio === 1) return size;
|
|
249
|
+
precision = precision || 100;
|
|
250
|
+
if (typeof size === "number") return Math.ceil(size * ratio * precision) / precision;
|
|
251
|
+
if (typeof size !== "string") return size;
|
|
252
|
+
const oldParts = size.split(unitsSplit);
|
|
253
|
+
if (oldParts === null || !oldParts.length) return size;
|
|
254
|
+
const newParts = [];
|
|
255
|
+
let code = oldParts.shift();
|
|
256
|
+
let isNumber2 = unitsTest.test(code);
|
|
257
|
+
while (true) {
|
|
258
|
+
if (isNumber2) {
|
|
259
|
+
const num = parseFloat(code);
|
|
260
|
+
if (isNaN(num)) newParts.push(code);
|
|
261
|
+
else newParts.push(Math.ceil(num * ratio * precision) / precision);
|
|
262
|
+
} else newParts.push(code);
|
|
263
|
+
code = oldParts.shift();
|
|
264
|
+
if (code === void 0) return newParts.join("");
|
|
265
|
+
isNumber2 = !isNumber2;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function splitSVGDefs(content, tag = "defs") {
|
|
269
|
+
let defs = "";
|
|
270
|
+
const index = content.indexOf("<" + tag);
|
|
271
|
+
while (index >= 0) {
|
|
272
|
+
const start = content.indexOf(">", index);
|
|
273
|
+
const end = content.indexOf("</" + tag);
|
|
274
|
+
if (start === -1 || end === -1) break;
|
|
275
|
+
const endEnd = content.indexOf(">", end);
|
|
276
|
+
if (endEnd === -1) break;
|
|
277
|
+
defs += content.slice(start + 1, end).trim();
|
|
278
|
+
content = content.slice(0, index).trim() + content.slice(endEnd + 1);
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
defs,
|
|
282
|
+
content
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
function mergeDefsAndContent(defs, content) {
|
|
286
|
+
return defs ? "<defs>" + defs + "</defs>" + content : content;
|
|
287
|
+
}
|
|
288
|
+
function wrapSVGContent(body, start, end) {
|
|
289
|
+
const split = splitSVGDefs(body);
|
|
290
|
+
return mergeDefsAndContent(split.defs, start + split.content + end);
|
|
291
|
+
}
|
|
292
|
+
var isUnsetKeyword = (value) => value === "unset" || value === "undefined" || value === "none";
|
|
293
|
+
function iconToSVG(icon, customisations) {
|
|
294
|
+
const fullIcon = {
|
|
295
|
+
...defaultIconProps,
|
|
296
|
+
...icon
|
|
297
|
+
};
|
|
298
|
+
const fullCustomisations = {
|
|
299
|
+
...defaultIconCustomisations,
|
|
300
|
+
...customisations
|
|
301
|
+
};
|
|
302
|
+
const box = {
|
|
303
|
+
left: fullIcon.left,
|
|
304
|
+
top: fullIcon.top,
|
|
305
|
+
width: fullIcon.width,
|
|
306
|
+
height: fullIcon.height
|
|
307
|
+
};
|
|
308
|
+
let body = fullIcon.body;
|
|
309
|
+
[fullIcon, fullCustomisations].forEach((props) => {
|
|
310
|
+
const transformations = [];
|
|
311
|
+
const hFlip = props.hFlip;
|
|
312
|
+
const vFlip = props.vFlip;
|
|
313
|
+
let rotation = props.rotate;
|
|
314
|
+
if (hFlip) if (vFlip) rotation += 2;
|
|
315
|
+
else {
|
|
316
|
+
transformations.push("translate(" + (box.width + box.left).toString() + " " + (0 - box.top).toString() + ")");
|
|
317
|
+
transformations.push("scale(-1 1)");
|
|
318
|
+
box.top = box.left = 0;
|
|
319
|
+
}
|
|
320
|
+
else if (vFlip) {
|
|
321
|
+
transformations.push("translate(" + (0 - box.left).toString() + " " + (box.height + box.top).toString() + ")");
|
|
322
|
+
transformations.push("scale(1 -1)");
|
|
323
|
+
box.top = box.left = 0;
|
|
324
|
+
}
|
|
325
|
+
let tempValue;
|
|
326
|
+
if (rotation < 0) rotation -= Math.floor(rotation / 4) * 4;
|
|
327
|
+
rotation = rotation % 4;
|
|
328
|
+
switch (rotation) {
|
|
329
|
+
case 1:
|
|
330
|
+
tempValue = box.height / 2 + box.top;
|
|
331
|
+
transformations.unshift("rotate(90 " + tempValue.toString() + " " + tempValue.toString() + ")");
|
|
332
|
+
break;
|
|
333
|
+
case 2:
|
|
334
|
+
transformations.unshift("rotate(180 " + (box.width / 2 + box.left).toString() + " " + (box.height / 2 + box.top).toString() + ")");
|
|
335
|
+
break;
|
|
336
|
+
case 3:
|
|
337
|
+
tempValue = box.width / 2 + box.left;
|
|
338
|
+
transformations.unshift("rotate(-90 " + tempValue.toString() + " " + tempValue.toString() + ")");
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
if (rotation % 2 === 1) {
|
|
342
|
+
if (box.left !== box.top) {
|
|
343
|
+
tempValue = box.left;
|
|
344
|
+
box.left = box.top;
|
|
345
|
+
box.top = tempValue;
|
|
346
|
+
}
|
|
347
|
+
if (box.width !== box.height) {
|
|
348
|
+
tempValue = box.width;
|
|
349
|
+
box.width = box.height;
|
|
350
|
+
box.height = tempValue;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
if (transformations.length) body = wrapSVGContent(body, '<g transform="' + transformations.join(" ") + '">', "</g>");
|
|
354
|
+
});
|
|
355
|
+
const customisationsWidth = fullCustomisations.width;
|
|
356
|
+
const customisationsHeight = fullCustomisations.height;
|
|
357
|
+
const boxWidth = box.width;
|
|
358
|
+
const boxHeight = box.height;
|
|
359
|
+
let width;
|
|
360
|
+
let height;
|
|
361
|
+
if (customisationsWidth === null) {
|
|
362
|
+
height = customisationsHeight === null ? "1em" : customisationsHeight === "auto" ? boxHeight : customisationsHeight;
|
|
363
|
+
width = calculateSize(height, boxWidth / boxHeight);
|
|
364
|
+
} else {
|
|
365
|
+
width = customisationsWidth === "auto" ? boxWidth : customisationsWidth;
|
|
366
|
+
height = customisationsHeight === null ? calculateSize(width, boxHeight / boxWidth) : customisationsHeight === "auto" ? boxHeight : customisationsHeight;
|
|
367
|
+
}
|
|
368
|
+
const attributes = {};
|
|
369
|
+
const setAttr = (prop, value) => {
|
|
370
|
+
if (!isUnsetKeyword(value)) attributes[prop] = value.toString();
|
|
371
|
+
};
|
|
372
|
+
setAttr("width", width);
|
|
373
|
+
setAttr("height", height);
|
|
374
|
+
const viewBox = [
|
|
375
|
+
box.left,
|
|
376
|
+
box.top,
|
|
377
|
+
boxWidth,
|
|
378
|
+
boxHeight
|
|
379
|
+
];
|
|
380
|
+
attributes.viewBox = viewBox.join(" ");
|
|
381
|
+
return {
|
|
382
|
+
attributes,
|
|
383
|
+
viewBox,
|
|
384
|
+
body
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
var regex = /\sid="(\S+)"/g;
|
|
388
|
+
var randomPrefix = "IconifyId" + Date.now().toString(16) + (Math.random() * 16777216 | 0).toString(16);
|
|
389
|
+
var counter = 0;
|
|
390
|
+
function replaceIDs(body, prefix = randomPrefix) {
|
|
391
|
+
const ids = [];
|
|
392
|
+
let match;
|
|
393
|
+
while (match = regex.exec(body)) ids.push(match[1]);
|
|
394
|
+
if (!ids.length) return body;
|
|
395
|
+
const suffix = "suffix" + (Math.random() * 16777216 | Date.now()).toString(16);
|
|
396
|
+
ids.forEach((id) => {
|
|
397
|
+
const newID = typeof prefix === "function" ? prefix(id) : prefix + (counter++).toString();
|
|
398
|
+
const escapedID = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
399
|
+
body = body.replace(new RegExp('([#;"])(' + escapedID + ')([")]|\\.[a-z])', "g"), "$1" + newID + suffix + "$3");
|
|
400
|
+
});
|
|
401
|
+
body = body.replace(new RegExp(suffix, "g"), "");
|
|
402
|
+
return body;
|
|
403
|
+
}
|
|
404
|
+
var storage = /* @__PURE__ */ Object.create(null);
|
|
405
|
+
function setAPIModule(provider, item) {
|
|
406
|
+
storage[provider] = item;
|
|
407
|
+
}
|
|
408
|
+
function getAPIModule(provider) {
|
|
409
|
+
return storage[provider] || storage[""];
|
|
410
|
+
}
|
|
411
|
+
function createAPIConfig(source) {
|
|
412
|
+
let resources;
|
|
413
|
+
if (typeof source.resources === "string") resources = [source.resources];
|
|
414
|
+
else {
|
|
415
|
+
resources = source.resources;
|
|
416
|
+
if (!(resources instanceof Array) || !resources.length) return null;
|
|
417
|
+
}
|
|
418
|
+
const result = {
|
|
419
|
+
resources,
|
|
420
|
+
path: source.path || "/",
|
|
421
|
+
maxURL: source.maxURL || 500,
|
|
422
|
+
rotate: source.rotate || 750,
|
|
423
|
+
timeout: source.timeout || 5e3,
|
|
424
|
+
random: source.random === true,
|
|
425
|
+
index: source.index || 0,
|
|
426
|
+
dataAfterTimeout: source.dataAfterTimeout !== false
|
|
427
|
+
};
|
|
428
|
+
return result;
|
|
429
|
+
}
|
|
430
|
+
var configStorage = /* @__PURE__ */ Object.create(null);
|
|
431
|
+
var fallBackAPISources = ["https://api.simplesvg.com", "https://api.unisvg.com"];
|
|
432
|
+
var fallBackAPI = [];
|
|
433
|
+
while (fallBackAPISources.length > 0) if (fallBackAPISources.length === 1) fallBackAPI.push(fallBackAPISources.shift());
|
|
434
|
+
else if (Math.random() > 0.5) fallBackAPI.push(fallBackAPISources.shift());
|
|
435
|
+
else fallBackAPI.push(fallBackAPISources.pop());
|
|
436
|
+
configStorage[""] = createAPIConfig({ resources: ["https://api.iconify.design"].concat(fallBackAPI) });
|
|
437
|
+
function addAPIProvider(provider, customConfig) {
|
|
438
|
+
const config = createAPIConfig(customConfig);
|
|
439
|
+
if (config === null) return false;
|
|
440
|
+
configStorage[provider] = config;
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
function getAPIConfig(provider) {
|
|
444
|
+
return configStorage[provider];
|
|
445
|
+
}
|
|
446
|
+
var detectFetch = () => {
|
|
447
|
+
let callback;
|
|
448
|
+
try {
|
|
449
|
+
callback = fetch;
|
|
450
|
+
if (typeof callback === "function") return callback;
|
|
451
|
+
} catch (err) {
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
var fetchModule = detectFetch();
|
|
455
|
+
function calculateMaxLength(provider, prefix) {
|
|
456
|
+
const config = getAPIConfig(provider);
|
|
457
|
+
if (!config) return 0;
|
|
458
|
+
let result;
|
|
459
|
+
if (!config.maxURL) result = 0;
|
|
460
|
+
else {
|
|
461
|
+
let maxHostLength = 0;
|
|
462
|
+
config.resources.forEach((item) => {
|
|
463
|
+
const host = item;
|
|
464
|
+
maxHostLength = Math.max(maxHostLength, host.length);
|
|
465
|
+
});
|
|
466
|
+
const url = prefix + ".json?icons=";
|
|
467
|
+
result = config.maxURL - maxHostLength - config.path.length - url.length;
|
|
468
|
+
}
|
|
469
|
+
return result;
|
|
470
|
+
}
|
|
471
|
+
function shouldAbort(status) {
|
|
472
|
+
return status === 404;
|
|
473
|
+
}
|
|
474
|
+
var prepare = (provider, prefix, icons) => {
|
|
475
|
+
const results = [];
|
|
476
|
+
const maxLength = calculateMaxLength(provider, prefix);
|
|
477
|
+
const type = "icons";
|
|
478
|
+
let item = {
|
|
479
|
+
type,
|
|
480
|
+
provider,
|
|
481
|
+
prefix,
|
|
482
|
+
icons: []
|
|
483
|
+
};
|
|
484
|
+
let length = 0;
|
|
485
|
+
icons.forEach((name, index) => {
|
|
486
|
+
length += name.length + 1;
|
|
487
|
+
if (length >= maxLength && index > 0) {
|
|
488
|
+
results.push(item);
|
|
489
|
+
item = {
|
|
490
|
+
type,
|
|
491
|
+
provider,
|
|
492
|
+
prefix,
|
|
493
|
+
icons: []
|
|
494
|
+
};
|
|
495
|
+
length = name.length;
|
|
496
|
+
}
|
|
497
|
+
item.icons.push(name);
|
|
498
|
+
});
|
|
499
|
+
results.push(item);
|
|
500
|
+
return results;
|
|
501
|
+
};
|
|
502
|
+
function getPath(provider) {
|
|
503
|
+
if (typeof provider === "string") {
|
|
504
|
+
const config = getAPIConfig(provider);
|
|
505
|
+
if (config) return config.path;
|
|
506
|
+
}
|
|
507
|
+
return "/";
|
|
508
|
+
}
|
|
509
|
+
var send = (host, params, callback) => {
|
|
510
|
+
if (!fetchModule) {
|
|
511
|
+
callback("abort", 424);
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
let path = getPath(params.provider);
|
|
515
|
+
switch (params.type) {
|
|
516
|
+
case "icons": {
|
|
517
|
+
const prefix = params.prefix;
|
|
518
|
+
const icons = params.icons;
|
|
519
|
+
const iconsList = icons.join(",");
|
|
520
|
+
const urlParams = new URLSearchParams({ icons: iconsList });
|
|
521
|
+
path += prefix + ".json?" + urlParams.toString();
|
|
522
|
+
break;
|
|
523
|
+
}
|
|
524
|
+
case "custom": {
|
|
525
|
+
const uri = params.uri;
|
|
526
|
+
path += uri.slice(0, 1) === "/" ? uri.slice(1) : uri;
|
|
527
|
+
break;
|
|
528
|
+
}
|
|
529
|
+
default:
|
|
530
|
+
callback("abort", 400);
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
let defaultError = 503;
|
|
534
|
+
fetchModule(host + path).then((response) => {
|
|
535
|
+
const status = response.status;
|
|
536
|
+
if (status !== 200) {
|
|
537
|
+
setTimeout(() => {
|
|
538
|
+
callback(shouldAbort(status) ? "abort" : "next", status);
|
|
539
|
+
});
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
defaultError = 501;
|
|
543
|
+
return response.json();
|
|
544
|
+
}).then((data) => {
|
|
545
|
+
if (typeof data !== "object" || data === null) {
|
|
546
|
+
setTimeout(() => {
|
|
547
|
+
if (data === 404) callback("abort", data);
|
|
548
|
+
else callback("next", defaultError);
|
|
549
|
+
});
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
setTimeout(() => {
|
|
553
|
+
callback("success", data);
|
|
554
|
+
});
|
|
555
|
+
}).catch(() => {
|
|
556
|
+
callback("next", defaultError);
|
|
557
|
+
});
|
|
558
|
+
};
|
|
559
|
+
var fetchAPIModule = {
|
|
560
|
+
prepare,
|
|
561
|
+
send
|
|
562
|
+
};
|
|
563
|
+
function removeCallback(storages, id) {
|
|
564
|
+
storages.forEach((storage2) => {
|
|
565
|
+
const items = storage2.loaderCallbacks;
|
|
566
|
+
if (items) storage2.loaderCallbacks = items.filter((row) => row.id !== id);
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
function updateCallbacks(storage2) {
|
|
570
|
+
if (!storage2.pendingCallbacksFlag) {
|
|
571
|
+
storage2.pendingCallbacksFlag = true;
|
|
572
|
+
setTimeout(() => {
|
|
573
|
+
storage2.pendingCallbacksFlag = false;
|
|
574
|
+
const items = storage2.loaderCallbacks ? storage2.loaderCallbacks.slice(0) : [];
|
|
575
|
+
if (!items.length) return;
|
|
576
|
+
let hasPending = false;
|
|
577
|
+
const provider = storage2.provider;
|
|
578
|
+
const prefix = storage2.prefix;
|
|
579
|
+
items.forEach((item) => {
|
|
580
|
+
const icons = item.icons;
|
|
581
|
+
const oldLength = icons.pending.length;
|
|
582
|
+
icons.pending = icons.pending.filter((icon) => {
|
|
583
|
+
if (icon.prefix !== prefix) return true;
|
|
584
|
+
const name = icon.name;
|
|
585
|
+
if (storage2.icons[name]) icons.loaded.push({
|
|
586
|
+
provider,
|
|
587
|
+
prefix,
|
|
588
|
+
name
|
|
589
|
+
});
|
|
590
|
+
else if (storage2.missing.has(name)) icons.missing.push({
|
|
591
|
+
provider,
|
|
592
|
+
prefix,
|
|
593
|
+
name
|
|
594
|
+
});
|
|
595
|
+
else {
|
|
596
|
+
hasPending = true;
|
|
597
|
+
return true;
|
|
598
|
+
}
|
|
599
|
+
return false;
|
|
600
|
+
});
|
|
601
|
+
if (icons.pending.length !== oldLength) {
|
|
602
|
+
if (!hasPending) removeCallback([storage2], item.id);
|
|
603
|
+
item.callback(icons.loaded.slice(0), icons.missing.slice(0), icons.pending.slice(0), item.abort);
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
var idCounter = 0;
|
|
610
|
+
function storeCallback(callback, icons, pendingSources) {
|
|
611
|
+
const id = idCounter++;
|
|
612
|
+
const abort = removeCallback.bind(null, pendingSources, id);
|
|
613
|
+
if (!icons.pending.length) return abort;
|
|
614
|
+
const item = {
|
|
615
|
+
id,
|
|
616
|
+
icons,
|
|
617
|
+
callback,
|
|
618
|
+
abort
|
|
619
|
+
};
|
|
620
|
+
pendingSources.forEach((storage2) => {
|
|
621
|
+
(storage2.loaderCallbacks || (storage2.loaderCallbacks = [])).push(item);
|
|
622
|
+
});
|
|
623
|
+
return abort;
|
|
624
|
+
}
|
|
625
|
+
function sortIcons(icons) {
|
|
626
|
+
const result = {
|
|
627
|
+
loaded: [],
|
|
628
|
+
missing: [],
|
|
629
|
+
pending: []
|
|
630
|
+
};
|
|
631
|
+
const storage2 = /* @__PURE__ */ Object.create(null);
|
|
632
|
+
icons.sort((a, b) => {
|
|
633
|
+
if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);
|
|
634
|
+
if (a.prefix !== b.prefix) return a.prefix.localeCompare(b.prefix);
|
|
635
|
+
return a.name.localeCompare(b.name);
|
|
636
|
+
});
|
|
637
|
+
let lastIcon = {
|
|
638
|
+
provider: "",
|
|
639
|
+
prefix: "",
|
|
640
|
+
name: ""
|
|
641
|
+
};
|
|
642
|
+
icons.forEach((icon) => {
|
|
643
|
+
if (lastIcon.name === icon.name && lastIcon.prefix === icon.prefix && lastIcon.provider === icon.provider) return;
|
|
644
|
+
lastIcon = icon;
|
|
645
|
+
const provider = icon.provider;
|
|
646
|
+
const prefix = icon.prefix;
|
|
647
|
+
const name = icon.name;
|
|
648
|
+
const providerStorage = storage2[provider] || (storage2[provider] = /* @__PURE__ */ Object.create(null));
|
|
649
|
+
const localStorage = providerStorage[prefix] || (providerStorage[prefix] = getStorage(provider, prefix));
|
|
650
|
+
let list;
|
|
651
|
+
if (name in localStorage.icons) list = result.loaded;
|
|
652
|
+
else if (prefix === "" || localStorage.missing.has(name)) list = result.missing;
|
|
653
|
+
else list = result.pending;
|
|
654
|
+
const item = {
|
|
655
|
+
provider,
|
|
656
|
+
prefix,
|
|
657
|
+
name
|
|
658
|
+
};
|
|
659
|
+
list.push(item);
|
|
660
|
+
});
|
|
661
|
+
return result;
|
|
662
|
+
}
|
|
663
|
+
function listToIcons(list, validate = true, simpleNames2 = false) {
|
|
664
|
+
const result = [];
|
|
665
|
+
list.forEach((item) => {
|
|
666
|
+
const icon = typeof item === "string" ? stringToIcon(item, validate, simpleNames2) : item;
|
|
667
|
+
if (icon) result.push(icon);
|
|
668
|
+
});
|
|
669
|
+
return result;
|
|
670
|
+
}
|
|
671
|
+
var defaultConfig = {
|
|
672
|
+
resources: [],
|
|
673
|
+
index: 0,
|
|
674
|
+
timeout: 2e3,
|
|
675
|
+
rotate: 750,
|
|
676
|
+
random: false,
|
|
677
|
+
dataAfterTimeout: false
|
|
678
|
+
};
|
|
679
|
+
function sendQuery(config, payload, query, done) {
|
|
680
|
+
const resourcesCount = config.resources.length;
|
|
681
|
+
const startIndex = config.random ? Math.floor(Math.random() * resourcesCount) : config.index;
|
|
682
|
+
let resources;
|
|
683
|
+
if (config.random) {
|
|
684
|
+
let list = config.resources.slice(0);
|
|
685
|
+
resources = [];
|
|
686
|
+
while (list.length > 1) {
|
|
687
|
+
const nextIndex = Math.floor(Math.random() * list.length);
|
|
688
|
+
resources.push(list[nextIndex]);
|
|
689
|
+
list = list.slice(0, nextIndex).concat(list.slice(nextIndex + 1));
|
|
690
|
+
}
|
|
691
|
+
resources = resources.concat(list);
|
|
692
|
+
} else resources = config.resources.slice(startIndex).concat(config.resources.slice(0, startIndex));
|
|
693
|
+
const startTime = Date.now();
|
|
694
|
+
let status = "pending";
|
|
695
|
+
let queriesSent = 0;
|
|
696
|
+
let lastError;
|
|
697
|
+
let timer = null;
|
|
698
|
+
let queue = [];
|
|
699
|
+
let doneCallbacks = [];
|
|
700
|
+
if (typeof done === "function") doneCallbacks.push(done);
|
|
701
|
+
function resetTimer() {
|
|
702
|
+
if (timer) {
|
|
703
|
+
clearTimeout(timer);
|
|
704
|
+
timer = null;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
function abort() {
|
|
708
|
+
if (status === "pending") status = "aborted";
|
|
709
|
+
resetTimer();
|
|
710
|
+
queue.forEach((item) => {
|
|
711
|
+
if (item.status === "pending") item.status = "aborted";
|
|
712
|
+
});
|
|
713
|
+
queue = [];
|
|
714
|
+
}
|
|
715
|
+
function subscribe(callback, overwrite) {
|
|
716
|
+
if (overwrite) doneCallbacks = [];
|
|
717
|
+
if (typeof callback === "function") doneCallbacks.push(callback);
|
|
718
|
+
}
|
|
719
|
+
function getQueryStatus() {
|
|
720
|
+
return {
|
|
721
|
+
startTime,
|
|
722
|
+
payload,
|
|
723
|
+
status,
|
|
724
|
+
queriesSent,
|
|
725
|
+
queriesPending: queue.length,
|
|
726
|
+
subscribe,
|
|
727
|
+
abort
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
function failQuery() {
|
|
731
|
+
status = "failed";
|
|
732
|
+
doneCallbacks.forEach((callback) => {
|
|
733
|
+
callback(void 0, lastError);
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
function clearQueue() {
|
|
737
|
+
queue.forEach((item) => {
|
|
738
|
+
if (item.status === "pending") item.status = "aborted";
|
|
739
|
+
});
|
|
740
|
+
queue = [];
|
|
741
|
+
}
|
|
742
|
+
function moduleResponse(item, response, data) {
|
|
743
|
+
const isError = response !== "success";
|
|
744
|
+
queue = queue.filter((queued) => queued !== item);
|
|
745
|
+
switch (status) {
|
|
746
|
+
case "pending":
|
|
747
|
+
break;
|
|
748
|
+
case "failed":
|
|
749
|
+
if (isError || !config.dataAfterTimeout) return;
|
|
750
|
+
break;
|
|
751
|
+
default:
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
if (response === "abort") {
|
|
755
|
+
lastError = data;
|
|
756
|
+
failQuery();
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
if (isError) {
|
|
760
|
+
lastError = data;
|
|
761
|
+
if (!queue.length) if (!resources.length) failQuery();
|
|
762
|
+
else execNext();
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
resetTimer();
|
|
766
|
+
clearQueue();
|
|
767
|
+
if (!config.random) {
|
|
768
|
+
const index = config.resources.indexOf(item.resource);
|
|
769
|
+
if (index !== -1 && index !== config.index) config.index = index;
|
|
770
|
+
}
|
|
771
|
+
status = "completed";
|
|
772
|
+
doneCallbacks.forEach((callback) => {
|
|
773
|
+
callback(data);
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
function execNext() {
|
|
777
|
+
if (status !== "pending") return;
|
|
778
|
+
resetTimer();
|
|
779
|
+
const resource = resources.shift();
|
|
780
|
+
if (resource === void 0) {
|
|
781
|
+
if (queue.length) {
|
|
782
|
+
timer = setTimeout(() => {
|
|
783
|
+
resetTimer();
|
|
784
|
+
if (status === "pending") {
|
|
785
|
+
clearQueue();
|
|
786
|
+
failQuery();
|
|
787
|
+
}
|
|
788
|
+
}, config.timeout);
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
failQuery();
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
const item = {
|
|
795
|
+
status: "pending",
|
|
796
|
+
resource,
|
|
797
|
+
callback: (status$1, data) => {
|
|
798
|
+
moduleResponse(item, status$1, data);
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
queue.push(item);
|
|
802
|
+
queriesSent++;
|
|
803
|
+
timer = setTimeout(execNext, config.rotate);
|
|
804
|
+
query(resource, payload, item.callback);
|
|
805
|
+
}
|
|
806
|
+
setTimeout(execNext);
|
|
807
|
+
return getQueryStatus;
|
|
808
|
+
}
|
|
809
|
+
function initRedundancy(cfg) {
|
|
810
|
+
const config = {
|
|
811
|
+
...defaultConfig,
|
|
812
|
+
...cfg
|
|
813
|
+
};
|
|
814
|
+
let queries = [];
|
|
815
|
+
function cleanup() {
|
|
816
|
+
queries = queries.filter((item) => item().status === "pending");
|
|
817
|
+
}
|
|
818
|
+
function query(payload, queryCallback, doneCallback) {
|
|
819
|
+
const query$1 = sendQuery(config, payload, queryCallback, (data, error) => {
|
|
820
|
+
cleanup();
|
|
821
|
+
if (doneCallback) doneCallback(data, error);
|
|
822
|
+
});
|
|
823
|
+
queries.push(query$1);
|
|
824
|
+
return query$1;
|
|
825
|
+
}
|
|
826
|
+
function find(callback) {
|
|
827
|
+
return queries.find((value) => {
|
|
828
|
+
return callback(value);
|
|
829
|
+
}) || null;
|
|
830
|
+
}
|
|
831
|
+
const instance = {
|
|
832
|
+
query,
|
|
833
|
+
find,
|
|
834
|
+
setIndex: (index) => {
|
|
835
|
+
config.index = index;
|
|
836
|
+
},
|
|
837
|
+
getIndex: () => config.index,
|
|
838
|
+
cleanup
|
|
839
|
+
};
|
|
840
|
+
return instance;
|
|
841
|
+
}
|
|
842
|
+
function emptyCallback$1() {
|
|
843
|
+
}
|
|
844
|
+
var redundancyCache = /* @__PURE__ */ Object.create(null);
|
|
845
|
+
function getRedundancyCache(provider) {
|
|
846
|
+
if (!redundancyCache[provider]) {
|
|
847
|
+
const config = getAPIConfig(provider);
|
|
848
|
+
if (!config) return;
|
|
849
|
+
const redundancy = initRedundancy(config);
|
|
850
|
+
const cachedReundancy = {
|
|
851
|
+
config,
|
|
852
|
+
redundancy
|
|
853
|
+
};
|
|
854
|
+
redundancyCache[provider] = cachedReundancy;
|
|
855
|
+
}
|
|
856
|
+
return redundancyCache[provider];
|
|
857
|
+
}
|
|
858
|
+
function sendAPIQuery(target, query, callback) {
|
|
859
|
+
let redundancy;
|
|
860
|
+
let send2;
|
|
861
|
+
if (typeof target === "string") {
|
|
862
|
+
const api = getAPIModule(target);
|
|
863
|
+
if (!api) {
|
|
864
|
+
callback(void 0, 424);
|
|
865
|
+
return emptyCallback$1;
|
|
866
|
+
}
|
|
867
|
+
send2 = api.send;
|
|
868
|
+
const cached = getRedundancyCache(target);
|
|
869
|
+
if (cached) redundancy = cached.redundancy;
|
|
870
|
+
} else {
|
|
871
|
+
const config = createAPIConfig(target);
|
|
872
|
+
if (config) {
|
|
873
|
+
redundancy = initRedundancy(config);
|
|
874
|
+
const moduleKey = target.resources ? target.resources[0] : "";
|
|
875
|
+
const api = getAPIModule(moduleKey);
|
|
876
|
+
if (api) send2 = api.send;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
if (!redundancy || !send2) {
|
|
880
|
+
callback(void 0, 424);
|
|
881
|
+
return emptyCallback$1;
|
|
882
|
+
}
|
|
883
|
+
return redundancy.query(query, send2, callback)().abort;
|
|
884
|
+
}
|
|
885
|
+
function emptyCallback() {
|
|
886
|
+
}
|
|
887
|
+
function loadedNewIcons(storage2) {
|
|
888
|
+
if (!storage2.iconsLoaderFlag) {
|
|
889
|
+
storage2.iconsLoaderFlag = true;
|
|
890
|
+
setTimeout(() => {
|
|
891
|
+
storage2.iconsLoaderFlag = false;
|
|
892
|
+
updateCallbacks(storage2);
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
function checkIconNamesForAPI(icons) {
|
|
897
|
+
const valid = [];
|
|
898
|
+
const invalid = [];
|
|
899
|
+
icons.forEach((name) => {
|
|
900
|
+
(name.match(matchIconName) ? valid : invalid).push(name);
|
|
901
|
+
});
|
|
902
|
+
return {
|
|
903
|
+
valid,
|
|
904
|
+
invalid
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
function parseLoaderResponse(storage2, icons, data) {
|
|
908
|
+
function checkMissing() {
|
|
909
|
+
const pending = storage2.pendingIcons;
|
|
910
|
+
icons.forEach((name) => {
|
|
911
|
+
if (pending) pending.delete(name);
|
|
912
|
+
if (!storage2.icons[name]) storage2.missing.add(name);
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
if (data && typeof data === "object") try {
|
|
916
|
+
const parsed = addIconSet(storage2, data);
|
|
917
|
+
if (!parsed.length) {
|
|
918
|
+
checkMissing();
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
} catch (err) {
|
|
922
|
+
console.error(err);
|
|
923
|
+
}
|
|
924
|
+
checkMissing();
|
|
925
|
+
loadedNewIcons(storage2);
|
|
926
|
+
}
|
|
927
|
+
function parsePossiblyAsyncResponse(response, callback) {
|
|
928
|
+
if (response instanceof Promise) response.then((data) => {
|
|
929
|
+
callback(data);
|
|
930
|
+
}).catch(() => {
|
|
931
|
+
callback(null);
|
|
932
|
+
});
|
|
933
|
+
else callback(response);
|
|
934
|
+
}
|
|
935
|
+
function loadNewIcons(storage2, icons) {
|
|
936
|
+
if (!storage2.iconsToLoad) storage2.iconsToLoad = icons;
|
|
937
|
+
else storage2.iconsToLoad = storage2.iconsToLoad.concat(icons).sort();
|
|
938
|
+
if (!storage2.iconsQueueFlag) {
|
|
939
|
+
storage2.iconsQueueFlag = true;
|
|
940
|
+
setTimeout(() => {
|
|
941
|
+
storage2.iconsQueueFlag = false;
|
|
942
|
+
const { provider, prefix } = storage2;
|
|
943
|
+
const icons$1 = storage2.iconsToLoad;
|
|
944
|
+
delete storage2.iconsToLoad;
|
|
945
|
+
if (!icons$1 || !icons$1.length) return;
|
|
946
|
+
const customIconLoader = storage2.loadIcon;
|
|
947
|
+
if (storage2.loadIcons && (icons$1.length > 1 || !customIconLoader)) {
|
|
948
|
+
parsePossiblyAsyncResponse(storage2.loadIcons(icons$1, prefix, provider), (data) => {
|
|
949
|
+
parseLoaderResponse(storage2, icons$1, data);
|
|
950
|
+
});
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
if (customIconLoader) {
|
|
954
|
+
icons$1.forEach((name) => {
|
|
955
|
+
const response = customIconLoader(name, prefix, provider);
|
|
956
|
+
parsePossiblyAsyncResponse(response, (data) => {
|
|
957
|
+
const iconSet = data ? {
|
|
958
|
+
prefix,
|
|
959
|
+
icons: { [name]: data }
|
|
960
|
+
} : null;
|
|
961
|
+
parseLoaderResponse(storage2, [name], iconSet);
|
|
962
|
+
});
|
|
963
|
+
});
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
const { valid, invalid } = checkIconNamesForAPI(icons$1);
|
|
967
|
+
if (invalid.length) parseLoaderResponse(storage2, invalid, null);
|
|
968
|
+
if (!valid.length) return;
|
|
969
|
+
const api = prefix.match(matchIconName) ? getAPIModule(provider) : null;
|
|
970
|
+
if (!api) {
|
|
971
|
+
parseLoaderResponse(storage2, valid, null);
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
const params = api.prepare(provider, prefix, valid);
|
|
975
|
+
params.forEach((item) => {
|
|
976
|
+
sendAPIQuery(provider, item, (data) => {
|
|
977
|
+
parseLoaderResponse(storage2, item.icons, data);
|
|
978
|
+
});
|
|
979
|
+
});
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
var loadIcons = (icons, callback) => {
|
|
984
|
+
const cleanedIcons = listToIcons(icons, true, allowSimpleNames());
|
|
985
|
+
const sortedIcons = sortIcons(cleanedIcons);
|
|
986
|
+
if (!sortedIcons.pending.length) {
|
|
987
|
+
let callCallback = true;
|
|
988
|
+
if (callback) setTimeout(() => {
|
|
989
|
+
if (callCallback) callback(sortedIcons.loaded, sortedIcons.missing, sortedIcons.pending, emptyCallback);
|
|
990
|
+
});
|
|
991
|
+
return () => {
|
|
992
|
+
callCallback = false;
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
const newIcons = /* @__PURE__ */ Object.create(null);
|
|
996
|
+
const sources = [];
|
|
997
|
+
let lastProvider, lastPrefix;
|
|
998
|
+
sortedIcons.pending.forEach((icon) => {
|
|
999
|
+
const { provider, prefix } = icon;
|
|
1000
|
+
if (prefix === lastPrefix && provider === lastProvider) return;
|
|
1001
|
+
lastProvider = provider;
|
|
1002
|
+
lastPrefix = prefix;
|
|
1003
|
+
sources.push(getStorage(provider, prefix));
|
|
1004
|
+
const providerNewIcons = newIcons[provider] || (newIcons[provider] = /* @__PURE__ */ Object.create(null));
|
|
1005
|
+
if (!providerNewIcons[prefix]) providerNewIcons[prefix] = [];
|
|
1006
|
+
});
|
|
1007
|
+
sortedIcons.pending.forEach((icon) => {
|
|
1008
|
+
const { provider, prefix, name } = icon;
|
|
1009
|
+
const storage2 = getStorage(provider, prefix);
|
|
1010
|
+
const pendingQueue = storage2.pendingIcons || (storage2.pendingIcons = /* @__PURE__ */ new Set());
|
|
1011
|
+
if (!pendingQueue.has(name)) {
|
|
1012
|
+
pendingQueue.add(name);
|
|
1013
|
+
newIcons[provider][prefix].push(name);
|
|
1014
|
+
}
|
|
1015
|
+
});
|
|
1016
|
+
sources.forEach((storage2) => {
|
|
1017
|
+
const list = newIcons[storage2.provider][storage2.prefix];
|
|
1018
|
+
if (list.length) loadNewIcons(storage2, list);
|
|
1019
|
+
});
|
|
1020
|
+
return callback ? storeCallback(callback, sortedIcons, sources) : emptyCallback;
|
|
1021
|
+
};
|
|
1022
|
+
function mergeCustomisations(defaults, item) {
|
|
1023
|
+
const result = { ...defaults };
|
|
1024
|
+
for (const key in item) {
|
|
1025
|
+
const value = item[key];
|
|
1026
|
+
const valueType = typeof value;
|
|
1027
|
+
if (key in defaultIconSizeCustomisations) {
|
|
1028
|
+
if (value === null || value && (valueType === "string" || valueType === "number")) result[key] = value;
|
|
1029
|
+
} else if (valueType === typeof result[key]) result[key] = key === "rotate" ? value % 4 : value;
|
|
1030
|
+
}
|
|
1031
|
+
return result;
|
|
1032
|
+
}
|
|
1033
|
+
var separator = /[\s,]+/;
|
|
1034
|
+
function flipFromString(custom, flip) {
|
|
1035
|
+
flip.split(separator).forEach((str) => {
|
|
1036
|
+
const value = str.trim();
|
|
1037
|
+
switch (value) {
|
|
1038
|
+
case "horizontal":
|
|
1039
|
+
custom.hFlip = true;
|
|
1040
|
+
break;
|
|
1041
|
+
case "vertical":
|
|
1042
|
+
custom.vFlip = true;
|
|
1043
|
+
break;
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
function rotateFromString(value, defaultValue = 0) {
|
|
1048
|
+
const units = value.replace(/^-?[0-9.]*/, "");
|
|
1049
|
+
function cleanup(value$1) {
|
|
1050
|
+
while (value$1 < 0) value$1 += 4;
|
|
1051
|
+
return value$1 % 4;
|
|
1052
|
+
}
|
|
1053
|
+
if (units === "") {
|
|
1054
|
+
const num = parseInt(value);
|
|
1055
|
+
return isNaN(num) ? 0 : cleanup(num);
|
|
1056
|
+
} else if (units !== value) {
|
|
1057
|
+
let split = 0;
|
|
1058
|
+
switch (units) {
|
|
1059
|
+
case "%":
|
|
1060
|
+
split = 25;
|
|
1061
|
+
break;
|
|
1062
|
+
case "deg":
|
|
1063
|
+
split = 90;
|
|
1064
|
+
}
|
|
1065
|
+
if (split) {
|
|
1066
|
+
let num = parseFloat(value.slice(0, value.length - units.length));
|
|
1067
|
+
if (isNaN(num)) return 0;
|
|
1068
|
+
num = num / split;
|
|
1069
|
+
return num % 1 === 0 ? cleanup(num) : 0;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
return defaultValue;
|
|
1073
|
+
}
|
|
1074
|
+
function iconToHTML(body, attributes) {
|
|
1075
|
+
let renderAttribsHTML = body.indexOf("xlink:") === -1 ? "" : ' xmlns:xlink="http://www.w3.org/1999/xlink"';
|
|
1076
|
+
for (const attr in attributes) renderAttribsHTML += " " + attr + '="' + attributes[attr] + '"';
|
|
1077
|
+
return '<svg xmlns="http://www.w3.org/2000/svg"' + renderAttribsHTML + ">" + body + "</svg>";
|
|
1078
|
+
}
|
|
1079
|
+
function encodeSVGforURL(svg) {
|
|
1080
|
+
return svg.replace(/"/g, "'").replace(/%/g, "%25").replace(/#/g, "%23").replace(/</g, "%3C").replace(/>/g, "%3E").replace(/\s+/g, " ");
|
|
1081
|
+
}
|
|
1082
|
+
function svgToData(svg) {
|
|
1083
|
+
return "data:image/svg+xml," + encodeSVGforURL(svg);
|
|
1084
|
+
}
|
|
1085
|
+
function svgToURL(svg) {
|
|
1086
|
+
return 'url("' + svgToData(svg) + '")';
|
|
1087
|
+
}
|
|
1088
|
+
var policy;
|
|
1089
|
+
function createPolicy() {
|
|
1090
|
+
try {
|
|
1091
|
+
policy = window.trustedTypes.createPolicy("iconify", { createHTML: (s) => s });
|
|
1092
|
+
} catch (err) {
|
|
1093
|
+
policy = null;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
function cleanUpInnerHTML(html) {
|
|
1097
|
+
if (policy === void 0) createPolicy();
|
|
1098
|
+
return policy ? policy.createHTML(html) : html;
|
|
1099
|
+
}
|
|
1100
|
+
var defaultExtendedIconCustomisations = {
|
|
1101
|
+
...defaultIconCustomisations,
|
|
1102
|
+
inline: false
|
|
1103
|
+
};
|
|
1104
|
+
var svgDefaults = {
|
|
1105
|
+
"xmlns": "http://www.w3.org/2000/svg",
|
|
1106
|
+
"xmlnsXlink": "http://www.w3.org/1999/xlink",
|
|
1107
|
+
"aria-hidden": true,
|
|
1108
|
+
"role": "img"
|
|
1109
|
+
};
|
|
1110
|
+
var commonProps = {
|
|
1111
|
+
display: "inline-block"
|
|
1112
|
+
};
|
|
1113
|
+
var monotoneProps = {
|
|
1114
|
+
backgroundColor: "currentColor"
|
|
1115
|
+
};
|
|
1116
|
+
var coloredProps = {
|
|
1117
|
+
backgroundColor: "transparent"
|
|
1118
|
+
};
|
|
1119
|
+
var propsToAdd = {
|
|
1120
|
+
Image: "var(--svg)",
|
|
1121
|
+
Repeat: "no-repeat",
|
|
1122
|
+
Size: "100% 100%"
|
|
1123
|
+
};
|
|
1124
|
+
var propsToAddTo = {
|
|
1125
|
+
WebkitMask: monotoneProps,
|
|
1126
|
+
mask: monotoneProps,
|
|
1127
|
+
background: coloredProps
|
|
1128
|
+
};
|
|
1129
|
+
for (const prefix in propsToAddTo) {
|
|
1130
|
+
const list = propsToAddTo[prefix];
|
|
1131
|
+
for (const prop in propsToAdd) {
|
|
1132
|
+
list[prefix + prop] = propsToAdd[prop];
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
var inlineDefaults = {
|
|
1136
|
+
...defaultExtendedIconCustomisations,
|
|
1137
|
+
inline: true
|
|
1138
|
+
};
|
|
1139
|
+
function fixSize(value) {
|
|
1140
|
+
return value + (value.match(/^[-0-9.]+$/) ? "px" : "");
|
|
1141
|
+
}
|
|
1142
|
+
var render = (icon, props, name) => {
|
|
1143
|
+
const defaultProps = props.inline ? inlineDefaults : defaultExtendedIconCustomisations;
|
|
1144
|
+
const customisations = mergeCustomisations(defaultProps, props);
|
|
1145
|
+
const mode = props.mode || "svg";
|
|
1146
|
+
const style = {};
|
|
1147
|
+
const customStyle = props.style || {};
|
|
1148
|
+
const componentProps = {
|
|
1149
|
+
...mode === "svg" ? svgDefaults : {}
|
|
1150
|
+
};
|
|
1151
|
+
if (name) {
|
|
1152
|
+
const iconName = stringToIcon(name, false, true);
|
|
1153
|
+
if (iconName) {
|
|
1154
|
+
const classNames = ["iconify"];
|
|
1155
|
+
const props2 = [
|
|
1156
|
+
"provider",
|
|
1157
|
+
"prefix"
|
|
1158
|
+
];
|
|
1159
|
+
for (const prop of props2) {
|
|
1160
|
+
if (iconName[prop]) {
|
|
1161
|
+
classNames.push("iconify--" + iconName[prop]);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
componentProps.className = classNames.join(" ");
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
for (let key in props) {
|
|
1168
|
+
const value = props[key];
|
|
1169
|
+
if (value === void 0) {
|
|
1170
|
+
continue;
|
|
1171
|
+
}
|
|
1172
|
+
switch (key) {
|
|
1173
|
+
// Properties to ignore
|
|
1174
|
+
case "icon":
|
|
1175
|
+
case "style":
|
|
1176
|
+
case "children":
|
|
1177
|
+
case "onLoad":
|
|
1178
|
+
case "mode":
|
|
1179
|
+
case "ssr":
|
|
1180
|
+
case "fallback":
|
|
1181
|
+
break;
|
|
1182
|
+
// Forward ref
|
|
1183
|
+
case "_ref":
|
|
1184
|
+
componentProps.ref = value;
|
|
1185
|
+
break;
|
|
1186
|
+
// Merge class names
|
|
1187
|
+
case "className":
|
|
1188
|
+
componentProps[key] = (componentProps[key] ? componentProps[key] + " " : "") + value;
|
|
1189
|
+
break;
|
|
1190
|
+
// Boolean attributes
|
|
1191
|
+
case "inline":
|
|
1192
|
+
case "hFlip":
|
|
1193
|
+
case "vFlip":
|
|
1194
|
+
customisations[key] = value === true || value === "true" || value === 1;
|
|
1195
|
+
break;
|
|
1196
|
+
// Flip as string: 'horizontal,vertical'
|
|
1197
|
+
case "flip":
|
|
1198
|
+
if (typeof value === "string") {
|
|
1199
|
+
flipFromString(customisations, value);
|
|
1200
|
+
}
|
|
1201
|
+
break;
|
|
1202
|
+
// Color: copy to style
|
|
1203
|
+
case "color":
|
|
1204
|
+
style.color = value;
|
|
1205
|
+
break;
|
|
1206
|
+
// Rotation as string
|
|
1207
|
+
case "rotate":
|
|
1208
|
+
if (typeof value === "string") {
|
|
1209
|
+
customisations[key] = rotateFromString(value);
|
|
1210
|
+
} else if (typeof value === "number") {
|
|
1211
|
+
customisations[key] = value;
|
|
1212
|
+
}
|
|
1213
|
+
break;
|
|
1214
|
+
// Remove aria-hidden
|
|
1215
|
+
case "ariaHidden":
|
|
1216
|
+
case "aria-hidden":
|
|
1217
|
+
if (value !== true && value !== "true") {
|
|
1218
|
+
delete componentProps["aria-hidden"];
|
|
1219
|
+
}
|
|
1220
|
+
break;
|
|
1221
|
+
// Copy missing property if it does not exist in customisations
|
|
1222
|
+
default:
|
|
1223
|
+
if (defaultProps[key] === void 0) {
|
|
1224
|
+
componentProps[key] = value;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
const item = iconToSVG(icon, customisations);
|
|
1229
|
+
const renderAttribs = item.attributes;
|
|
1230
|
+
if (customisations.inline) {
|
|
1231
|
+
style.verticalAlign = "-0.125em";
|
|
1232
|
+
}
|
|
1233
|
+
if (mode === "svg") {
|
|
1234
|
+
componentProps.style = {
|
|
1235
|
+
...style,
|
|
1236
|
+
...customStyle
|
|
1237
|
+
};
|
|
1238
|
+
Object.assign(componentProps, renderAttribs);
|
|
1239
|
+
let localCounter = 0;
|
|
1240
|
+
let id = props.id;
|
|
1241
|
+
if (typeof id === "string") {
|
|
1242
|
+
id = id.replace(/-/g, "_");
|
|
1243
|
+
}
|
|
1244
|
+
componentProps.dangerouslySetInnerHTML = {
|
|
1245
|
+
__html: cleanUpInnerHTML(replaceIDs(item.body, id ? () => id + "ID" + localCounter++ : "iconifyReact"))
|
|
1246
|
+
};
|
|
1247
|
+
return createElement("svg", componentProps);
|
|
1248
|
+
}
|
|
1249
|
+
const { body, width, height } = icon;
|
|
1250
|
+
const useMask = mode === "mask" || (mode === "bg" ? false : body.indexOf("currentColor") !== -1);
|
|
1251
|
+
const html = iconToHTML(body, {
|
|
1252
|
+
...renderAttribs,
|
|
1253
|
+
width: width + "",
|
|
1254
|
+
height: height + ""
|
|
1255
|
+
});
|
|
1256
|
+
componentProps.style = {
|
|
1257
|
+
...style,
|
|
1258
|
+
"--svg": svgToURL(html),
|
|
1259
|
+
"width": fixSize(renderAttribs.width),
|
|
1260
|
+
"height": fixSize(renderAttribs.height),
|
|
1261
|
+
...commonProps,
|
|
1262
|
+
...useMask ? monotoneProps : coloredProps,
|
|
1263
|
+
...customStyle
|
|
1264
|
+
};
|
|
1265
|
+
return createElement("span", componentProps);
|
|
1266
|
+
};
|
|
1267
|
+
allowSimpleNames(true);
|
|
1268
|
+
setAPIModule("", fetchAPIModule);
|
|
1269
|
+
if (typeof document !== "undefined" && typeof window !== "undefined") {
|
|
1270
|
+
const _window = window;
|
|
1271
|
+
if (_window.IconifyPreload !== void 0) {
|
|
1272
|
+
const preload = _window.IconifyPreload;
|
|
1273
|
+
const err = "Invalid IconifyPreload syntax.";
|
|
1274
|
+
if (typeof preload === "object" && preload !== null) {
|
|
1275
|
+
(preload instanceof Array ? preload : [preload]).forEach((item) => {
|
|
1276
|
+
try {
|
|
1277
|
+
if (
|
|
1278
|
+
// Check if item is an object and not null/array
|
|
1279
|
+
typeof item !== "object" || item === null || item instanceof Array || // Check for 'icons' and 'prefix'
|
|
1280
|
+
typeof item.icons !== "object" || typeof item.prefix !== "string" || // Add icon set
|
|
1281
|
+
!addCollection(item)
|
|
1282
|
+
) {
|
|
1283
|
+
console.error(err);
|
|
1284
|
+
}
|
|
1285
|
+
} catch (e) {
|
|
1286
|
+
console.error(err);
|
|
1287
|
+
}
|
|
1288
|
+
});
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
if (_window.IconifyProviders !== void 0) {
|
|
1292
|
+
const providers = _window.IconifyProviders;
|
|
1293
|
+
if (typeof providers === "object" && providers !== null) {
|
|
1294
|
+
for (let key in providers) {
|
|
1295
|
+
const err = "IconifyProviders[" + key + "] is invalid.";
|
|
1296
|
+
try {
|
|
1297
|
+
const value = providers[key];
|
|
1298
|
+
if (typeof value !== "object" || !value || value.resources === void 0) {
|
|
1299
|
+
continue;
|
|
1300
|
+
}
|
|
1301
|
+
if (!addAPIProvider(key, value)) {
|
|
1302
|
+
console.error(err);
|
|
1303
|
+
}
|
|
1304
|
+
} catch (e) {
|
|
1305
|
+
console.error(err);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
function IconComponent(props) {
|
|
1312
|
+
const [mounted, setMounted] = useState(!!props.ssr);
|
|
1313
|
+
const [abort, setAbort] = useState({});
|
|
1314
|
+
function getInitialState(mounted2) {
|
|
1315
|
+
if (mounted2) {
|
|
1316
|
+
const name2 = props.icon;
|
|
1317
|
+
if (typeof name2 === "object") {
|
|
1318
|
+
return {
|
|
1319
|
+
name: "",
|
|
1320
|
+
data: name2
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1323
|
+
const data2 = getIconData(name2);
|
|
1324
|
+
if (data2) {
|
|
1325
|
+
return {
|
|
1326
|
+
name: name2,
|
|
1327
|
+
data: data2
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
return {
|
|
1332
|
+
name: ""
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
const [state, setState] = useState(getInitialState(!!props.ssr));
|
|
1336
|
+
function cleanup() {
|
|
1337
|
+
const callback = abort.callback;
|
|
1338
|
+
if (callback) {
|
|
1339
|
+
callback();
|
|
1340
|
+
setAbort({});
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
function changeState(newState) {
|
|
1344
|
+
if (JSON.stringify(state) !== JSON.stringify(newState)) {
|
|
1345
|
+
cleanup();
|
|
1346
|
+
setState(newState);
|
|
1347
|
+
return true;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
function updateState() {
|
|
1351
|
+
var _a;
|
|
1352
|
+
const name2 = props.icon;
|
|
1353
|
+
if (typeof name2 === "object") {
|
|
1354
|
+
changeState({
|
|
1355
|
+
name: "",
|
|
1356
|
+
data: name2
|
|
1357
|
+
});
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
const data2 = getIconData(name2);
|
|
1361
|
+
if (changeState({
|
|
1362
|
+
name: name2,
|
|
1363
|
+
data: data2
|
|
1364
|
+
})) {
|
|
1365
|
+
if (data2 === void 0) {
|
|
1366
|
+
const callback = loadIcons([name2], updateState);
|
|
1367
|
+
setAbort({
|
|
1368
|
+
callback
|
|
1369
|
+
});
|
|
1370
|
+
} else if (data2) {
|
|
1371
|
+
(_a = props.onLoad) === null || _a === void 0 ? void 0 : _a.call(props, name2);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
useEffect(() => {
|
|
1376
|
+
setMounted(true);
|
|
1377
|
+
return cleanup;
|
|
1378
|
+
}, []);
|
|
1379
|
+
useEffect(() => {
|
|
1380
|
+
if (mounted) {
|
|
1381
|
+
updateState();
|
|
1382
|
+
}
|
|
1383
|
+
}, [props.icon, mounted]);
|
|
1384
|
+
const { name, data } = state;
|
|
1385
|
+
if (!data) {
|
|
1386
|
+
return props.children ? props.children : props.fallback ? props.fallback : createElement("span", {});
|
|
1387
|
+
}
|
|
1388
|
+
return render({
|
|
1389
|
+
...defaultIconProps,
|
|
1390
|
+
...data
|
|
1391
|
+
}, props, name);
|
|
1392
|
+
}
|
|
1393
|
+
var Icon = forwardRef((props, ref) => IconComponent({
|
|
1394
|
+
...props,
|
|
1395
|
+
_ref: ref
|
|
1396
|
+
}));
|
|
1397
|
+
forwardRef((props, ref) => IconComponent({
|
|
1398
|
+
inline: true,
|
|
1399
|
+
...props,
|
|
1400
|
+
_ref: ref
|
|
1401
|
+
}));
|
|
13
1402
|
var buttonVariants = cva(
|
|
14
1403
|
"inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-300 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-primary-700 dark:focus-visible:ring-offset-zinc-950",
|
|
15
1404
|
{
|
|
@@ -833,6 +2222,138 @@ var uploadFile = ({
|
|
|
833
2222
|
}
|
|
834
2223
|
xhr.send(formData);
|
|
835
2224
|
});
|
|
2225
|
+
var splitFileIntoChunks = (file, chunkSize) => {
|
|
2226
|
+
const chunks = [];
|
|
2227
|
+
let start = 0;
|
|
2228
|
+
let index = 0;
|
|
2229
|
+
while (start < file.size) {
|
|
2230
|
+
const end = Math.min(start + chunkSize, file.size);
|
|
2231
|
+
const blob = file.slice(start, end);
|
|
2232
|
+
chunks.push({
|
|
2233
|
+
blob,
|
|
2234
|
+
index,
|
|
2235
|
+
start,
|
|
2236
|
+
end
|
|
2237
|
+
});
|
|
2238
|
+
start = end;
|
|
2239
|
+
index++;
|
|
2240
|
+
}
|
|
2241
|
+
return chunks;
|
|
2242
|
+
};
|
|
2243
|
+
var uploadChunk = ({
|
|
2244
|
+
action,
|
|
2245
|
+
chunk,
|
|
2246
|
+
chunkIndex,
|
|
2247
|
+
totalChunks,
|
|
2248
|
+
fileName,
|
|
2249
|
+
fileSize,
|
|
2250
|
+
method = "post",
|
|
2251
|
+
headers,
|
|
2252
|
+
onProgress,
|
|
2253
|
+
signal
|
|
2254
|
+
}) => new Promise((resolve, reject) => {
|
|
2255
|
+
const xhr = new XMLHttpRequest();
|
|
2256
|
+
xhr.open(method.toUpperCase(), action, true);
|
|
2257
|
+
const handleAbort = () => {
|
|
2258
|
+
xhr.abort();
|
|
2259
|
+
};
|
|
2260
|
+
if (headers) {
|
|
2261
|
+
Object.entries(headers).forEach(([key, value]) => {
|
|
2262
|
+
xhr.setRequestHeader(key, value);
|
|
2263
|
+
});
|
|
2264
|
+
}
|
|
2265
|
+
xhr.upload.onprogress = (event) => {
|
|
2266
|
+
onProgress == null ? void 0 : onProgress(event);
|
|
2267
|
+
};
|
|
2268
|
+
xhr.onload = () => {
|
|
2269
|
+
signal == null ? void 0 : signal.removeEventListener("abort", handleAbort);
|
|
2270
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
2271
|
+
resolve(xhr.responseText);
|
|
2272
|
+
} else {
|
|
2273
|
+
reject(new Error(`Chunk upload failed: ${xhr.statusText}`));
|
|
2274
|
+
}
|
|
2275
|
+
};
|
|
2276
|
+
xhr.onerror = (event) => {
|
|
2277
|
+
signal == null ? void 0 : signal.removeEventListener("abort", handleAbort);
|
|
2278
|
+
reject(event);
|
|
2279
|
+
};
|
|
2280
|
+
xhr.onabort = () => {
|
|
2281
|
+
signal == null ? void 0 : signal.removeEventListener("abort", handleAbort);
|
|
2282
|
+
reject(new DOMException("Chunk upload aborted", "AbortError"));
|
|
2283
|
+
};
|
|
2284
|
+
if (signal == null ? void 0 : signal.aborted) {
|
|
2285
|
+
reject(new DOMException("Chunk upload aborted", "AbortError"));
|
|
2286
|
+
return;
|
|
2287
|
+
}
|
|
2288
|
+
signal == null ? void 0 : signal.addEventListener("abort", handleAbort);
|
|
2289
|
+
const formData = new FormData();
|
|
2290
|
+
formData.append("file", chunk);
|
|
2291
|
+
formData.append("chunkIndex", String(chunkIndex));
|
|
2292
|
+
formData.append("totalChunks", String(totalChunks));
|
|
2293
|
+
formData.append("fileName", fileName);
|
|
2294
|
+
formData.append("fileSize", String(fileSize));
|
|
2295
|
+
xhr.send(formData);
|
|
2296
|
+
});
|
|
2297
|
+
var checkUploadedChunks = (action, file, chunkSize, headers) => new Promise((resolve, _reject) => {
|
|
2298
|
+
const xhr = new XMLHttpRequest();
|
|
2299
|
+
const params = new URLSearchParams({
|
|
2300
|
+
fileName: file.name,
|
|
2301
|
+
fileSize: String(file.size),
|
|
2302
|
+
chunkSize: String(chunkSize)
|
|
2303
|
+
});
|
|
2304
|
+
xhr.open("GET", `${action}?${params}`, true);
|
|
2305
|
+
if (headers) {
|
|
2306
|
+
Object.entries(headers).forEach(([key, value]) => {
|
|
2307
|
+
xhr.setRequestHeader(key, value);
|
|
2308
|
+
});
|
|
2309
|
+
}
|
|
2310
|
+
xhr.onload = () => {
|
|
2311
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
2312
|
+
resolve(xhr.responseText);
|
|
2313
|
+
} else {
|
|
2314
|
+
resolve("[]");
|
|
2315
|
+
}
|
|
2316
|
+
};
|
|
2317
|
+
xhr.onerror = () => {
|
|
2318
|
+
resolve("[]");
|
|
2319
|
+
};
|
|
2320
|
+
xhr.ontimeout = () => {
|
|
2321
|
+
resolve("[]");
|
|
2322
|
+
};
|
|
2323
|
+
xhr.send();
|
|
2324
|
+
}).then((responseText) => {
|
|
2325
|
+
try {
|
|
2326
|
+
const data = JSON.parse(responseText);
|
|
2327
|
+
return data.uploadedChunks || [];
|
|
2328
|
+
} catch (e) {
|
|
2329
|
+
return [];
|
|
2330
|
+
}
|
|
2331
|
+
});
|
|
2332
|
+
var mergeChunks = (action, fileName, totalChunks, method = "post", headers) => new Promise((resolve, reject) => {
|
|
2333
|
+
const xhr = new XMLHttpRequest();
|
|
2334
|
+
xhr.open(method.toUpperCase(), action, true);
|
|
2335
|
+
if (headers) {
|
|
2336
|
+
Object.entries(headers).forEach(([key, value]) => {
|
|
2337
|
+
xhr.setRequestHeader(key, value);
|
|
2338
|
+
});
|
|
2339
|
+
}
|
|
2340
|
+
xhr.setRequestHeader("Content-Type", "application/json");
|
|
2341
|
+
xhr.onload = () => {
|
|
2342
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
2343
|
+
resolve(xhr.responseText);
|
|
2344
|
+
} else {
|
|
2345
|
+
reject(new Error(`Merge chunks failed: ${xhr.statusText}`));
|
|
2346
|
+
}
|
|
2347
|
+
};
|
|
2348
|
+
xhr.onerror = (event) => {
|
|
2349
|
+
reject(event);
|
|
2350
|
+
};
|
|
2351
|
+
const body = JSON.stringify({
|
|
2352
|
+
fileName,
|
|
2353
|
+
totalChunks
|
|
2354
|
+
});
|
|
2355
|
+
xhr.send(body);
|
|
2356
|
+
});
|
|
836
2357
|
var uploadTriggerVariants = cva(
|
|
837
2358
|
"flex cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-300 focus-visible:ring-offset-2 focus-visible:ring-offset-white",
|
|
838
2359
|
{
|
|
@@ -1084,7 +2605,97 @@ function ImageUpload({
|
|
|
1084
2605
|
}
|
|
1085
2606
|
);
|
|
1086
2607
|
}
|
|
1087
|
-
function
|
|
2608
|
+
function ChunkItem({ index, progress, isCompleted, isUploading, isPending }) {
|
|
2609
|
+
const getStatusColor = () => {
|
|
2610
|
+
if (isCompleted) return "bg-green-500";
|
|
2611
|
+
if (isUploading) return "bg-blue-500";
|
|
2612
|
+
return "bg-gray-300";
|
|
2613
|
+
};
|
|
2614
|
+
return /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: /* @__PURE__ */ jsx(
|
|
2615
|
+
"div",
|
|
2616
|
+
{
|
|
2617
|
+
className: `w-2 h-2 rounded-full ${getStatusColor()} transition-all duration-200`,
|
|
2618
|
+
title: `\u5206\u7247 ${index + 1}: ${isCompleted ? "\u5DF2\u5B8C\u6210" : isUploading ? `${progress}%` : "\u7B49\u5F85\u4E2D"}`,
|
|
2619
|
+
children: isUploading && /* @__PURE__ */ jsxs("svg", { className: "w-2 h-2 -rotate-90", viewBox: "0 0 8 8", children: [
|
|
2620
|
+
/* @__PURE__ */ jsx(
|
|
2621
|
+
"circle",
|
|
2622
|
+
{
|
|
2623
|
+
cx: "4",
|
|
2624
|
+
cy: "4",
|
|
2625
|
+
r: "3",
|
|
2626
|
+
fill: "none",
|
|
2627
|
+
stroke: "#e5e7eb",
|
|
2628
|
+
strokeWidth: "1"
|
|
2629
|
+
}
|
|
2630
|
+
),
|
|
2631
|
+
/* @__PURE__ */ jsx(
|
|
2632
|
+
"circle",
|
|
2633
|
+
{
|
|
2634
|
+
cx: "4",
|
|
2635
|
+
cy: "4",
|
|
2636
|
+
r: "3",
|
|
2637
|
+
fill: "none",
|
|
2638
|
+
stroke: "#3b82f6",
|
|
2639
|
+
strokeWidth: "1",
|
|
2640
|
+
strokeDasharray: `${progress * 0.188} 18.8`,
|
|
2641
|
+
strokeLinecap: "round"
|
|
2642
|
+
}
|
|
2643
|
+
)
|
|
2644
|
+
] })
|
|
2645
|
+
}
|
|
2646
|
+
) });
|
|
2647
|
+
}
|
|
2648
|
+
function ChunkList({ chunkProgress, totalChunks }) {
|
|
2649
|
+
if (!chunkProgress || totalChunks <= 1) {
|
|
2650
|
+
return null;
|
|
2651
|
+
}
|
|
2652
|
+
const { uploadedChunks, chunkIndex, chunkProgress: currentProgress } = chunkProgress;
|
|
2653
|
+
const chunks = Array.from({ length: totalChunks }, (_, i) => {
|
|
2654
|
+
if (i < uploadedChunks) {
|
|
2655
|
+
return { index: i, status: "completed" };
|
|
2656
|
+
} else if (i === chunkIndex) {
|
|
2657
|
+
return { index: i, status: "uploading", progress: currentProgress };
|
|
2658
|
+
} else {
|
|
2659
|
+
return { index: i, status: "pending" };
|
|
2660
|
+
}
|
|
2661
|
+
});
|
|
2662
|
+
if (totalChunks > 20) {
|
|
2663
|
+
return /* @__PURE__ */ jsx("div", { className: "mt-1 text-xs text-gray-400", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
2664
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2665
|
+
uploadedChunks,
|
|
2666
|
+
"/",
|
|
2667
|
+
totalChunks,
|
|
2668
|
+
" \u5206\u7247\u5DF2\u4E0A\u4F20"
|
|
2669
|
+
] }),
|
|
2670
|
+
chunkIndex !== void 0 && /* @__PURE__ */ jsxs("span", { className: "text-blue-500", children: [
|
|
2671
|
+
"\u5F53\u524D: \u5206\u7247 ",
|
|
2672
|
+
chunkIndex + 1,
|
|
2673
|
+
" (",
|
|
2674
|
+
currentProgress,
|
|
2675
|
+
"%)"
|
|
2676
|
+
] })
|
|
2677
|
+
] }) });
|
|
2678
|
+
}
|
|
2679
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-0.5 flex-wrap", children: [
|
|
2680
|
+
chunks.map((chunk) => /* @__PURE__ */ jsx(
|
|
2681
|
+
ChunkItem,
|
|
2682
|
+
{
|
|
2683
|
+
index: chunk.index,
|
|
2684
|
+
progress: chunk.progress || 0,
|
|
2685
|
+
isCompleted: chunk.status === "completed",
|
|
2686
|
+
isUploading: chunk.status === "uploading",
|
|
2687
|
+
isPending: chunk.status === "pending"
|
|
2688
|
+
},
|
|
2689
|
+
chunk.index
|
|
2690
|
+
)),
|
|
2691
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs text-gray-400 ml-1", children: [
|
|
2692
|
+
uploadedChunks,
|
|
2693
|
+
"/",
|
|
2694
|
+
totalChunks
|
|
2695
|
+
] })
|
|
2696
|
+
] });
|
|
2697
|
+
}
|
|
2698
|
+
function FileItem({ file, onRemove, onCancel, chunkProgress }) {
|
|
1088
2699
|
const { id, file: fileData, status, progress, error } = file;
|
|
1089
2700
|
const iconMap = {
|
|
1090
2701
|
idle: { icon: "lucide:file", className: "text-gray-400" },
|
|
@@ -1106,17 +2717,26 @@ function FileItem({ file, onRemove, onCancel }) {
|
|
|
1106
2717
|
/* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500 ml-2", children: formatSize(fileData.size) })
|
|
1107
2718
|
] }),
|
|
1108
2719
|
(status === "uploading" || status === "success") && /* @__PURE__ */ jsxs("div", { className: "mt-1", children: [
|
|
1109
|
-
/* @__PURE__ */
|
|
1110
|
-
"div",
|
|
2720
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2721
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 h-1.5 bg-gray-200 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
2722
|
+
"div",
|
|
2723
|
+
{
|
|
2724
|
+
className: "h-full bg-blue-500 transition-all duration-300",
|
|
2725
|
+
style: { width: `${progress}%` }
|
|
2726
|
+
}
|
|
2727
|
+
) }),
|
|
2728
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs text-gray-500 whitespace-nowrap", children: [
|
|
2729
|
+
progress,
|
|
2730
|
+
"%"
|
|
2731
|
+
] })
|
|
2732
|
+
] }),
|
|
2733
|
+
chunkProgress && chunkProgress.totalChunks > 1 && /* @__PURE__ */ jsx(
|
|
2734
|
+
ChunkList,
|
|
1111
2735
|
{
|
|
1112
|
-
|
|
1113
|
-
|
|
2736
|
+
chunkProgress,
|
|
2737
|
+
totalChunks: chunkProgress.totalChunks
|
|
1114
2738
|
}
|
|
1115
|
-
)
|
|
1116
|
-
/* @__PURE__ */ jsxs("span", { className: "text-xs text-gray-500", children: [
|
|
1117
|
-
progress,
|
|
1118
|
-
"%"
|
|
1119
|
-
] })
|
|
2739
|
+
)
|
|
1120
2740
|
] }),
|
|
1121
2741
|
status === "error" && error && /* @__PURE__ */ jsx("div", { className: "mt-1 text-xs text-red-500", children: error.message })
|
|
1122
2742
|
] }),
|
|
@@ -1144,7 +2764,7 @@ function FileItem({ file, onRemove, onCancel }) {
|
|
|
1144
2764
|
] })
|
|
1145
2765
|
] });
|
|
1146
2766
|
}
|
|
1147
|
-
function FileList({ files, onRemove, onCancel, show = true }) {
|
|
2767
|
+
function FileList({ files, onRemove, onCancel, show = true, chunkProgressMap }) {
|
|
1148
2768
|
if (!show || files.length === 0) {
|
|
1149
2769
|
return null;
|
|
1150
2770
|
}
|
|
@@ -1153,7 +2773,8 @@ function FileList({ files, onRemove, onCancel, show = true }) {
|
|
|
1153
2773
|
{
|
|
1154
2774
|
file,
|
|
1155
2775
|
onRemove,
|
|
1156
|
-
onCancel
|
|
2776
|
+
onCancel,
|
|
2777
|
+
chunkProgress: chunkProgressMap == null ? void 0 : chunkProgressMap[file.id]
|
|
1157
2778
|
},
|
|
1158
2779
|
file.id
|
|
1159
2780
|
)) });
|
|
@@ -1168,6 +2789,26 @@ var DEFAULT_OPTIONS = {
|
|
|
1168
2789
|
method: "post",
|
|
1169
2790
|
name: "file"
|
|
1170
2791
|
};
|
|
2792
|
+
var DEFAULT_CHUNKED_CONFIG = {
|
|
2793
|
+
chunked: false,
|
|
2794
|
+
chunkSize: 2 * 1024 * 1024,
|
|
2795
|
+
// 2MB
|
|
2796
|
+
chunkConcurrency: 0,
|
|
2797
|
+
// 0 表示根据文件大小自动计算
|
|
2798
|
+
resumable: false,
|
|
2799
|
+
chunkedUrl: "",
|
|
2800
|
+
mergeUrl: "",
|
|
2801
|
+
chunkThreshold: 5 * 1024 * 1024
|
|
2802
|
+
// 5MB
|
|
2803
|
+
};
|
|
2804
|
+
var calculateConcurrency = (fileSize) => {
|
|
2805
|
+
const mb = fileSize / 1024 / 1024;
|
|
2806
|
+
if (mb < 10) return 2;
|
|
2807
|
+
if (mb < 50) return 3;
|
|
2808
|
+
if (mb < 100) return 4;
|
|
2809
|
+
if (mb < 500) return 5;
|
|
2810
|
+
return 6;
|
|
2811
|
+
};
|
|
1171
2812
|
var createUploadError = (type, message, file, originalError) => ({
|
|
1172
2813
|
type,
|
|
1173
2814
|
message,
|
|
@@ -1180,6 +2821,10 @@ function Upload(config) {
|
|
|
1180
2821
|
...DEFAULT_OPTIONS,
|
|
1181
2822
|
...config
|
|
1182
2823
|
};
|
|
2824
|
+
const chunkedConfig = {
|
|
2825
|
+
...DEFAULT_CHUNKED_CONFIG,
|
|
2826
|
+
...config.chunkedConfig
|
|
2827
|
+
};
|
|
1183
2828
|
const {
|
|
1184
2829
|
mode,
|
|
1185
2830
|
autoUpload,
|
|
@@ -1203,11 +2848,21 @@ function Upload(config) {
|
|
|
1203
2848
|
onError,
|
|
1204
2849
|
onComplete
|
|
1205
2850
|
} = options;
|
|
2851
|
+
const {
|
|
2852
|
+
chunked,
|
|
2853
|
+
chunkSize,
|
|
2854
|
+
chunkConcurrency,
|
|
2855
|
+
resumable,
|
|
2856
|
+
chunkedUrl,
|
|
2857
|
+
mergeUrl,
|
|
2858
|
+
chunkThreshold
|
|
2859
|
+
} = chunkedConfig;
|
|
1206
2860
|
const [files, setFiles] = useState([]);
|
|
1207
2861
|
const [isDragging, setIsDragging] = useState(false);
|
|
1208
2862
|
const [previewUrl, setPreviewUrl] = useState(null);
|
|
1209
2863
|
const [status, setStatus] = useState("idle");
|
|
1210
2864
|
const [progress, setProgress] = useState(0);
|
|
2865
|
+
const [chunkProgress, setChunkProgress] = useState({});
|
|
1211
2866
|
const inputId = useId();
|
|
1212
2867
|
const abortRef = useRef(null);
|
|
1213
2868
|
const cancelRef = useRef(false);
|
|
@@ -1257,6 +2912,24 @@ function Upload(config) {
|
|
|
1257
2912
|
const { file } = fileItem;
|
|
1258
2913
|
const controller = new AbortController();
|
|
1259
2914
|
abortRef.current = controller;
|
|
2915
|
+
const useChunkedUpload = chunked && file.size > chunkThreshold;
|
|
2916
|
+
if (!useChunkedUpload) {
|
|
2917
|
+
return uploadWithNormalMode(
|
|
2918
|
+
fileItem,
|
|
2919
|
+
totalBytes,
|
|
2920
|
+
uploadedBytes,
|
|
2921
|
+
controller
|
|
2922
|
+
);
|
|
2923
|
+
}
|
|
2924
|
+
return uploadWithChunkedMode(
|
|
2925
|
+
fileItem,
|
|
2926
|
+
totalBytes,
|
|
2927
|
+
uploadedBytes,
|
|
2928
|
+
controller
|
|
2929
|
+
);
|
|
2930
|
+
};
|
|
2931
|
+
const uploadWithNormalMode = async (fileItem, totalBytes, uploadedBytes, controller) => {
|
|
2932
|
+
const { file } = fileItem;
|
|
1260
2933
|
try {
|
|
1261
2934
|
const formData = new FormData();
|
|
1262
2935
|
formData.append(name, file);
|
|
@@ -1314,6 +2987,156 @@ function Upload(config) {
|
|
|
1314
2987
|
return { ...fileItem, status: "error", error };
|
|
1315
2988
|
}
|
|
1316
2989
|
};
|
|
2990
|
+
const uploadWithChunkedMode = async (fileItem, totalBytes, uploadedBytes, controller) => {
|
|
2991
|
+
const { file } = fileItem;
|
|
2992
|
+
const fileId = fileItem.id;
|
|
2993
|
+
try {
|
|
2994
|
+
let uploadedChunkIndices = [];
|
|
2995
|
+
if (resumable && chunkedUrl) {
|
|
2996
|
+
uploadedChunkIndices = await checkUploadedChunks(
|
|
2997
|
+
chunkedUrl,
|
|
2998
|
+
file,
|
|
2999
|
+
chunkSize,
|
|
3000
|
+
headers
|
|
3001
|
+
);
|
|
3002
|
+
}
|
|
3003
|
+
const chunks = splitFileIntoChunks(file, chunkSize);
|
|
3004
|
+
const totalChunks = chunks.length;
|
|
3005
|
+
const actualConcurrency = chunkConcurrency > 0 ? Math.min(chunkConcurrency, totalChunks) : Math.min(calculateConcurrency(file.size), totalChunks);
|
|
3006
|
+
const chunksToUpload = chunks.filter(
|
|
3007
|
+
(chunk) => !uploadedChunkIndices.includes(chunk.index)
|
|
3008
|
+
);
|
|
3009
|
+
const completedChunksRef = { current: uploadedChunkIndices.length };
|
|
3010
|
+
const chunkProgressMapRef = { current: /* @__PURE__ */ new Map() };
|
|
3011
|
+
const uploadTasks = chunksToUpload.map((chunk) => async () => {
|
|
3012
|
+
if (cancelRef.current || controller.signal.aborted) {
|
|
3013
|
+
throw new DOMException("Upload aborted", "AbortError");
|
|
3014
|
+
}
|
|
3015
|
+
chunkProgressMapRef.current.set(chunk.index, 0);
|
|
3016
|
+
await uploadChunk({
|
|
3017
|
+
action,
|
|
3018
|
+
chunk: chunk.blob,
|
|
3019
|
+
chunkIndex: chunk.index,
|
|
3020
|
+
totalChunks,
|
|
3021
|
+
fileName: file.name,
|
|
3022
|
+
fileSize: file.size,
|
|
3023
|
+
method,
|
|
3024
|
+
headers,
|
|
3025
|
+
signal: controller.signal,
|
|
3026
|
+
onProgress: (event) => {
|
|
3027
|
+
if (!event.lengthComputable) {
|
|
3028
|
+
return;
|
|
3029
|
+
}
|
|
3030
|
+
const chunkLoaded = event.loaded;
|
|
3031
|
+
const chunkTotal = chunk.end - chunk.start;
|
|
3032
|
+
const chunkProgressPercent = Math.min(
|
|
3033
|
+
100,
|
|
3034
|
+
Math.round(chunkLoaded / chunkTotal * 100)
|
|
3035
|
+
);
|
|
3036
|
+
chunkProgressMapRef.current.set(chunk.index, chunkProgressPercent);
|
|
3037
|
+
const completedCount = completedChunksRef.current;
|
|
3038
|
+
let inProgressProgress = 0;
|
|
3039
|
+
chunkProgressMapRef.current.forEach((progress2) => {
|
|
3040
|
+
inProgressProgress += progress2;
|
|
3041
|
+
});
|
|
3042
|
+
const totalProgress = Math.min(
|
|
3043
|
+
100,
|
|
3044
|
+
Math.round(
|
|
3045
|
+
(completedCount * 100 + inProgressProgress) / totalChunks
|
|
3046
|
+
)
|
|
3047
|
+
);
|
|
3048
|
+
setChunkProgress((prev) => ({
|
|
3049
|
+
...prev,
|
|
3050
|
+
[fileId]: {
|
|
3051
|
+
chunkIndex: chunk.index,
|
|
3052
|
+
chunkProgress: chunkProgressPercent,
|
|
3053
|
+
totalProgress,
|
|
3054
|
+
uploadedChunks: completedCount,
|
|
3055
|
+
totalChunks
|
|
3056
|
+
}
|
|
3057
|
+
}));
|
|
3058
|
+
setProgress(totalProgress);
|
|
3059
|
+
onProgress == null ? void 0 : onProgress(totalProgress, file);
|
|
3060
|
+
setFiles(
|
|
3061
|
+
(prev) => prev.map(
|
|
3062
|
+
(f) => f.id === fileItem.id ? { ...f, progress: totalProgress } : f
|
|
3063
|
+
)
|
|
3064
|
+
);
|
|
3065
|
+
}
|
|
3066
|
+
});
|
|
3067
|
+
completedChunksRef.current++;
|
|
3068
|
+
chunkProgressMapRef.current.delete(chunk.index);
|
|
3069
|
+
return chunk.index;
|
|
3070
|
+
});
|
|
3071
|
+
const executeWithConcurrency = async (tasks, limit) => {
|
|
3072
|
+
const results = [];
|
|
3073
|
+
const executing = [];
|
|
3074
|
+
let taskIndex = 0;
|
|
3075
|
+
const runTask = async (task) => {
|
|
3076
|
+
const result = await task();
|
|
3077
|
+
return result;
|
|
3078
|
+
};
|
|
3079
|
+
while (taskIndex < tasks.length || executing.length > 0) {
|
|
3080
|
+
while (taskIndex < tasks.length && executing.length < limit) {
|
|
3081
|
+
const task = tasks[taskIndex];
|
|
3082
|
+
taskIndex++;
|
|
3083
|
+
const promise = runTask(task).then((result) => {
|
|
3084
|
+
results.push(result);
|
|
3085
|
+
return result;
|
|
3086
|
+
});
|
|
3087
|
+
executing.push(promise);
|
|
3088
|
+
}
|
|
3089
|
+
if (executing.length > 0) {
|
|
3090
|
+
await Promise.race(executing);
|
|
3091
|
+
const completedIndex = executing.findIndex(
|
|
3092
|
+
(p) => p.then !== void 0
|
|
3093
|
+
);
|
|
3094
|
+
if (completedIndex !== -1) {
|
|
3095
|
+
executing.splice(completedIndex, 1);
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
}
|
|
3099
|
+
return results;
|
|
3100
|
+
};
|
|
3101
|
+
await executeWithConcurrency(uploadTasks, actualConcurrency);
|
|
3102
|
+
let responseText = "";
|
|
3103
|
+
if (mergeUrl) {
|
|
3104
|
+
responseText = await mergeChunks(
|
|
3105
|
+
mergeUrl,
|
|
3106
|
+
file.name,
|
|
3107
|
+
totalChunks,
|
|
3108
|
+
method === "get" ? "post" : method,
|
|
3109
|
+
headers
|
|
3110
|
+
);
|
|
3111
|
+
}
|
|
3112
|
+
const updatedFile = {
|
|
3113
|
+
...fileItem,
|
|
3114
|
+
status: "success",
|
|
3115
|
+
progress: 100,
|
|
3116
|
+
response: responseText || "Chunked upload completed"
|
|
3117
|
+
};
|
|
3118
|
+
setChunkProgress((prev) => {
|
|
3119
|
+
const newProgress = { ...prev };
|
|
3120
|
+
delete newProgress[fileId];
|
|
3121
|
+
return newProgress;
|
|
3122
|
+
});
|
|
3123
|
+
onSuccess == null ? void 0 : onSuccess(responseText || "Chunked upload completed", file);
|
|
3124
|
+
return updatedFile;
|
|
3125
|
+
} catch (event) {
|
|
3126
|
+
const isAbort = cancelRef.current || (event == null ? void 0 : event.name) === "AbortError";
|
|
3127
|
+
if (isAbort) {
|
|
3128
|
+
return { ...fileItem, status: "idle", progress: 0 };
|
|
3129
|
+
}
|
|
3130
|
+
const error = createUploadError(
|
|
3131
|
+
"NETWORK_ERROR",
|
|
3132
|
+
event instanceof Error ? event.message : "\u5206\u7247\u4E0A\u4F20\u5931\u8D25",
|
|
3133
|
+
file,
|
|
3134
|
+
event instanceof Error ? event : void 0
|
|
3135
|
+
);
|
|
3136
|
+
onError == null ? void 0 : onError(error, file);
|
|
3137
|
+
return { ...fileItem, status: "error", error };
|
|
3138
|
+
}
|
|
3139
|
+
};
|
|
1317
3140
|
const uploadFiles = useCallback(async (filesToUpload) => {
|
|
1318
3141
|
var _a;
|
|
1319
3142
|
if (!action || filesToUpload.length === 0) {
|
|
@@ -1347,7 +3170,12 @@ function Upload(config) {
|
|
|
1347
3170
|
uploadedFiles.push(result);
|
|
1348
3171
|
setFiles(
|
|
1349
3172
|
(prev) => prev.map(
|
|
1350
|
-
(f) => f.id === fileItem.id ? {
|
|
3173
|
+
(f) => f.id === fileItem.id ? {
|
|
3174
|
+
...f,
|
|
3175
|
+
status: result.status,
|
|
3176
|
+
response: result.response,
|
|
3177
|
+
progress: result.status === "success" ? 100 : f.progress
|
|
3178
|
+
} : f
|
|
1351
3179
|
)
|
|
1352
3180
|
);
|
|
1353
3181
|
if (result.status === "success") {
|
|
@@ -1513,7 +3341,8 @@ function Upload(config) {
|
|
|
1513
3341
|
files,
|
|
1514
3342
|
show: showFileList,
|
|
1515
3343
|
onRemove: handleRemoveFile,
|
|
1516
|
-
onCancel: handleCancelFile
|
|
3344
|
+
onCancel: handleCancelFile,
|
|
3345
|
+
chunkProgressMap: chunkProgress
|
|
1517
3346
|
}
|
|
1518
3347
|
)
|
|
1519
3348
|
] });
|