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