@5even7/dlc-ui 0.2.2 → 0.2.4

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/progress.mjs CHANGED
@@ -147,9 +147,13 @@ function getPreset(kind, ref) {
147
147
  const list = PROGRESS_PRESETS ;
148
148
  if (!list) throw new Error(`Unknown preset kind: ${kind} (use "capsule" or "progress")`);
149
149
  const key = String(ref).trim().toLowerCase();
150
- const found = list.find(
151
- (preset) => preset.name.toLowerCase() === key
152
- );
150
+ let found = null;
151
+ for (let index = 0; index < list.length; index += 1) {
152
+ if (list[index].name.toLowerCase() === key) {
153
+ found = list[index];
154
+ break;
155
+ }
156
+ }
153
157
  if (!found) throw new Error(`Unknown ${kind} preset: ${ref}`);
154
158
  return found;
155
159
  }
@@ -159,10 +163,10 @@ const DEFAULTS = {
159
163
  width: 454,
160
164
  height: 104,
161
165
  min: 0,
162
- max: 100,
166
+ max: 100,
163
167
  draggable: true,
164
- keyboard: true,
165
168
  disabled: false,
169
+ readonly: false,
166
170
  valueSuffix: '%',
167
171
  edgeStyle: 'flow',
168
172
  quality: 'auto',
@@ -353,7 +357,7 @@ function normalizeRgbArgs(args) {
353
357
  if (parts.length < 3) return null;
354
358
  const to255 = (value) => {
355
359
  if (typeof value !== 'string' || !value) return null;
356
- if (value.endsWith('%')) return clampChannel((parseFloat(value) / 100) * 255);
360
+ if (value.charAt(value.length - 1) === '%') return clampChannel((parseFloat(value) / 100) * 255);
357
361
  const number = Number(value);
358
362
  return Number.isFinite(number) ? clampChannel(number) : null;
359
363
  };
@@ -361,7 +365,11 @@ function normalizeRgbArgs(args) {
361
365
  const green = to255(parts[1]);
362
366
  const blue = to255(parts[2]);
363
367
  if (red === null || green === null || blue === null) return null;
364
- return `#${[red, green, blue].map((n) => n.toString(16).padStart(2, '0')).join('')}`;
368
+ const hex = (n) => {
369
+ const text = n.toString(16);
370
+ return text.length === 1 ? `0${text}` : text;
371
+ };
372
+ return `#${hex(red)}${hex(green)}${hex(blue)}`;
365
373
  }
366
374
 
367
375
  /**
@@ -973,13 +981,17 @@ const PALETTES = {
973
981
  'tide': ['#0a2239', '#2e9bff', '#7fe3ff', '#eaf9ff']
974
982
  };
975
983
 
976
- function drawCloud(context, x, y, radiusX, radiusY, color, alpha) {
977
- context.save();
978
- context.translate(x, y);
979
- context.scale(1, radiusY / radiusX);
980
- const gradient = context.createRadialGradient(0, 0, 0, 0, 0, radiusX);
981
- gradient.addColorStop(0, `${color}${Math.round(alpha * 255).toString(16).padStart(2, '0')}`);
982
- gradient.addColorStop(0.46, `${color}${Math.round(alpha * 0.42 * 255).toString(16).padStart(2, '0')}`);
984
+ function drawCloud(context, x, y, radiusX, radiusY, color, alpha) {
985
+ context.save();
986
+ context.translate(x, y);
987
+ context.scale(1, radiusY / radiusX);
988
+ const gradient = context.createRadialGradient(0, 0, 0, 0, 0, radiusX);
989
+ const alphaHex = (value) => {
990
+ const text = Math.round(value).toString(16);
991
+ return text.length === 1 ? `0${text}` : text;
992
+ };
993
+ gradient.addColorStop(0, `${color}${alphaHex(alpha * 255)}`);
994
+ gradient.addColorStop(0.46, `${color}${alphaHex(alpha * 0.42 * 255)}`);
983
995
  gradient.addColorStop(1, `${color}00`);
984
996
  context.fillStyle = gradient;
985
997
  context.fillRect(-radiusX, -radiusX, radiusX * 2, radiusX * 2);
@@ -1425,9 +1437,14 @@ class ProgressCapsuleController {
1425
1437
  ctx.restore();
1426
1438
  }
1427
1439
 
1428
- setRange(min, max) {
1429
- this.min = min;
1430
- this.max = max;
1440
+ setRange(min, max) {
1441
+ if (min > max) {
1442
+ const swap = min;
1443
+ min = max;
1444
+ max = swap;
1445
+ }
1446
+ this.min = min;
1447
+ this.max = max;
1431
1448
  const clamped = clamp(this.value, this.min, this.max);
1432
1449
  if (clamped !== this.value) this.setProgress(clamped, 'prop');
1433
1450
  }
@@ -1566,6 +1583,8 @@ class ProgressCapsuleController {
1566
1583
  beginDrag(event) {
1567
1584
  if (event.button !== undefined && event.button !== 0) return;
1568
1585
  event.preventDefault();
1586
+ // preventDefault 会吞掉点击聚焦,主动聚焦让键盘方向键立即可用。
1587
+ try { this.root.focus({ preventScroll: true }); } catch { this.root.focus(); }
1569
1588
  this.dragging = true;
1570
1589
  this.pendingPointer = null;
1571
1590
  this._dragRaf = 0;
@@ -1620,33 +1639,7 @@ class ProgressCapsuleController {
1620
1639
  this.root.addEventListener('pointercancel', this.handlers.pointercancel);
1621
1640
  }
1622
1641
 
1623
- if (this.options.keyboard !== false) {
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
- };
1634
- if (event.key === 'Home') {
1635
- event.preventDefault();
1636
- this.setProgress(this.min, 'keyboard');
1637
- } else if (event.key === 'End') {
1638
- event.preventDefault();
1639
- this.setProgress(this.max, 'keyboard');
1640
- } else if (actions[event.key]) {
1641
- event.preventDefault();
1642
- this.setProgress(this.value + actions[event.key], 'keyboard');
1643
- } else {
1644
- return;
1645
- }
1646
- };
1647
- this.root.addEventListener('keydown', this.handlers.keydown);
1648
- }
1649
- }
1642
+ }
1650
1643
 
1651
1644
  update(delta, paused) {
1652
1645
  if (!paused) this.flowTime += delta;
@@ -1684,7 +1677,7 @@ class ProgressCapsuleController {
1684
1677
  * Mount a fluid progress capsule into `container`.
1685
1678
  *
1686
1679
  * Options: preset (id/code/name or object), width, height, value, min, max,
1687
- * draggable, keyboard, colors, edgeStyle, textRatio (0-100, text region
1680
+ * draggable, colors, edgeStyle, textRatio (0-100, text region
1688
1681
  * width in percent), text (HTML string or DOM nodes for the text slot),
1689
1682
  * colorContent (HTML string or DOM nodes for the color slot),
1690
1683
  * showValue (show/hide the right-side percentage), quality,
@@ -1697,6 +1690,11 @@ function createProgressCapsule(container, options = {}) {
1697
1690
 
1698
1691
  const preset = { ...getPreset('progress', options.preset ?? '星火') };
1699
1692
  const merged = normalizeOptions(DEFAULTS.progress, preset, options);
1693
+ if (merged.min > merged.max) {
1694
+ const swap = merged.min;
1695
+ merged.min = merged.max;
1696
+ merged.max = swap;
1697
+ }
1700
1698
  const normalizedColors = merged.colors.map(normalizeColor);
1701
1699
  if (normalizedColors.every(Boolean)) preset.colors = normalizedColors;
1702
1700
  preset.edgeStyle = merged.edgeStyle;
@@ -1705,8 +1703,9 @@ function createProgressCapsule(container, options = {}) {
1705
1703
  // Vue 的裸布尔属性(<ProgressCapsule disabled />)会传成空字符串,
1706
1704
  // 这里统一按 true 处理。
1707
1705
  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;
1706
+ const readonly = merged.readonly === true || merged.readonly === '' || merged.readonly === 'true';
1707
+ const locked = disabled || readonly;
1708
+ const effectiveDraggable = locked ? false : merged.draggable !== false;
1710
1709
  const dirty = {
1711
1710
  preset: false,
1712
1711
  colors: false,
@@ -1719,12 +1718,16 @@ function createProgressCapsule(container, options = {}) {
1719
1718
  const root = document.createElement('div');
1720
1719
  root.className = 'hj-capsule-root hj-progress-root';
1721
1720
  root.setAttribute('role', 'slider');
1722
- root.setAttribute('tabindex', '0');
1723
1721
  root.setAttribute('data-draggable', String(effectiveDraggable));
1724
1722
  if (disabled) {
1725
1723
  root.setAttribute('aria-disabled', 'true');
1726
1724
  root.classList.add('is-disabled');
1727
1725
  }
1726
+ if (readonly) {
1727
+ root.setAttribute('aria-readonly', 'true');
1728
+ root.classList.add('is-readonly');
1729
+ }
1730
+ if (locked) root.setAttribute('tabindex', '-1');
1728
1731
  root.setAttribute('aria-valuemin', String(merged.min ?? 0));
1729
1732
  root.setAttribute('aria-valuemax', String(merged.max ?? 100));
1730
1733
  root.setAttribute('aria-valuenow', String(preset.initialProgress));
@@ -1735,8 +1738,6 @@ function createProgressCapsule(container, options = {}) {
1735
1738
  );
1736
1739
  };
1737
1740
  updateAria();
1738
- if (!effectiveKeyboard) root.setAttribute('tabindex', '-1');
1739
-
1740
1741
  const canvas = document.createElement('canvas');
1741
1742
  canvas.className = 'hj-progress-canvas';
1742
1743
  canvas.setAttribute('aria-hidden', 'true');
@@ -1798,7 +1799,7 @@ function createProgressCapsule(container, options = {}) {
1798
1799
  valueElement,
1799
1800
  preset,
1800
1801
  emitter,
1801
- options: { ...merged, draggable: effectiveDraggable, keyboard: effectiveKeyboard },
1802
+ options: { ...merged, draggable: effectiveDraggable },
1802
1803
  copy,
1803
1804
  dirty
1804
1805
  });
@@ -1939,10 +1940,16 @@ function createProgressCapsule(container, options = {}) {
1939
1940
  controller.resizeCanvas();
1940
1941
  return this;
1941
1942
  },
1942
- setSize(width, height) {
1943
- if (width !== undefined) merged.width = width;
1944
- if (height !== undefined) merged.height = height;
1945
- applySize();
1943
+ setSize(width, height) {
1944
+ if (width !== undefined) {
1945
+ parseSize(width);
1946
+ merged.width = width;
1947
+ }
1948
+ if (height !== undefined) {
1949
+ parseSize(height);
1950
+ merged.height = height;
1951
+ }
1952
+ applySize();
1946
1953
  controller.resizeCanvas();
1947
1954
  return this;
1948
1955
  },
@@ -1972,8 +1979,8 @@ function createProgressCapsule(container, options = {}) {
1972
1979
  controller.dispose();
1973
1980
  root.remove();
1974
1981
  },
1975
- textRatio: merged.textRatio,
1976
- cssVars: merged.cssVars,
1982
+ get textRatio() { return merged.textRatio; },
1983
+ get cssVars() { return merged.cssVars; },
1977
1984
  dirty
1978
1985
  };
1979
1986
  }
package/dist/vue2.cjs CHANGED
@@ -416,9 +416,13 @@ function getPreset(kind, ref) {
416
416
  var list = kind === 'capsule' ? CAPSULE_PRESETS : kind === 'progress' ? PROGRESS_PRESETS : null;
417
417
  if (!list) throw new Error("Unknown preset kind: ".concat(kind, " (use \"capsule\" or \"progress\")"));
418
418
  var key = String(ref).trim().toLowerCase();
419
- var found = list.find(function (preset) {
420
- return preset.name.toLowerCase() === key;
421
- });
419
+ var found = null;
420
+ for (var index = 0; index < list.length; index += 1) {
421
+ if (list[index].name.toLowerCase() === key) {
422
+ found = list[index];
423
+ break;
424
+ }
425
+ }
422
426
  if (!found) throw new Error("Unknown ".concat(kind, " preset: ").concat(ref));
423
427
  return found;
424
428
  }
@@ -439,8 +443,8 @@ var DEFAULTS = {
439
443
  min: 0,
440
444
  max: 100,
441
445
  draggable: true,
442
- keyboard: true,
443
446
  disabled: false,
447
+ readonly: false,
444
448
  valueSuffix: '%',
445
449
  edgeStyle: 'flow',
446
450
  quality: 'auto',
@@ -629,7 +633,7 @@ function normalizeRgbArgs(args) {
629
633
  if (parts.length < 3) return null;
630
634
  var to255 = function to255(value) {
631
635
  if (typeof value !== 'string' || !value) return null;
632
- if (value.endsWith('%')) return clampChannel(parseFloat(value) / 100 * 255);
636
+ if (value.charAt(value.length - 1) === '%') return clampChannel(parseFloat(value) / 100 * 255);
633
637
  var number = Number(value);
634
638
  return Number.isFinite(number) ? clampChannel(number) : null;
635
639
  };
@@ -637,9 +641,11 @@ function normalizeRgbArgs(args) {
637
641
  var green = to255(parts[1]);
638
642
  var blue = to255(parts[2]);
639
643
  if (red === null || green === null || blue === null) return null;
640
- return "#".concat([red, green, blue].map(function (n) {
641
- return n.toString(16).padStart(2, '0');
642
- }).join(''));
644
+ var hex = function hex(n) {
645
+ var text = n.toString(16);
646
+ return text.length === 1 ? "0".concat(text) : text;
647
+ };
648
+ return "#".concat(hex(red)).concat(hex(green)).concat(hex(blue));
643
649
  }
644
650
 
645
651
  /**
@@ -904,6 +910,7 @@ var FallbackRenderer = /*#__PURE__*/function () {
904
910
  this.preset = preset;
905
911
  this.context = canvas.getContext('2d');
906
912
  this.visible = true;
913
+ this.timePhase = 0;
907
914
  }
908
915
  return _createClass(FallbackRenderer, [{
909
916
  key: "resize",
@@ -924,7 +931,7 @@ var FallbackRenderer = /*#__PURE__*/function () {
924
931
  var _this$canvas = this.canvas,
925
932
  width = _this$canvas.width,
926
933
  height = _this$canvas.height;
927
- var t = time * (this.preset.speed || 1);
934
+ var t = (time + this.timePhase) * (this.preset.speed || 1);
928
935
  var phase = (this.preset.seed || 0) * 0.7;
929
936
  var gradient = ctx.createLinearGradient(0, 0, width, height);
930
937
  gradient.addColorStop(0, this.preset.colors[0]);
@@ -961,7 +968,10 @@ var FallbackRenderer = /*#__PURE__*/function () {
961
968
  }, {
962
969
  key: "randomize",
963
970
  value: function randomize() {
964
- if (this.preset) this.preset.seed = Math.random() * 100;
971
+ if (this.preset) {
972
+ this.preset.seed = Math.random() * 100;
973
+ this.timePhase = Math.random() * Math.PI * 2;
974
+ }
965
975
  }
966
976
  }, {
967
977
  key: "setMouseColor",
@@ -1207,6 +1217,8 @@ function createCapsule(container) {
1207
1217
  }
1208
1218
  if (merged.textRatio !== undefined) {
1209
1219
  root.style.setProperty('--hj-text-width', "".concat(merged.textRatio, "%"));
1220
+ var userMinWidth = merged.cssVars && merged.cssVars['--hj-text-min-width'];
1221
+ if (merged.textRatio === 0) root.style.setProperty('--hj-text-min-width', '0');else if (userMinWidth) root.style.setProperty('--hj-text-min-width', userMinWidth);else root.style.removeProperty('--hj-text-min-width');
1210
1222
  }
1211
1223
  renderer.resize();
1212
1224
  };
@@ -1330,6 +1342,8 @@ function createCapsule(container) {
1330
1342
  dirty.textRatio = true;
1331
1343
  merged.textRatio = value;
1332
1344
  root.style.setProperty('--hj-text-width', "".concat(value, "%"));
1345
+ var userMinWidth = merged.cssVars && merged.cssVars['--hj-text-min-width'];
1346
+ if (value === 0) root.style.setProperty('--hj-text-min-width', '0');else if (userMinWidth) root.style.setProperty('--hj-text-min-width', userMinWidth);else root.style.removeProperty('--hj-text-min-width');
1333
1347
  return this;
1334
1348
  },
1335
1349
  setCssVars: function setCssVars(vars) {
@@ -1348,8 +1362,14 @@ function createCapsule(container) {
1348
1362
  return this;
1349
1363
  },
1350
1364
  setSize: function setSize(width, height) {
1351
- if (width !== undefined) merged.width = width;
1352
- if (height !== undefined) merged.height = height;
1365
+ if (width !== undefined) {
1366
+ parseSize(width); // 非法尺寸直接抛错前先校验,避免污染内部状态
1367
+ merged.width = width;
1368
+ }
1369
+ if (height !== undefined) {
1370
+ parseSize(height);
1371
+ merged.height = height;
1372
+ }
1353
1373
  applySize();
1354
1374
  return this;
1355
1375
  },
@@ -1378,8 +1398,12 @@ function createCapsule(container) {
1378
1398
  renderer.dispose();
1379
1399
  root.remove();
1380
1400
  },
1381
- textRatio: merged.textRatio,
1382
- cssVars: merged.cssVars,
1401
+ get textRatio() {
1402
+ return merged.textRatio;
1403
+ },
1404
+ get cssVars() {
1405
+ return merged.cssVars;
1406
+ },
1383
1407
  dirty: dirty
1384
1408
  };
1385
1409
  }
@@ -1675,8 +1699,12 @@ function drawCloud(context, x, y, radiusX, radiusY, color, alpha) {
1675
1699
  context.translate(x, y);
1676
1700
  context.scale(1, radiusY / radiusX);
1677
1701
  var gradient = context.createRadialGradient(0, 0, 0, 0, 0, radiusX);
1678
- gradient.addColorStop(0, "".concat(color).concat(Math.round(alpha * 255).toString(16).padStart(2, '0')));
1679
- gradient.addColorStop(0.46, "".concat(color).concat(Math.round(alpha * 0.42 * 255).toString(16).padStart(2, '0')));
1702
+ var alphaHex = function alphaHex(value) {
1703
+ var text = Math.round(value).toString(16);
1704
+ return text.length === 1 ? "0".concat(text) : text;
1705
+ };
1706
+ gradient.addColorStop(0, "".concat(color).concat(alphaHex(alpha * 255)));
1707
+ gradient.addColorStop(0.46, "".concat(color).concat(alphaHex(alpha * 0.42 * 255)));
1680
1708
  gradient.addColorStop(1, "".concat(color, "00"));
1681
1709
  context.fillStyle = gradient;
1682
1710
  context.fillRect(-radiusX, -radiusX, radiusX * 2, radiusX * 2);
@@ -2126,6 +2154,11 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2126
2154
  }, {
2127
2155
  key: "setRange",
2128
2156
  value: function setRange(min, max) {
2157
+ if (min > max) {
2158
+ var swap = min;
2159
+ min = max;
2160
+ max = swap;
2161
+ }
2129
2162
  this.min = min;
2130
2163
  this.max = max;
2131
2164
  var clamped = clamp(this.value, this.min, this.max);
@@ -2261,6 +2294,14 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2261
2294
  value: function beginDrag(event) {
2262
2295
  if (event.button !== undefined && event.button !== 0) return;
2263
2296
  event.preventDefault();
2297
+ // preventDefault 会吞掉点击聚焦,主动聚焦让键盘方向键立即可用。
2298
+ try {
2299
+ this.root.focus({
2300
+ preventScroll: true
2301
+ });
2302
+ } catch (_unused) {
2303
+ this.root.focus();
2304
+ }
2264
2305
  this.dragging = true;
2265
2306
  this.pendingPointer = null;
2266
2307
  this._dragRaf = 0;
@@ -2268,7 +2309,7 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2268
2309
  try {
2269
2310
  var _this$root$setPointer, _this$root;
2270
2311
  (_this$root$setPointer = (_this$root = this.root).setPointerCapture) === null || _this$root$setPointer === void 0 || _this$root$setPointer.call(_this$root, event.pointerId);
2271
- } catch (_unused) {}
2312
+ } catch (_unused2) {}
2272
2313
  this.emitter.emit('dragstart', {
2273
2314
  value: this.value
2274
2315
  });
@@ -2308,7 +2349,7 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2308
2349
  if ((event === null || event === void 0 ? void 0 : event.pointerId) !== undefined && (_this$root$hasPointer = (_this$root2 = this.root).hasPointerCapture) !== null && _this$root$hasPointer !== void 0 && _this$root$hasPointer.call(_this$root2, event.pointerId)) {
2309
2350
  this.root.releasePointerCapture(event.pointerId);
2310
2351
  }
2311
- } catch (_unused2) {}
2352
+ } catch (_unused3) {}
2312
2353
  this.emitter.emit('dragend', {
2313
2354
  value: this.value
2314
2355
  });
@@ -2335,32 +2376,6 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2335
2376
  this.root.addEventListener('pointerup', this.handlers.pointerup);
2336
2377
  this.root.addEventListener('pointercancel', this.handlers.pointercancel);
2337
2378
  }
2338
- if (this.options.keyboard !== false) {
2339
- this.handlers.keydown = function (event) {
2340
- var step = (_this3.max - _this3.min) * 0.02;
2341
- var actions = {
2342
- ArrowLeft: -step,
2343
- ArrowDown: -step,
2344
- ArrowRight: step,
2345
- ArrowUp: step,
2346
- PageDown: -step * 5,
2347
- PageUp: step * 5
2348
- };
2349
- if (event.key === 'Home') {
2350
- event.preventDefault();
2351
- _this3.setProgress(_this3.min, 'keyboard');
2352
- } else if (event.key === 'End') {
2353
- event.preventDefault();
2354
- _this3.setProgress(_this3.max, 'keyboard');
2355
- } else if (actions[event.key]) {
2356
- event.preventDefault();
2357
- _this3.setProgress(_this3.value + actions[event.key], 'keyboard');
2358
- } else {
2359
- return;
2360
- }
2361
- };
2362
- this.root.addEventListener('keydown', this.handlers.keydown);
2363
- }
2364
2379
  }
2365
2380
  }, {
2366
2381
  key: "update",
@@ -2407,7 +2422,7 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2407
2422
  * Mount a fluid progress capsule into `container`.
2408
2423
  *
2409
2424
  * Options: preset (id/code/name or object), width, height, value, min, max,
2410
- * draggable, keyboard, colors, edgeStyle, textRatio (0-100, text region
2425
+ * draggable, colors, edgeStyle, textRatio (0-100, text region
2411
2426
  * width in percent), text (HTML string or DOM nodes for the text slot),
2412
2427
  * colorContent (HTML string or DOM nodes for the color slot),
2413
2428
  * showValue (show/hide the right-side percentage), quality,
@@ -2421,6 +2436,11 @@ function createProgressCapsule(container) {
2421
2436
  }
2422
2437
  var preset = _objectSpread2({}, getPreset('progress', (_options$preset = options.preset) !== null && _options$preset !== void 0 ? _options$preset : '星火'));
2423
2438
  var merged = normalizeOptions(DEFAULTS.progress, preset, options);
2439
+ if (merged.min > merged.max) {
2440
+ var swap = merged.min;
2441
+ merged.min = merged.max;
2442
+ merged.max = swap;
2443
+ }
2424
2444
  var normalizedColors = merged.colors.map(normalizeColor);
2425
2445
  if (normalizedColors.every(Boolean)) preset.colors = normalizedColors;
2426
2446
  preset.edgeStyle = merged.edgeStyle;
@@ -2429,8 +2449,9 @@ function createProgressCapsule(container) {
2429
2449
  // Vue 的裸布尔属性(<ProgressCapsule disabled />)会传成空字符串,
2430
2450
  // 这里统一按 true 处理。
2431
2451
  var disabled = merged.disabled === true || merged.disabled === '' || merged.disabled === 'true';
2432
- var effectiveDraggable = disabled ? false : merged.draggable !== false;
2433
- var effectiveKeyboard = disabled ? false : merged.keyboard !== false;
2452
+ var readonly = merged.readonly === true || merged.readonly === '' || merged.readonly === 'true';
2453
+ var locked = disabled || readonly;
2454
+ var effectiveDraggable = locked ? false : merged.draggable !== false;
2434
2455
  var dirty = {
2435
2456
  preset: false,
2436
2457
  colors: false,
@@ -2442,12 +2463,16 @@ function createProgressCapsule(container) {
2442
2463
  var root = document.createElement('div');
2443
2464
  root.className = 'hj-capsule-root hj-progress-root';
2444
2465
  root.setAttribute('role', 'slider');
2445
- root.setAttribute('tabindex', '0');
2446
2466
  root.setAttribute('data-draggable', String(effectiveDraggable));
2447
2467
  if (disabled) {
2448
2468
  root.setAttribute('aria-disabled', 'true');
2449
2469
  root.classList.add('is-disabled');
2450
2470
  }
2471
+ if (readonly) {
2472
+ root.setAttribute('aria-readonly', 'true');
2473
+ root.classList.add('is-readonly');
2474
+ }
2475
+ if (locked) root.setAttribute('tabindex', '-1');
2451
2476
  root.setAttribute('aria-valuemin', String((_merged$min = merged.min) !== null && _merged$min !== void 0 ? _merged$min : 0));
2452
2477
  root.setAttribute('aria-valuemax', String((_merged$max = merged.max) !== null && _merged$max !== void 0 ? _merged$max : 100));
2453
2478
  root.setAttribute('aria-valuenow', String(preset.initialProgress));
@@ -2459,7 +2484,6 @@ function createProgressCapsule(container) {
2459
2484
  }));
2460
2485
  };
2461
2486
  updateAria();
2462
- if (!effectiveKeyboard) root.setAttribute('tabindex', '-1');
2463
2487
  var canvas = document.createElement('canvas');
2464
2488
  canvas.className = 'hj-progress-canvas';
2465
2489
  canvas.setAttribute('aria-hidden', 'true');
@@ -2526,8 +2550,7 @@ function createProgressCapsule(container) {
2526
2550
  preset: preset,
2527
2551
  emitter: emitter,
2528
2552
  options: _objectSpread2(_objectSpread2({}, merged), {}, {
2529
- draggable: effectiveDraggable,
2530
- keyboard: effectiveKeyboard
2553
+ draggable: effectiveDraggable
2531
2554
  }),
2532
2555
  copy: copy,
2533
2556
  dirty: dirty
@@ -2687,8 +2710,14 @@ function createProgressCapsule(container) {
2687
2710
  return this;
2688
2711
  },
2689
2712
  setSize: function setSize(width, height) {
2690
- if (width !== undefined) merged.width = width;
2691
- if (height !== undefined) merged.height = height;
2713
+ if (width !== undefined) {
2714
+ parseSize(width);
2715
+ merged.width = width;
2716
+ }
2717
+ if (height !== undefined) {
2718
+ parseSize(height);
2719
+ merged.height = height;
2720
+ }
2692
2721
  applySize();
2693
2722
  controller.resizeCanvas();
2694
2723
  return this;
@@ -2719,8 +2748,12 @@ function createProgressCapsule(container) {
2719
2748
  controller.dispose();
2720
2749
  root.remove();
2721
2750
  },
2722
- textRatio: merged.textRatio,
2723
- cssVars: merged.cssVars,
2751
+ get textRatio() {
2752
+ return merged.textRatio;
2753
+ },
2754
+ get cssVars() {
2755
+ return merged.cssVars;
2756
+ },
2724
2757
  dirty: dirty
2725
2758
  };
2726
2759
  }
@@ -2925,9 +2958,15 @@ function createColorBackground(host) {
2925
2958
  renderer.dispose();
2926
2959
  layer.remove();
2927
2960
  },
2928
- opacity: merged.opacity,
2929
- fallbackColor: merged.fallbackColor,
2930
- mouseColor: merged.mouseColor,
2961
+ get opacity() {
2962
+ return merged.opacity;
2963
+ },
2964
+ get fallbackColor() {
2965
+ return merged.fallbackColor;
2966
+ },
2967
+ get mouseColor() {
2968
+ return merged.mouseColor;
2969
+ },
2931
2970
  dirty: dirty
2932
2971
  };
2933
2972
  }
@@ -2980,17 +3019,23 @@ function makeWrapper(_ref) {
2980
3019
  this.applyAttrs();
2981
3020
  },
2982
3021
  recreate: function recreate() {
3022
+ var _this2 = this;
2983
3023
  var extraState = this.runtimeState();
2984
3024
  if (this.controller) this.controller.dispose();
2985
3025
  this.mountController(extraState);
3026
+ // 结构属性连续变化时,插槽内容可能在重建后才被 Vue 写入容器,
3027
+ // 补一次搬运确保不丢。
3028
+ this.$nextTick(function () {
3029
+ return _this2.moveSlots();
3030
+ });
2986
3031
  },
2987
3032
  scheduleRecreate: function scheduleRecreate() {
2988
- var _this2 = this;
3033
+ var _this3 = this;
2989
3034
  if (this._recreateQueued) return;
2990
3035
  this._recreateQueued = true;
2991
3036
  this.$nextTick(function () {
2992
- _this2._recreateQueued = false;
2993
- _this2.recreate();
3037
+ _this3._recreateQueued = false;
3038
+ _this3.recreate();
2994
3039
  });
2995
3040
  },
2996
3041
  moveSlots: function moveSlots() {
@@ -2998,22 +3043,21 @@ function makeWrapper(_ref) {
2998
3043
  var root = this.controller.element;
2999
3044
  var textLayer = root.querySelector('.hj-capsule-text, .hj-progress-text');
3000
3045
  var visualLayer = root.querySelector('.hj-capsule-visual, .hj-progress-visual');
3001
- var move = function move(wrapper, layer) {
3002
- if (!wrapper || !layer) return;
3003
- for (var _i = 0, _Array$from = Array.from(wrapper.childNodes); _i < _Array$from.length; _i++) {
3004
- var node = _Array$from[_i];
3005
- layer.appendChild(node);
3006
- }
3007
- };
3008
3046
  var refs = this.$refs || {};
3009
- move(refs.slotText, textLayer);
3010
- move(refs.slotColor, visualLayer);
3047
+ // 把插槽容器整体搬进对应区域,而不是搬子节点:Vue 重渲染/重建组件时
3048
+ // 内容始终留在区域内,不会丢(子节点搬运会在 recreate 时序下丢失)。
3049
+ if (refs.slotText && textLayer && refs.slotText.parentElement !== textLayer) {
3050
+ textLayer.appendChild(refs.slotText);
3051
+ }
3052
+ if (refs.slotColor && visualLayer && refs.slotColor.parentElement !== visualLayer) {
3053
+ visualLayer.appendChild(refs.slotColor);
3054
+ }
3011
3055
  },
3012
3056
  applyAttrs: function applyAttrs() {
3013
3057
  if (!this.controller || !this.controller.element || !this.$attrs) return;
3014
3058
  var root = this.controller.element;
3015
- for (var _i2 = 0, _Object$keys = Object.keys(this.$attrs); _i2 < _Object$keys.length; _i2++) {
3016
- var key = _Object$keys[_i2];
3059
+ for (var _i = 0, _Object$keys = Object.keys(this.$attrs); _i < _Object$keys.length; _i++) {
3060
+ var key = _Object$keys[_i];
3017
3061
  if (key === 'class' || key === 'style') continue;
3018
3062
  var value = this.$attrs[key];
3019
3063
  if (value == null || value === false) root.removeAttribute(key);else root.setAttribute(key, String(value));
@@ -3161,7 +3205,7 @@ function makeCapsuleWrapper(createCapsule, render) {
3161
3205
  function makeProgressWrapper(createProgressCapsule, render) {
3162
3206
  return makeWrapper({
3163
3207
  name: 'ProgressCapsule',
3164
- props: ['preset', 'width', 'height', 'value', 'min', 'max', 'draggable', 'keyboard', 'disabled', 'edgeStyle', 'colors', 'textRatio', 'label', 'showValue', 'valueSuffix', 'quality', 'renderer', 'respectReducedMotion', 'cssVars'],
3208
+ props: ['preset', 'width', 'height', 'value', 'min', 'max', 'draggable', 'disabled', 'readonly', 'edgeStyle', 'colors', 'textRatio', 'label', 'showValue', 'valueSuffix', 'quality', 'renderer', 'respectReducedMotion', 'cssVars'],
3165
3209
  events: PROGRESS_EVENTS,
3166
3210
  create: createProgressCapsule,
3167
3211
  render: render,
@@ -3196,10 +3240,10 @@ function makeProgressWrapper(createProgressCapsule, render) {
3196
3240
  disabled: function disabled() {
3197
3241
  this.scheduleRecreate();
3198
3242
  },
3199
- draggable: function draggable() {
3243
+ readonly: function readonly() {
3200
3244
  this.scheduleRecreate();
3201
3245
  },
3202
- keyboard: function keyboard() {
3246
+ draggable: function draggable() {
3203
3247
  this.scheduleRecreate();
3204
3248
  },
3205
3249
  renderer: function renderer() {