@5even7/dlc-ui 0.1.0 → 0.2.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/CHANGELOG.md +33 -3
- package/README.md +277 -248
- package/dist/capsule.cjs +421 -103
- package/dist/capsule.mjs +481 -197
- package/dist/color.cjs +342 -37
- package/dist/color.mjs +390 -105
- package/dist/index.cjs +745 -203
- package/dist/index.mjs +923 -457
- package/dist/index.umd.js +745 -203
- package/dist/index.umd.min.js +1 -1
- package/dist/progress.cjs +487 -116
- package/dist/progress.mjs +568 -245
- package/dist/vue2.cjs +1092 -208
- package/dist/vue2.mjs +1280 -501
- package/dist/vue3.cjs +1092 -208
- package/dist/vue3.mjs +1280 -501
- package/package.json +1 -1
- package/styles/base.css +12 -18
- package/styles/capsule.css +34 -81
- package/styles/progress.css +37 -57
- package/types/index.d.ts +97 -81
- package/types/vue3.d.ts +59 -20
package/dist/progress.mjs
CHANGED
|
@@ -96,40 +96,40 @@ function normalizeOptions(defaults, preset, user) {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
const PROGRESS_PRESETS = [
|
|
99
|
-
{
|
|
100
|
-
id: 'model-training',
|
|
101
|
-
code: 'NC-10',
|
|
102
|
-
name: '
|
|
99
|
+
{
|
|
100
|
+
id: 'model-training',
|
|
101
|
+
code: 'NC-10',
|
|
102
|
+
name: '星火',
|
|
103
103
|
subtitle: 'SHA 4.5 + 100 2026 TKN',
|
|
104
104
|
group: 'progress',
|
|
105
105
|
initialProgress: 43,
|
|
106
106
|
edgeStyle: 'flow',
|
|
107
107
|
colors: ['#2B1025', '#FF3F94', '#FF8A3D', '#FFF06A']
|
|
108
108
|
},
|
|
109
|
-
{
|
|
110
|
-
id: 'agent-migration',
|
|
111
|
-
code: 'NC-11',
|
|
112
|
-
name: '
|
|
109
|
+
{
|
|
110
|
+
id: 'agent-migration',
|
|
111
|
+
code: 'NC-11',
|
|
112
|
+
name: '迁流',
|
|
113
113
|
subtitle: 'TRANSFERRING PROTOCOL',
|
|
114
114
|
group: 'progress',
|
|
115
115
|
initialProgress: 33,
|
|
116
116
|
edgeStyle: 'flow',
|
|
117
117
|
colors: ['#101C37', '#245BFF', '#00CFFF', '#5DFFE6']
|
|
118
118
|
},
|
|
119
|
-
{
|
|
120
|
-
id: 'visual-training',
|
|
121
|
-
code: 'NC-12',
|
|
122
|
-
name: '
|
|
119
|
+
{
|
|
120
|
+
id: 'visual-training',
|
|
121
|
+
code: 'NC-12',
|
|
122
|
+
name: '幻境',
|
|
123
123
|
subtitle: 'GENERATING POWER ++',
|
|
124
124
|
group: 'progress',
|
|
125
125
|
initialProgress: 58,
|
|
126
126
|
edgeStyle: 'flow',
|
|
127
127
|
colors: ['#21142D', '#7042FF', '#42F58D', '#C4FF8A']
|
|
128
128
|
},
|
|
129
|
-
{
|
|
130
|
-
id: 'tide',
|
|
131
|
-
code: 'NC-13',
|
|
132
|
-
name: '
|
|
129
|
+
{
|
|
130
|
+
id: 'tide',
|
|
131
|
+
code: 'NC-13',
|
|
132
|
+
name: '汐潮',
|
|
133
133
|
subtitle: 'MOON PULL / COAST',
|
|
134
134
|
group: 'progress',
|
|
135
135
|
initialProgress: 30,
|
|
@@ -138,74 +138,262 @@ const PROGRESS_PRESETS = [
|
|
|
138
138
|
}
|
|
139
139
|
];
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
preset.
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function getPreset(kind, ref) {
|
|
156
|
-
const list = PROGRESS_PRESETS ;
|
|
157
|
-
if (!list) throw new Error(`Unknown preset kind: ${kind} (use "capsule" or "progress")`);
|
|
158
|
-
if (ref && typeof ref === 'object') {
|
|
159
|
-
const valid = validateProgressPreset(ref);
|
|
160
|
-
if (!valid) throw new Error(`Invalid ${kind} preset object`);
|
|
161
|
-
return ref;
|
|
162
|
-
}
|
|
163
|
-
const key = String(ref).trim().toLowerCase();
|
|
164
|
-
const found = list.find(
|
|
165
|
-
(preset) =>
|
|
166
|
-
preset.id.toLowerCase() === key ||
|
|
167
|
-
preset.code.toLowerCase() === key ||
|
|
168
|
-
preset.name.toLowerCase() === key
|
|
169
|
-
);
|
|
170
|
-
if (!found) throw new Error(`Unknown ${kind} preset: ${ref}`);
|
|
171
|
-
return found;
|
|
141
|
+
/**
|
|
142
|
+
* Resolve a preset by its literary name (e.g. '沧溟').
|
|
143
|
+
* Matching is case-insensitive and ignores surrounding whitespace,
|
|
144
|
+
* so '沧溟' and ' 沧溟 ' both work.
|
|
145
|
+
*/
|
|
146
|
+
function getPreset(kind, ref) {
|
|
147
|
+
const list = PROGRESS_PRESETS ;
|
|
148
|
+
if (!list) throw new Error(`Unknown preset kind: ${kind} (use "capsule" or "progress")`);
|
|
149
|
+
const key = String(ref).trim().toLowerCase();
|
|
150
|
+
const found = list.find(
|
|
151
|
+
(preset) => preset.name.toLowerCase() === key
|
|
152
|
+
);
|
|
153
|
+
if (!found) throw new Error(`Unknown ${kind} preset: ${ref}`);
|
|
154
|
+
return found;
|
|
172
155
|
}
|
|
173
156
|
|
|
174
|
-
const DEFAULTS = {
|
|
175
|
-
progress: {
|
|
176
|
-
width: 454,
|
|
177
|
-
height: 104,
|
|
178
|
-
min: 0,
|
|
157
|
+
const DEFAULTS = {
|
|
158
|
+
progress: {
|
|
159
|
+
width: 454,
|
|
160
|
+
height: 104,
|
|
161
|
+
min: 0,
|
|
179
162
|
max: 100,
|
|
180
|
-
draggable: true,
|
|
181
|
-
keyboard: true,
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
163
|
+
draggable: true,
|
|
164
|
+
keyboard: true,
|
|
165
|
+
disabled: false,
|
|
166
|
+
valueSuffix: '%',
|
|
167
|
+
edgeStyle: 'flow',
|
|
168
|
+
quality: 'auto',
|
|
169
|
+
renderer: 'auto',
|
|
170
|
+
textRatio: 54,
|
|
171
|
+
showValue: true,
|
|
172
|
+
respectReducedMotion: true
|
|
173
|
+
}
|
|
188
174
|
};
|
|
189
175
|
|
|
190
|
-
/**
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
valueSuffix: '%',
|
|
176
|
+
/**
|
|
177
|
+
* Internal accessibility labels and small UI text. Since the copy API was
|
|
178
|
+
* removed (slots own the text area), these are no longer user-overridable.
|
|
179
|
+
* Templates use {brand} {code} {name} placeholders.
|
|
180
|
+
*/
|
|
181
|
+
const COPY = {
|
|
182
|
+
brandName: '画境观屿',
|
|
183
|
+
valueSuffix: '%',
|
|
198
184
|
progressAria: '{brand} {code} 加载进度',
|
|
199
185
|
capsuleAria: '打开 {name} 沉浸预览'
|
|
200
186
|
};
|
|
201
187
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
188
|
+
/**
|
|
189
|
+
* Color helpers. `normalizeColor` converts any supported CSS color
|
|
190
|
+
* (hex / named / rgb() / rgba()) into a 6-digit hex string, so renderers can
|
|
191
|
+
* keep working with #rrggbb only. rgba() alpha is intentionally dropped:
|
|
192
|
+
* the WebGL shader has no per-color alpha channel, and the component is
|
|
193
|
+
* opaque by design — use component-level `opacity` for transparency.
|
|
194
|
+
*/
|
|
195
|
+
|
|
196
|
+
const NAMED_COLORS = {
|
|
197
|
+
aliceblue: '#f0f8ff',
|
|
198
|
+
antiquewhite: '#faebd7',
|
|
199
|
+
aqua: '#00ffff',
|
|
200
|
+
aquamarine: '#7fffd4',
|
|
201
|
+
azure: '#f0ffff',
|
|
202
|
+
beige: '#f5f5dc',
|
|
203
|
+
bisque: '#ffe4c4',
|
|
204
|
+
black: '#000000',
|
|
205
|
+
blanchedalmond: '#ffebcd',
|
|
206
|
+
blue: '#0000ff',
|
|
207
|
+
blueviolet: '#8a2be2',
|
|
208
|
+
brown: '#a52a2a',
|
|
209
|
+
burlywood: '#deb887',
|
|
210
|
+
cadetblue: '#5f9ea0',
|
|
211
|
+
chartreuse: '#7fff00',
|
|
212
|
+
chocolate: '#d2691e',
|
|
213
|
+
coral: '#ff7f50',
|
|
214
|
+
cornflowerblue: '#6495ed',
|
|
215
|
+
cornsilk: '#fff8dc',
|
|
216
|
+
crimson: '#dc143c',
|
|
217
|
+
cyan: '#00ffff',
|
|
218
|
+
darkblue: '#00008b',
|
|
219
|
+
darkcyan: '#008b8b',
|
|
220
|
+
darkgoldenrod: '#b8860b',
|
|
221
|
+
darkgray: '#a9a9a9',
|
|
222
|
+
darkgreen: '#006400',
|
|
223
|
+
darkgrey: '#a9a9a9',
|
|
224
|
+
darkkhaki: '#bdb76b',
|
|
225
|
+
darkmagenta: '#8b008b',
|
|
226
|
+
darkolivegreen: '#556b2f',
|
|
227
|
+
darkorange: '#ff8c00',
|
|
228
|
+
darkorchid: '#9932cc',
|
|
229
|
+
darkred: '#8b0000',
|
|
230
|
+
darksalmon: '#e9967a',
|
|
231
|
+
darkseagreen: '#8fbc8f',
|
|
232
|
+
darkslateblue: '#483d8b',
|
|
233
|
+
darkslategray: '#2f4f4f',
|
|
234
|
+
darkslategrey: '#2f4f4f',
|
|
235
|
+
darkturquoise: '#00ced1',
|
|
236
|
+
darkviolet: '#9400d3',
|
|
237
|
+
deeppink: '#ff1493',
|
|
238
|
+
deepskyblue: '#00bfff',
|
|
239
|
+
dimgray: '#696969',
|
|
240
|
+
dimgrey: '#696969',
|
|
241
|
+
dodgerblue: '#1e90ff',
|
|
242
|
+
firebrick: '#b22222',
|
|
243
|
+
floralwhite: '#fffaf0',
|
|
244
|
+
forestgreen: '#228b22',
|
|
245
|
+
fuchsia: '#ff00ff',
|
|
246
|
+
gainsboro: '#dcdcdc',
|
|
247
|
+
ghostwhite: '#f8f8ff',
|
|
248
|
+
gold: '#ffd700',
|
|
249
|
+
goldenrod: '#daa520',
|
|
250
|
+
gray: '#808080',
|
|
251
|
+
green: '#008000',
|
|
252
|
+
greenyellow: '#adff2f',
|
|
253
|
+
grey: '#808080',
|
|
254
|
+
honeydew: '#f0fff0',
|
|
255
|
+
hotpink: '#ff69b4',
|
|
256
|
+
indianred: '#cd5c5c',
|
|
257
|
+
indigo: '#4b0082',
|
|
258
|
+
ivory: '#fffff0',
|
|
259
|
+
khaki: '#f0e68c',
|
|
260
|
+
lavender: '#e6e6fa',
|
|
261
|
+
lavenderblush: '#fff0f5',
|
|
262
|
+
lawngreen: '#7cfc00',
|
|
263
|
+
lemonchiffon: '#fffacd',
|
|
264
|
+
lightblue: '#add8e6',
|
|
265
|
+
lightcoral: '#f08080',
|
|
266
|
+
lightcyan: '#e0ffff',
|
|
267
|
+
lightgoldenrodyellow: '#fafad2',
|
|
268
|
+
lightgray: '#d3d3d3',
|
|
269
|
+
lightgreen: '#90ee90',
|
|
270
|
+
lightgrey: '#d3d3d3',
|
|
271
|
+
lightpink: '#ffb6c1',
|
|
272
|
+
lightsalmon: '#ffa07a',
|
|
273
|
+
lightseagreen: '#20b2aa',
|
|
274
|
+
lightskyblue: '#87cefa',
|
|
275
|
+
lightslategray: '#778899',
|
|
276
|
+
lightslategrey: '#778899',
|
|
277
|
+
lightsteelblue: '#b0c4de',
|
|
278
|
+
lightyellow: '#ffffe0',
|
|
279
|
+
lime: '#00ff00',
|
|
280
|
+
limegreen: '#32cd32',
|
|
281
|
+
linen: '#faf0e6',
|
|
282
|
+
magenta: '#ff00ff',
|
|
283
|
+
maroon: '#800000',
|
|
284
|
+
mediumaquamarine: '#66cdaa',
|
|
285
|
+
mediumblue: '#0000cd',
|
|
286
|
+
mediumorchid: '#ba55d3',
|
|
287
|
+
mediumpurple: '#9370db',
|
|
288
|
+
mediumseagreen: '#3cb371',
|
|
289
|
+
mediumslateblue: '#7b68ee',
|
|
290
|
+
mediumspringgreen: '#00fa9a',
|
|
291
|
+
mediumturquoise: '#48d1cc',
|
|
292
|
+
mediumvioletred: '#c71585',
|
|
293
|
+
midnightblue: '#191970',
|
|
294
|
+
mintcream: '#f5fffa',
|
|
295
|
+
mistyrose: '#ffe4e1',
|
|
296
|
+
moccasin: '#ffe4b5',
|
|
297
|
+
navajowhite: '#ffdead',
|
|
298
|
+
navy: '#000080',
|
|
299
|
+
oldlace: '#fdf5e6',
|
|
300
|
+
olive: '#808000',
|
|
301
|
+
olivedrab: '#6b8e23',
|
|
302
|
+
orange: '#ffa500',
|
|
303
|
+
orangered: '#ff4500',
|
|
304
|
+
orchid: '#da70d6',
|
|
305
|
+
palegoldenrod: '#eee8aa',
|
|
306
|
+
palegreen: '#98fb98',
|
|
307
|
+
paleturquoise: '#afeeee',
|
|
308
|
+
palevioletred: '#db7093',
|
|
309
|
+
papayawhip: '#ffefd5',
|
|
310
|
+
peachpuff: '#ffdab9',
|
|
311
|
+
peru: '#cd853f',
|
|
312
|
+
pink: '#ffc0cb',
|
|
313
|
+
plum: '#dda0dd',
|
|
314
|
+
powderblue: '#b0e0e6',
|
|
315
|
+
purple: '#800080',
|
|
316
|
+
rebeccapurple: '#663399',
|
|
317
|
+
red: '#ff0000',
|
|
318
|
+
rosybrown: '#bc8f8f',
|
|
319
|
+
royalblue: '#4169e1',
|
|
320
|
+
saddlebrown: '#8b4513',
|
|
321
|
+
salmon: '#fa8072',
|
|
322
|
+
sandybrown: '#f4a460',
|
|
323
|
+
seagreen: '#2e8b57',
|
|
324
|
+
seashell: '#fff5ee',
|
|
325
|
+
sienna: '#a0522d',
|
|
326
|
+
silver: '#c0c0c0',
|
|
327
|
+
skyblue: '#87ceeb',
|
|
328
|
+
slateblue: '#6a5acd',
|
|
329
|
+
slategray: '#708090',
|
|
330
|
+
slategrey: '#708090',
|
|
331
|
+
snow: '#fffafa',
|
|
332
|
+
springgreen: '#00ff7f',
|
|
333
|
+
steelblue: '#4682b4',
|
|
334
|
+
tan: '#d2b48c',
|
|
335
|
+
teal: '#008080',
|
|
336
|
+
thistle: '#d8bfd8',
|
|
337
|
+
tomato: '#ff6347',
|
|
338
|
+
turquoise: '#40e0d0',
|
|
339
|
+
violet: '#ee82ee',
|
|
340
|
+
wheat: '#f5deb3',
|
|
341
|
+
white: '#ffffff',
|
|
342
|
+
whitesmoke: '#f5f5f5',
|
|
343
|
+
yellow: '#ffff00',
|
|
344
|
+
yellowgreen: '#9acd32'
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
function clampChannel(value) {
|
|
348
|
+
return Math.min(255, Math.max(0, Math.round(value)));
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function normalizeRgbArgs(args) {
|
|
352
|
+
const parts = args.split(/[,\s/]+/).filter(Boolean);
|
|
353
|
+
if (parts.length < 3) return null;
|
|
354
|
+
const to255 = (value) => {
|
|
355
|
+
if (typeof value !== 'string' || !value) return null;
|
|
356
|
+
if (value.endsWith('%')) return clampChannel((parseFloat(value) / 100) * 255);
|
|
357
|
+
const number = Number(value);
|
|
358
|
+
return Number.isFinite(number) ? clampChannel(number) : null;
|
|
359
|
+
};
|
|
360
|
+
const red = to255(parts[0]);
|
|
361
|
+
const green = to255(parts[1]);
|
|
362
|
+
const blue = to255(parts[2]);
|
|
363
|
+
if (red === null || green === null || blue === null) return null;
|
|
364
|
+
return `#${[red, green, blue].map((n) => n.toString(16).padStart(2, '0')).join('')}`;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Convert any supported CSS color into `#rrggbb`. Returns null when the
|
|
369
|
+
* value cannot be parsed. Supports: #rgb / #rrggbb (case-insensitive),
|
|
370
|
+
* CSS named colors, rgb() / rgba() with comma or modern space syntax,
|
|
371
|
+
* including percentages. Alpha in rgba() is ignored.
|
|
372
|
+
*/
|
|
373
|
+
function normalizeColor(value) {
|
|
374
|
+
if (typeof value !== 'string') return null;
|
|
375
|
+
const input = value.trim();
|
|
376
|
+
if (!input) return null;
|
|
377
|
+
const lower = input.toLowerCase();
|
|
378
|
+
if (NAMED_COLORS[lower]) return NAMED_COLORS[lower];
|
|
379
|
+
if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(input)) {
|
|
380
|
+
const hex = input.slice(1).toLowerCase();
|
|
381
|
+
if (hex.length === 3) return `#${hex.split('').map((c) => c + c).join('')}`;
|
|
382
|
+
return `#${hex}`;
|
|
383
|
+
}
|
|
384
|
+
const match = input.match(/^rgba?\((.*)\)$/i);
|
|
385
|
+
if (match) return normalizeRgbArgs(match[1]);
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function hexToRgba(color, alpha = 1) {
|
|
390
|
+
const hex = normalizeColor(color);
|
|
391
|
+
if (!hex) return 'rgba(0, 0, 0, 0)';
|
|
392
|
+
const value = Number.parseInt(hex.slice(1), 16);
|
|
393
|
+
const red = (value >> 16) & 255;
|
|
394
|
+
const green = (value >> 8) & 255;
|
|
395
|
+
const blue = value & 255;
|
|
396
|
+
return `rgba(${red}, ${green}, ${blue}, ${alpha})`;
|
|
209
397
|
}
|
|
210
398
|
|
|
211
399
|
/**
|
|
@@ -911,6 +1099,22 @@ function attachProgressFlowOverlay({ root, canvas, preset, getProgress }) {
|
|
|
911
1099
|
};
|
|
912
1100
|
}
|
|
913
1101
|
|
|
1102
|
+
/**
|
|
1103
|
+
* Run a callback asynchronously, right after the current task and before the
|
|
1104
|
+
* next paint. Used for mount-time events (ready / error) so listeners that
|
|
1105
|
+
* are attached after create() still receive them. Falls back for legacy
|
|
1106
|
+
* browsers that lack queueMicrotask / Promise.
|
|
1107
|
+
*/
|
|
1108
|
+
function nextTick(fn) {
|
|
1109
|
+
if (typeof queueMicrotask === 'function') {
|
|
1110
|
+
queueMicrotask(fn);
|
|
1111
|
+
} else if (typeof Promise !== 'undefined' && typeof Promise.resolve === 'function') {
|
|
1112
|
+
Promise.resolve().then(fn);
|
|
1113
|
+
} else {
|
|
1114
|
+
setTimeout(fn, 0);
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
|
|
914
1118
|
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
915
1119
|
const SUPPORTS_CTX_FILTER = typeof CanvasRenderingContext2D !== 'undefined' && 'filter' in CanvasRenderingContext2D.prototype;
|
|
916
1120
|
|
|
@@ -990,14 +1194,16 @@ const FLOW_PROFILES = {
|
|
|
990
1194
|
};
|
|
991
1195
|
|
|
992
1196
|
class ProgressCapsuleController {
|
|
993
|
-
constructor({ root, canvas, valueElement, preset, emitter, options, copy }) {
|
|
1197
|
+
constructor({ root, canvas, valueElement, preset, emitter, options, copy, dirty }) {
|
|
994
1198
|
this.root = root;
|
|
995
1199
|
this.canvas = canvas;
|
|
996
1200
|
this.valueElement = valueElement;
|
|
997
1201
|
this.preset = preset;
|
|
998
1202
|
this.emitter = emitter;
|
|
999
|
-
this.options = options;
|
|
1000
|
-
this.copy = copy;
|
|
1203
|
+
this.options = options;
|
|
1204
|
+
this.copy = copy;
|
|
1205
|
+
this.dirty = dirty;
|
|
1206
|
+
this.valueSuffix = options.valueSuffix ?? copy.valueSuffix;
|
|
1001
1207
|
this.profile = preset.edgeStyle === 'tide'
|
|
1002
1208
|
? FLOW_PROFILES.tide
|
|
1003
1209
|
: (FLOW_PROFILES[preset.id] || FLOW_PROFILES['visual-training']);
|
|
@@ -1038,11 +1244,22 @@ class ProgressCapsuleController {
|
|
|
1038
1244
|
this.value = clamp(nextValue, this.min, this.max);
|
|
1039
1245
|
const rounded = Math.round(this.value);
|
|
1040
1246
|
this.root.style.setProperty('--progress', this.value.toFixed(2));
|
|
1041
|
-
this.root.setAttribute('aria-valuenow', String(rounded));
|
|
1042
|
-
this.root.setAttribute('aria-valuetext', `${rounded}${this.
|
|
1043
|
-
this.valueElement.textContent = `${rounded}${this.
|
|
1044
|
-
if (!this.suppressEvents)
|
|
1045
|
-
|
|
1247
|
+
this.root.setAttribute('aria-valuenow', String(rounded));
|
|
1248
|
+
this.root.setAttribute('aria-valuetext', `${rounded}${this.valueSuffix}`);
|
|
1249
|
+
if (this.valueElement) this.valueElement.textContent = `${rounded}${this.valueSuffix}`;
|
|
1250
|
+
if (!this.suppressEvents) {
|
|
1251
|
+
if (this.dirty) this.dirty.value = true;
|
|
1252
|
+
this.emitter.emit('change', { value: this.value, source });
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
setValueSuffix(suffix) {
|
|
1257
|
+
this.valueSuffix = String(suffix == null ? '' : suffix);
|
|
1258
|
+
const rounded = Math.round(this.value);
|
|
1259
|
+
if (this.valueElement) this.valueElement.textContent = `${rounded}${this.valueSuffix}`;
|
|
1260
|
+
this.root.setAttribute('aria-valuetext', `${rounded}${this.valueSuffix}`);
|
|
1261
|
+
return this;
|
|
1262
|
+
}
|
|
1046
1263
|
|
|
1047
1264
|
resizeCanvas() {
|
|
1048
1265
|
const bounds = this.root.getBoundingClientRect();
|
|
@@ -1215,13 +1432,14 @@ class ProgressCapsuleController {
|
|
|
1215
1432
|
if (clamped !== this.value) this.setProgress(clamped, 'prop');
|
|
1216
1433
|
}
|
|
1217
1434
|
|
|
1218
|
-
drawReferenceFlow() {
|
|
1435
|
+
drawReferenceFlow() {
|
|
1219
1436
|
const ctx = this.ctx;
|
|
1220
1437
|
const width = this.width;
|
|
1221
1438
|
const height = this.height;
|
|
1222
1439
|
if (!ctx || width <= 0 || height <= 0) return;
|
|
1223
1440
|
|
|
1224
|
-
const
|
|
1441
|
+
const range = Math.max(this.max - this.min, 1);
|
|
1442
|
+
const shoreline = width * Math.min(Math.max((this.value - this.min) / range, 0), 1);
|
|
1225
1443
|
const time = this.flowTime;
|
|
1226
1444
|
const [dark, accentA, accentB, glow] = this.preset.colors;
|
|
1227
1445
|
|
|
@@ -1339,32 +1557,49 @@ class ProgressCapsuleController {
|
|
|
1339
1557
|
}
|
|
1340
1558
|
}
|
|
1341
1559
|
|
|
1342
|
-
updateFromPointer(event) {
|
|
1343
|
-
const bounds = this.root.getBoundingClientRect();
|
|
1344
|
-
const ratio = bounds.width > 0 ? (event.clientX - bounds.left) / bounds.width : 0;
|
|
1345
|
-
this.setProgress(ratio *
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
beginDrag(event) {
|
|
1349
|
-
if (event.button !== undefined && event.button !== 0) return;
|
|
1350
|
-
event.preventDefault();
|
|
1351
|
-
this.dragging = true;
|
|
1352
|
-
this.
|
|
1353
|
-
|
|
1354
|
-
this.
|
|
1355
|
-
this.
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
this.
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
if (
|
|
1366
|
-
this.
|
|
1367
|
-
|
|
1560
|
+
updateFromPointer(event) {
|
|
1561
|
+
const bounds = this.root.getBoundingClientRect();
|
|
1562
|
+
const ratio = bounds.width > 0 ? (event.clientX - bounds.left) / bounds.width : 0;
|
|
1563
|
+
this.setProgress(this.min + ratio * (this.max - this.min), 'drag');
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
beginDrag(event) {
|
|
1567
|
+
if (event.button !== undefined && event.button !== 0) return;
|
|
1568
|
+
event.preventDefault();
|
|
1569
|
+
this.dragging = true;
|
|
1570
|
+
this.pendingPointer = null;
|
|
1571
|
+
this._dragRaf = 0;
|
|
1572
|
+
this.root.classList.add('is-dragging');
|
|
1573
|
+
try { this.root.setPointerCapture?.(event.pointerId); } catch {}
|
|
1574
|
+
this.emitter.emit('dragstart', { value: this.value });
|
|
1575
|
+
this.updateFromPointer(event);
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
moveDrag(event) {
|
|
1579
|
+
if (!this.dragging) return;
|
|
1580
|
+
event.preventDefault();
|
|
1581
|
+
// rAF 合并:一帧最多一次 setProgress/change,视觉仍每帧更新。
|
|
1582
|
+
this.pendingPointer = event;
|
|
1583
|
+
if (this._dragRaf) return;
|
|
1584
|
+
this._dragRaf = requestAnimationFrame(() => {
|
|
1585
|
+
this._dragRaf = 0;
|
|
1586
|
+
const pending = this.pendingPointer;
|
|
1587
|
+
this.pendingPointer = null;
|
|
1588
|
+
if (pending) this.updateFromPointer(pending);
|
|
1589
|
+
});
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
endDrag(event) {
|
|
1593
|
+
if (!this.dragging) return;
|
|
1594
|
+
this.dragging = false;
|
|
1595
|
+
if (this._dragRaf) {
|
|
1596
|
+
cancelAnimationFrame(this._dragRaf);
|
|
1597
|
+
this._dragRaf = 0;
|
|
1598
|
+
}
|
|
1599
|
+
const pending = this.pendingPointer;
|
|
1600
|
+
this.pendingPointer = null;
|
|
1601
|
+
if (pending) this.updateFromPointer(pending);
|
|
1602
|
+
this.root.classList.remove('is-dragging');
|
|
1368
1603
|
try {
|
|
1369
1604
|
if (event?.pointerId !== undefined && this.root.hasPointerCapture?.(event.pointerId)) {
|
|
1370
1605
|
this.root.releasePointerCapture(event.pointerId);
|
|
@@ -1386,15 +1621,16 @@ class ProgressCapsuleController {
|
|
|
1386
1621
|
}
|
|
1387
1622
|
|
|
1388
1623
|
if (this.options.keyboard !== false) {
|
|
1389
|
-
this.handlers.keydown = (event) => {
|
|
1390
|
-
const
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1624
|
+
this.handlers.keydown = (event) => {
|
|
1625
|
+
const step = (this.max - this.min) * 0.02;
|
|
1626
|
+
const actions = {
|
|
1627
|
+
ArrowLeft: -step,
|
|
1628
|
+
ArrowDown: -step,
|
|
1629
|
+
ArrowRight: step,
|
|
1630
|
+
ArrowUp: step,
|
|
1631
|
+
PageDown: -step * 5,
|
|
1632
|
+
PageUp: step * 5
|
|
1633
|
+
};
|
|
1398
1634
|
if (event.key === 'Home') {
|
|
1399
1635
|
event.preventDefault();
|
|
1400
1636
|
this.setProgress(this.min, 'keyboard');
|
|
@@ -1432,8 +1668,9 @@ class ProgressCapsuleController {
|
|
|
1432
1668
|
this.preset = { ...this.preset, colors };
|
|
1433
1669
|
}
|
|
1434
1670
|
|
|
1435
|
-
dispose() {
|
|
1436
|
-
if (this.
|
|
1671
|
+
dispose() {
|
|
1672
|
+
if (this._dragRaf) cancelAnimationFrame(this._dragRaf);
|
|
1673
|
+
if (this.resizeObserver) this.resizeObserver.disconnect();
|
|
1437
1674
|
else window.removeEventListener('resize', this.resizeCanvas);
|
|
1438
1675
|
for (const name of Object.keys(this.handlers)) {
|
|
1439
1676
|
const handler = this.handlers[name];
|
|
@@ -1444,103 +1681,127 @@ class ProgressCapsuleController {
|
|
|
1444
1681
|
}
|
|
1445
1682
|
|
|
1446
1683
|
/**
|
|
1447
|
-
* Mount a fluid progress capsule into `container`.
|
|
1448
|
-
*
|
|
1449
|
-
* Options: preset (id/code/name or object), width, height, value, min, max,
|
|
1450
|
-
* draggable, keyboard, colors, edgeStyle,
|
|
1451
|
-
*
|
|
1452
|
-
|
|
1453
|
-
|
|
1684
|
+
* Mount a fluid progress capsule into `container`.
|
|
1685
|
+
*
|
|
1686
|
+
* Options: preset (id/code/name or object), width, height, value, min, max,
|
|
1687
|
+
* draggable, keyboard, colors, edgeStyle, textRatio (0-100, text region
|
|
1688
|
+
* width in percent), text (HTML string or DOM nodes for the text slot),
|
|
1689
|
+
* colorContent (HTML string or DOM nodes for the color slot),
|
|
1690
|
+
* showValue (show/hide the right-side percentage), quality,
|
|
1691
|
+
* respectReducedMotion, cssVars.
|
|
1692
|
+
*/
|
|
1693
|
+
function createProgressCapsule(container, options = {}) {
|
|
1454
1694
|
if (!container || typeof container.appendChild !== 'function') {
|
|
1455
1695
|
throw new Error('createProgressCapsule: container element is required');
|
|
1456
1696
|
}
|
|
1457
1697
|
|
|
1458
|
-
const preset = { ...getPreset('progress', options.preset ?? '
|
|
1459
|
-
const merged = normalizeOptions(DEFAULTS.progress, preset, options);
|
|
1460
|
-
const
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1698
|
+
const preset = { ...getPreset('progress', options.preset ?? '星火') };
|
|
1699
|
+
const merged = normalizeOptions(DEFAULTS.progress, preset, options);
|
|
1700
|
+
const normalizedColors = merged.colors.map(normalizeColor);
|
|
1701
|
+
if (normalizedColors.every(Boolean)) preset.colors = normalizedColors;
|
|
1702
|
+
preset.edgeStyle = merged.edgeStyle;
|
|
1703
|
+
const copy = COPY;
|
|
1704
|
+
const customLabel = typeof options.label === 'string' && options.label ? options.label : null;
|
|
1705
|
+
// Vue 的裸布尔属性(<ProgressCapsule disabled />)会传成空字符串,
|
|
1706
|
+
// 这里统一按 true 处理。
|
|
1707
|
+
const disabled = merged.disabled === true || merged.disabled === '' || merged.disabled === 'true';
|
|
1708
|
+
const effectiveDraggable = disabled ? false : merged.draggable !== false;
|
|
1709
|
+
const effectiveKeyboard = disabled ? false : merged.keyboard !== false;
|
|
1710
|
+
const dirty = {
|
|
1711
|
+
preset: false,
|
|
1712
|
+
colors: false,
|
|
1713
|
+
textRatio: false,
|
|
1714
|
+
cssVars: false,
|
|
1715
|
+
edgeStyle: false,
|
|
1716
|
+
value: false
|
|
1717
|
+
};
|
|
1718
|
+
|
|
1719
|
+
const root = document.createElement('div');
|
|
1720
|
+
root.className = 'hj-capsule-root hj-progress-root';
|
|
1721
|
+
root.setAttribute('role', 'slider');
|
|
1722
|
+
root.setAttribute('tabindex', '0');
|
|
1723
|
+
root.setAttribute('data-draggable', String(effectiveDraggable));
|
|
1724
|
+
if (disabled) {
|
|
1725
|
+
root.setAttribute('aria-disabled', 'true');
|
|
1726
|
+
root.classList.add('is-disabled');
|
|
1727
|
+
}
|
|
1467
1728
|
root.setAttribute('aria-valuemin', String(merged.min ?? 0));
|
|
1468
1729
|
root.setAttribute('aria-valuemax', String(merged.max ?? 100));
|
|
1469
1730
|
root.setAttribute('aria-valuenow', String(preset.initialProgress));
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1731
|
+
const updateAria = () => {
|
|
1732
|
+
root.setAttribute(
|
|
1733
|
+
'aria-label',
|
|
1734
|
+
customLabel || interpolate(copy.progressAria, { brand: copy.brandName, code: preset.code, name: preset.name })
|
|
1735
|
+
);
|
|
1736
|
+
};
|
|
1737
|
+
updateAria();
|
|
1738
|
+
if (!effectiveKeyboard) root.setAttribute('tabindex', '-1');
|
|
1475
1739
|
|
|
1476
1740
|
const canvas = document.createElement('canvas');
|
|
1477
1741
|
canvas.className = 'hj-progress-canvas';
|
|
1478
1742
|
canvas.setAttribute('aria-hidden', 'true');
|
|
1479
1743
|
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
const
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
const
|
|
1490
|
-
const
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
const
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
root.style.height = parseSize(merged.height);
|
|
1530
|
-
const vars = merged.cssVars || {};
|
|
1531
|
-
for (const name of Object.keys(vars)) root.style.setProperty(name, vars[name]);
|
|
1532
|
-
};
|
|
1744
|
+
// Slot containers are always present but transparent by default; they only
|
|
1745
|
+
// provide geometry, never typography/padding/background (docs: 插槽 CSS 约定).
|
|
1746
|
+
const fillContent = (layer, content) => {
|
|
1747
|
+
layer.innerHTML = '';
|
|
1748
|
+
if (content == null) return;
|
|
1749
|
+
if (typeof content === 'string') {
|
|
1750
|
+
layer.innerHTML = content;
|
|
1751
|
+
return;
|
|
1752
|
+
}
|
|
1753
|
+
const nodes = Array.isArray(content) ? content : [content];
|
|
1754
|
+
for (const node of nodes) {
|
|
1755
|
+
if (node && typeof node.nodeType === 'number') layer.appendChild(node);
|
|
1756
|
+
}
|
|
1757
|
+
};
|
|
1758
|
+
|
|
1759
|
+
const textLayer = document.createElement('div');
|
|
1760
|
+
textLayer.className = 'hj-progress-text hj-progress-copy';
|
|
1761
|
+
|
|
1762
|
+
const visualLayer = document.createElement('div');
|
|
1763
|
+
visualLayer.className = 'hj-progress-visual';
|
|
1764
|
+
|
|
1765
|
+
fillContent(textLayer, options.text);
|
|
1766
|
+
fillContent(visualLayer, options.colorContent);
|
|
1767
|
+
|
|
1768
|
+
const valueElement = merged.showValue === false ? null : document.createElement('div');
|
|
1769
|
+
if (valueElement) {
|
|
1770
|
+
valueElement.className = 'hj-progress-value';
|
|
1771
|
+
valueElement.setAttribute('aria-hidden', 'true');
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
root.appendChild(canvas);
|
|
1775
|
+
root.appendChild(textLayer);
|
|
1776
|
+
root.appendChild(visualLayer);
|
|
1777
|
+
if (valueElement) root.appendChild(valueElement);
|
|
1778
|
+
container.appendChild(root);
|
|
1779
|
+
|
|
1780
|
+
const emitter = createEmitter();
|
|
1781
|
+
let paused = merged.respectReducedMotion && prefersReducedMotion();
|
|
1782
|
+
let disposed = false;
|
|
1783
|
+
|
|
1784
|
+
const applySize = () => {
|
|
1785
|
+
root.style.width = parseSize(merged.width);
|
|
1786
|
+
root.style.height = parseSize(merged.height);
|
|
1787
|
+
const vars = merged.cssVars || {};
|
|
1788
|
+
for (const name of Object.keys(vars)) root.style.setProperty(name, vars[name]);
|
|
1789
|
+
if (merged.textRatio !== undefined) {
|
|
1790
|
+
root.style.setProperty('--hj-text-width', `${merged.textRatio}%`);
|
|
1791
|
+
}
|
|
1792
|
+
};
|
|
1533
1793
|
applySize();
|
|
1534
1794
|
|
|
1535
|
-
const controller = new ProgressCapsuleController({
|
|
1536
|
-
root,
|
|
1537
|
-
canvas,
|
|
1538
|
-
valueElement,
|
|
1539
|
-
preset,
|
|
1540
|
-
emitter,
|
|
1541
|
-
options: merged,
|
|
1542
|
-
copy
|
|
1543
|
-
|
|
1795
|
+
const controller = new ProgressCapsuleController({
|
|
1796
|
+
root,
|
|
1797
|
+
canvas,
|
|
1798
|
+
valueElement,
|
|
1799
|
+
preset,
|
|
1800
|
+
emitter,
|
|
1801
|
+
options: { ...merged, draggable: effectiveDraggable, keyboard: effectiveKeyboard },
|
|
1802
|
+
copy,
|
|
1803
|
+
dirty
|
|
1804
|
+
});
|
|
1544
1805
|
|
|
1545
1806
|
let overlay = null;
|
|
1546
1807
|
if (merged.renderer !== 'canvas2d') {
|
|
@@ -1551,7 +1812,13 @@ function createProgressCapsule(container, options = {}) {
|
|
|
1551
1812
|
getProgress: () => controller.value
|
|
1552
1813
|
});
|
|
1553
1814
|
}
|
|
1554
|
-
if (overlay) controller.webglActive = true;
|
|
1815
|
+
if (overlay) controller.webglActive = true;
|
|
1816
|
+
else if (merged.renderer !== 'canvas2d') {
|
|
1817
|
+
nextTick(() => {
|
|
1818
|
+
if (disposed) return;
|
|
1819
|
+
emitter.emit('error', { message: 'WebGL2 unavailable, using Canvas2D fallback' });
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1555
1822
|
|
|
1556
1823
|
const visibility = createVisibilityGuard(root);
|
|
1557
1824
|
let flowTime = 0;
|
|
@@ -1567,15 +1834,14 @@ function createProgressCapsule(container, options = {}) {
|
|
|
1567
1834
|
() => paused
|
|
1568
1835
|
);
|
|
1569
1836
|
|
|
1570
|
-
|
|
1837
|
+
nextTick(() => {
|
|
1838
|
+
if (disposed) return;
|
|
1839
|
+
emitter.emit('ready', { preset: { ...preset } });
|
|
1840
|
+
});
|
|
1571
1841
|
|
|
1572
|
-
const syncDom = () => {
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
interpolate(copy.progressAria, { brand: copy.brandName, code: preset.code, name: preset.name })
|
|
1576
|
-
);
|
|
1577
|
-
renderCopy();
|
|
1578
|
-
};
|
|
1842
|
+
const syncDom = () => {
|
|
1843
|
+
updateAria();
|
|
1844
|
+
};
|
|
1579
1845
|
|
|
1580
1846
|
return {
|
|
1581
1847
|
element: root,
|
|
@@ -1594,31 +1860,84 @@ function createProgressCapsule(container, options = {}) {
|
|
|
1594
1860
|
controller.setRange(min, max);
|
|
1595
1861
|
return this;
|
|
1596
1862
|
},
|
|
1597
|
-
setPreset(ref) {
|
|
1598
|
-
const next = getPreset('progress', ref);
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
controller.
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
return this;
|
|
1863
|
+
setPreset(ref) {
|
|
1864
|
+
const next = getPreset('progress', ref);
|
|
1865
|
+
dirty.preset = true;
|
|
1866
|
+
Object.assign(preset, next);
|
|
1867
|
+
const nextColors = preset.colors.map(normalizeColor);
|
|
1868
|
+
if (nextColors.every(Boolean)) preset.colors = nextColors;
|
|
1869
|
+
controller.preset = preset;
|
|
1870
|
+
controller.profile = next.edgeStyle === 'tide'
|
|
1871
|
+
? FLOW_PROFILES.tide
|
|
1872
|
+
: (FLOW_PROFILES[next.id] || FLOW_PROFILES['visual-training']);
|
|
1873
|
+
controller.flowTime = stringSeed(next.id) * 31;
|
|
1874
|
+
controller.seed = stringSeed(`${next.id}-reference`) * Math.PI * 2;
|
|
1875
|
+
syncDom();
|
|
1876
|
+
if (overlay) {
|
|
1877
|
+
overlay.dispose();
|
|
1878
|
+
overlay = attachProgressFlowOverlay({ root, canvas, preset, getProgress: () => controller.value });
|
|
1879
|
+
}
|
|
1880
|
+
controller.webglActive = Boolean(overlay);
|
|
1881
|
+
controller.resizeCanvas();
|
|
1882
|
+
emitter.emit('presetchange', { preset: { ...preset } });
|
|
1883
|
+
return this;
|
|
1884
|
+
},
|
|
1885
|
+
setEdgeStyle(edgeStyle) {
|
|
1886
|
+
const value = String(edgeStyle || '').toLowerCase();
|
|
1887
|
+
if (value !== 'flow' && value !== 'tide') return this;
|
|
1888
|
+
dirty.edgeStyle = true;
|
|
1889
|
+
preset.edgeStyle = value;
|
|
1890
|
+
controller.profile = value === 'tide'
|
|
1891
|
+
? FLOW_PROFILES.tide
|
|
1892
|
+
: (FLOW_PROFILES[preset.id] || FLOW_PROFILES['visual-training']);
|
|
1893
|
+
if (overlay) {
|
|
1894
|
+
overlay.dispose();
|
|
1895
|
+
overlay = attachProgressFlowOverlay({ root, canvas, preset, getProgress: () => controller.value });
|
|
1896
|
+
}
|
|
1897
|
+
controller.webglActive = Boolean(overlay);
|
|
1898
|
+
controller.resizeCanvas();
|
|
1899
|
+
return this;
|
|
1900
|
+
},
|
|
1901
|
+
setText(content) {
|
|
1902
|
+
fillContent(textLayer, content);
|
|
1903
|
+
return this;
|
|
1904
|
+
},
|
|
1905
|
+
setColorContent(content) {
|
|
1906
|
+
fillContent(visualLayer, content);
|
|
1907
|
+
return this;
|
|
1908
|
+
},
|
|
1909
|
+
setTextRatio(ratio) {
|
|
1910
|
+
const value = Number(ratio);
|
|
1911
|
+
if (!Number.isFinite(value) || value < 0 || value > 100) return this;
|
|
1912
|
+
dirty.textRatio = true;
|
|
1913
|
+
merged.textRatio = value;
|
|
1914
|
+
root.style.setProperty('--hj-text-width', `${value}%`);
|
|
1915
|
+
return this;
|
|
1916
|
+
},
|
|
1917
|
+
setCssVars(vars) {
|
|
1918
|
+
if (!vars || typeof vars !== 'object') return this;
|
|
1919
|
+
dirty.cssVars = true;
|
|
1920
|
+
merged.cssVars = { ...(merged.cssVars || {}), ...vars };
|
|
1921
|
+
for (const name of Object.keys(vars)) root.style.setProperty(name, vars[name]);
|
|
1922
|
+
return this;
|
|
1923
|
+
},
|
|
1924
|
+
setLabel(label) {
|
|
1925
|
+
customLabel = typeof label === 'string' && label ? label : null;
|
|
1926
|
+
updateAria();
|
|
1927
|
+
return this;
|
|
1928
|
+
},
|
|
1929
|
+
setValueSuffix(suffix) {
|
|
1930
|
+
controller.setValueSuffix(suffix);
|
|
1931
|
+
return this;
|
|
1932
|
+
},
|
|
1933
|
+
setColors(colors) {
|
|
1934
|
+
const next = Array.isArray(colors) ? colors.map(normalizeColor) : [];
|
|
1935
|
+
if (next.length !== 4 || next.some((color) => !color)) return this;
|
|
1936
|
+
dirty.colors = true;
|
|
1937
|
+
controller.setColors(next);
|
|
1938
|
+
if (overlay) overlay.setColors(next);
|
|
1939
|
+
controller.resizeCanvas();
|
|
1940
|
+
return this;
|
|
1622
1941
|
},
|
|
1623
1942
|
setSize(width, height) {
|
|
1624
1943
|
if (width !== undefined) merged.width = width;
|
|
@@ -1645,14 +1964,18 @@ function createProgressCapsule(container, options = {}) {
|
|
|
1645
1964
|
controller.resizeCanvas();
|
|
1646
1965
|
return this;
|
|
1647
1966
|
},
|
|
1648
|
-
dispose() {
|
|
1649
|
-
|
|
1967
|
+
dispose() {
|
|
1968
|
+
disposed = true;
|
|
1969
|
+
unsubscribe();
|
|
1650
1970
|
visibility.dispose();
|
|
1651
1971
|
if (overlay) overlay.dispose();
|
|
1652
|
-
controller.dispose();
|
|
1653
|
-
root.remove();
|
|
1654
|
-
}
|
|
1655
|
-
|
|
1972
|
+
controller.dispose();
|
|
1973
|
+
root.remove();
|
|
1974
|
+
},
|
|
1975
|
+
textRatio: merged.textRatio,
|
|
1976
|
+
cssVars: merged.cssVars,
|
|
1977
|
+
dirty
|
|
1978
|
+
};
|
|
1656
1979
|
}
|
|
1657
1980
|
|
|
1658
1981
|
export { ProgressCapsuleController, createProgressCapsule };
|