@5even7/dlc-ui 0.2.0 → 0.2.2

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.cjs CHANGED
@@ -418,30 +418,236 @@ var DEFAULTS = {
418
418
  max: 100,
419
419
  draggable: true,
420
420
  keyboard: true,
421
+ disabled: false,
422
+ valueSuffix: '%',
421
423
  edgeStyle: 'flow',
422
424
  quality: 'auto',
423
425
  renderer: 'auto',
424
- showCopy: true,
426
+ textRatio: 54,
427
+ showValue: true,
425
428
  respectReducedMotion: true
426
429
  }
427
430
  };
428
431
 
429
- /**
430
- * All user-facing copy lives here so wording/brand changes never require a
431
- * global search. Templates use {brand} {code} {name} placeholders.
432
+ /**
433
+ * Internal accessibility labels and small UI text. Since the copy API was
434
+ * removed (slots own the text area), these are no longer user-overridable.
435
+ * Templates use {brand} {code} {name} placeholders.
432
436
  */
433
437
  var COPY = {
434
438
  brandName: '画境观屿',
435
- dragLabel: 'DRAG',
436
439
  valueSuffix: '%',
437
440
  progressAria: '{brand} {code} 加载进度',
438
441
  capsuleAria: '打开 {name} 沉浸预览'
439
442
  };
440
443
 
441
- function hexToRgba(hex) {
444
+ /**
445
+ * Color helpers. `normalizeColor` converts any supported CSS color
446
+ * (hex / named / rgb() / rgba()) into a 6-digit hex string, so renderers can
447
+ * keep working with #rrggbb only. rgba() alpha is intentionally dropped:
448
+ * the WebGL shader has no per-color alpha channel, and the component is
449
+ * opaque by design — use component-level `opacity` for transparency.
450
+ */
451
+
452
+ var NAMED_COLORS = {
453
+ aliceblue: '#f0f8ff',
454
+ antiquewhite: '#faebd7',
455
+ aqua: '#00ffff',
456
+ aquamarine: '#7fffd4',
457
+ azure: '#f0ffff',
458
+ beige: '#f5f5dc',
459
+ bisque: '#ffe4c4',
460
+ black: '#000000',
461
+ blanchedalmond: '#ffebcd',
462
+ blue: '#0000ff',
463
+ blueviolet: '#8a2be2',
464
+ brown: '#a52a2a',
465
+ burlywood: '#deb887',
466
+ cadetblue: '#5f9ea0',
467
+ chartreuse: '#7fff00',
468
+ chocolate: '#d2691e',
469
+ coral: '#ff7f50',
470
+ cornflowerblue: '#6495ed',
471
+ cornsilk: '#fff8dc',
472
+ crimson: '#dc143c',
473
+ cyan: '#00ffff',
474
+ darkblue: '#00008b',
475
+ darkcyan: '#008b8b',
476
+ darkgoldenrod: '#b8860b',
477
+ darkgray: '#a9a9a9',
478
+ darkgreen: '#006400',
479
+ darkgrey: '#a9a9a9',
480
+ darkkhaki: '#bdb76b',
481
+ darkmagenta: '#8b008b',
482
+ darkolivegreen: '#556b2f',
483
+ darkorange: '#ff8c00',
484
+ darkorchid: '#9932cc',
485
+ darkred: '#8b0000',
486
+ darksalmon: '#e9967a',
487
+ darkseagreen: '#8fbc8f',
488
+ darkslateblue: '#483d8b',
489
+ darkslategray: '#2f4f4f',
490
+ darkslategrey: '#2f4f4f',
491
+ darkturquoise: '#00ced1',
492
+ darkviolet: '#9400d3',
493
+ deeppink: '#ff1493',
494
+ deepskyblue: '#00bfff',
495
+ dimgray: '#696969',
496
+ dimgrey: '#696969',
497
+ dodgerblue: '#1e90ff',
498
+ firebrick: '#b22222',
499
+ floralwhite: '#fffaf0',
500
+ forestgreen: '#228b22',
501
+ fuchsia: '#ff00ff',
502
+ gainsboro: '#dcdcdc',
503
+ ghostwhite: '#f8f8ff',
504
+ gold: '#ffd700',
505
+ goldenrod: '#daa520',
506
+ gray: '#808080',
507
+ green: '#008000',
508
+ greenyellow: '#adff2f',
509
+ grey: '#808080',
510
+ honeydew: '#f0fff0',
511
+ hotpink: '#ff69b4',
512
+ indianred: '#cd5c5c',
513
+ indigo: '#4b0082',
514
+ ivory: '#fffff0',
515
+ khaki: '#f0e68c',
516
+ lavender: '#e6e6fa',
517
+ lavenderblush: '#fff0f5',
518
+ lawngreen: '#7cfc00',
519
+ lemonchiffon: '#fffacd',
520
+ lightblue: '#add8e6',
521
+ lightcoral: '#f08080',
522
+ lightcyan: '#e0ffff',
523
+ lightgoldenrodyellow: '#fafad2',
524
+ lightgray: '#d3d3d3',
525
+ lightgreen: '#90ee90',
526
+ lightgrey: '#d3d3d3',
527
+ lightpink: '#ffb6c1',
528
+ lightsalmon: '#ffa07a',
529
+ lightseagreen: '#20b2aa',
530
+ lightskyblue: '#87cefa',
531
+ lightslategray: '#778899',
532
+ lightslategrey: '#778899',
533
+ lightsteelblue: '#b0c4de',
534
+ lightyellow: '#ffffe0',
535
+ lime: '#00ff00',
536
+ limegreen: '#32cd32',
537
+ linen: '#faf0e6',
538
+ magenta: '#ff00ff',
539
+ maroon: '#800000',
540
+ mediumaquamarine: '#66cdaa',
541
+ mediumblue: '#0000cd',
542
+ mediumorchid: '#ba55d3',
543
+ mediumpurple: '#9370db',
544
+ mediumseagreen: '#3cb371',
545
+ mediumslateblue: '#7b68ee',
546
+ mediumspringgreen: '#00fa9a',
547
+ mediumturquoise: '#48d1cc',
548
+ mediumvioletred: '#c71585',
549
+ midnightblue: '#191970',
550
+ mintcream: '#f5fffa',
551
+ mistyrose: '#ffe4e1',
552
+ moccasin: '#ffe4b5',
553
+ navajowhite: '#ffdead',
554
+ navy: '#000080',
555
+ oldlace: '#fdf5e6',
556
+ olive: '#808000',
557
+ olivedrab: '#6b8e23',
558
+ orange: '#ffa500',
559
+ orangered: '#ff4500',
560
+ orchid: '#da70d6',
561
+ palegoldenrod: '#eee8aa',
562
+ palegreen: '#98fb98',
563
+ paleturquoise: '#afeeee',
564
+ palevioletred: '#db7093',
565
+ papayawhip: '#ffefd5',
566
+ peachpuff: '#ffdab9',
567
+ peru: '#cd853f',
568
+ pink: '#ffc0cb',
569
+ plum: '#dda0dd',
570
+ powderblue: '#b0e0e6',
571
+ purple: '#800080',
572
+ rebeccapurple: '#663399',
573
+ red: '#ff0000',
574
+ rosybrown: '#bc8f8f',
575
+ royalblue: '#4169e1',
576
+ saddlebrown: '#8b4513',
577
+ salmon: '#fa8072',
578
+ sandybrown: '#f4a460',
579
+ seagreen: '#2e8b57',
580
+ seashell: '#fff5ee',
581
+ sienna: '#a0522d',
582
+ silver: '#c0c0c0',
583
+ skyblue: '#87ceeb',
584
+ slateblue: '#6a5acd',
585
+ slategray: '#708090',
586
+ slategrey: '#708090',
587
+ snow: '#fffafa',
588
+ springgreen: '#00ff7f',
589
+ steelblue: '#4682b4',
590
+ tan: '#d2b48c',
591
+ teal: '#008080',
592
+ thistle: '#d8bfd8',
593
+ tomato: '#ff6347',
594
+ turquoise: '#40e0d0',
595
+ violet: '#ee82ee',
596
+ wheat: '#f5deb3',
597
+ white: '#ffffff',
598
+ whitesmoke: '#f5f5f5',
599
+ yellow: '#ffff00',
600
+ yellowgreen: '#9acd32'
601
+ };
602
+ function clampChannel(value) {
603
+ return Math.min(255, Math.max(0, Math.round(value)));
604
+ }
605
+ function normalizeRgbArgs(args) {
606
+ var parts = args.split(/[,\s/]+/).filter(Boolean);
607
+ if (parts.length < 3) return null;
608
+ var to255 = function to255(value) {
609
+ if (typeof value !== 'string' || !value) return null;
610
+ if (value.endsWith('%')) return clampChannel(parseFloat(value) / 100 * 255);
611
+ var number = Number(value);
612
+ return Number.isFinite(number) ? clampChannel(number) : null;
613
+ };
614
+ var red = to255(parts[0]);
615
+ var green = to255(parts[1]);
616
+ var blue = to255(parts[2]);
617
+ if (red === null || green === null || blue === null) return null;
618
+ return "#".concat([red, green, blue].map(function (n) {
619
+ return n.toString(16).padStart(2, '0');
620
+ }).join(''));
621
+ }
622
+
623
+ /**
624
+ * Convert any supported CSS color into `#rrggbb`. Returns null when the
625
+ * value cannot be parsed. Supports: #rgb / #rrggbb (case-insensitive),
626
+ * CSS named colors, rgb() / rgba() with comma or modern space syntax,
627
+ * including percentages. Alpha in rgba() is ignored.
628
+ */
629
+ function normalizeColor(value) {
630
+ if (typeof value !== 'string') return null;
631
+ var input = value.trim();
632
+ if (!input) return null;
633
+ var lower = input.toLowerCase();
634
+ if (NAMED_COLORS[lower]) return NAMED_COLORS[lower];
635
+ if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(input)) {
636
+ var hex = input.slice(1).toLowerCase();
637
+ if (hex.length === 3) return "#".concat(hex.split('').map(function (c) {
638
+ return c + c;
639
+ }).join(''));
640
+ return "#".concat(hex);
641
+ }
642
+ var match = input.match(/^rgba?\((.*)\)$/i);
643
+ if (match) return normalizeRgbArgs(match[1]);
644
+ return null;
645
+ }
646
+ function hexToRgba(color) {
442
647
  var alpha = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
443
- var normalized = hex.replace('#', '');
444
- var value = Number.parseInt(normalized, 16);
648
+ var hex = normalizeColor(color);
649
+ if (!hex) return 'rgba(0, 0, 0, 0)';
650
+ var value = Number.parseInt(hex.slice(1), 16);
445
651
  var red = value >> 16 & 255;
446
652
  var green = value >> 8 & 255;
447
653
  var blue = value & 255;
@@ -964,6 +1170,22 @@ function attachProgressFlowOverlay(_ref) {
964
1170
  };
965
1171
  }
966
1172
 
1173
+ /**
1174
+ * Run a callback asynchronously, right after the current task and before the
1175
+ * next paint. Used for mount-time events (ready / error) so listeners that
1176
+ * are attached after create() still receive them. Falls back for legacy
1177
+ * browsers that lack queueMicrotask / Promise.
1178
+ */
1179
+ function nextTick(fn) {
1180
+ if (typeof queueMicrotask === 'function') {
1181
+ queueMicrotask(fn);
1182
+ } else if (typeof Promise !== 'undefined' && typeof Promise.resolve === 'function') {
1183
+ Promise.resolve().then(fn);
1184
+ } else {
1185
+ setTimeout(fn, 0);
1186
+ }
1187
+ }
1188
+
967
1189
  var clamp = function clamp(value, min, max) {
968
1190
  return Math.min(Math.max(value, min), max);
969
1191
  };
@@ -1052,7 +1274,8 @@ var FLOW_PROFILES = {
1052
1274
  };
1053
1275
  var ProgressCapsuleController = /*#__PURE__*/function () {
1054
1276
  function ProgressCapsuleController(_ref) {
1055
- var _options$min,
1277
+ var _options$valueSuffix,
1278
+ _options$min,
1056
1279
  _options$max,
1057
1280
  _options$value,
1058
1281
  _this = this;
@@ -1062,7 +1285,8 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1062
1285
  preset = _ref.preset,
1063
1286
  emitter = _ref.emitter,
1064
1287
  options = _ref.options,
1065
- copy = _ref.copy;
1288
+ copy = _ref.copy,
1289
+ dirty = _ref.dirty;
1066
1290
  _classCallCheck(this, ProgressCapsuleController);
1067
1291
  this.root = root;
1068
1292
  this.canvas = canvas;
@@ -1071,6 +1295,8 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1071
1295
  this.emitter = emitter;
1072
1296
  this.options = options;
1073
1297
  this.copy = copy;
1298
+ this.dirty = dirty;
1299
+ this.valueSuffix = (_options$valueSuffix = options.valueSuffix) !== null && _options$valueSuffix !== void 0 ? _options$valueSuffix : copy.valueSuffix;
1074
1300
  this.profile = preset.edgeStyle === 'tide' ? FLOW_PROFILES.tide : FLOW_PROFILES[preset.id] || FLOW_PROFILES['visual-training'];
1075
1301
  this.min = (_options$min = options.min) !== null && _options$min !== void 0 ? _options$min : 0;
1076
1302
  this.max = (_options$max = options.max) !== null && _options$max !== void 0 ? _options$max : 100;
@@ -1110,12 +1336,24 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1110
1336
  var rounded = Math.round(this.value);
1111
1337
  this.root.style.setProperty('--progress', this.value.toFixed(2));
1112
1338
  this.root.setAttribute('aria-valuenow', String(rounded));
1113
- this.root.setAttribute('aria-valuetext', "".concat(rounded).concat(this.copy.valueSuffix));
1114
- this.valueElement.textContent = "".concat(rounded).concat(this.copy.valueSuffix);
1115
- if (!this.suppressEvents) this.emitter.emit('change', {
1116
- value: this.value,
1117
- source: source
1118
- });
1339
+ this.root.setAttribute('aria-valuetext', "".concat(rounded).concat(this.valueSuffix));
1340
+ if (this.valueElement) this.valueElement.textContent = "".concat(rounded).concat(this.valueSuffix);
1341
+ if (!this.suppressEvents) {
1342
+ if (this.dirty) this.dirty.value = true;
1343
+ this.emitter.emit('change', {
1344
+ value: this.value,
1345
+ source: source
1346
+ });
1347
+ }
1348
+ }
1349
+ }, {
1350
+ key: "setValueSuffix",
1351
+ value: function setValueSuffix(suffix) {
1352
+ this.valueSuffix = String(suffix == null ? '' : suffix);
1353
+ var rounded = Math.round(this.value);
1354
+ if (this.valueElement) this.valueElement.textContent = "".concat(rounded).concat(this.valueSuffix);
1355
+ this.root.setAttribute('aria-valuetext', "".concat(rounded).concat(this.valueSuffix));
1356
+ return this;
1119
1357
  }
1120
1358
  }, {
1121
1359
  key: "resizeCanvas",
@@ -1290,7 +1528,8 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1290
1528
  var width = this.width;
1291
1529
  var height = this.height;
1292
1530
  if (!ctx || width <= 0 || height <= 0) return;
1293
- var shoreline = width * (this.value / 100);
1531
+ var range = Math.max(this.max - this.min, 1);
1532
+ var shoreline = width * Math.min(Math.max((this.value - this.min) / range, 0), 1);
1294
1533
  var time = this.flowTime;
1295
1534
  var _this$preset$colors = _slicedToArray(this.preset.colors, 4),
1296
1535
  dark = _this$preset$colors[0],
@@ -1405,7 +1644,7 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1405
1644
  value: function updateFromPointer(event) {
1406
1645
  var bounds = this.root.getBoundingClientRect();
1407
1646
  var ratio = bounds.width > 0 ? (event.clientX - bounds.left) / bounds.width : 0;
1408
- this.setProgress(ratio * 100, 'drag');
1647
+ this.setProgress(this.min + ratio * (this.max - this.min), 'drag');
1409
1648
  }
1410
1649
  }, {
1411
1650
  key: "beginDrag",
@@ -1413,6 +1652,8 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1413
1652
  if (event.button !== undefined && event.button !== 0) return;
1414
1653
  event.preventDefault();
1415
1654
  this.dragging = true;
1655
+ this.pendingPointer = null;
1656
+ this._dragRaf = 0;
1416
1657
  this.root.classList.add('is-dragging');
1417
1658
  try {
1418
1659
  var _this$root$setPointer, _this$root;
@@ -1426,15 +1667,31 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1426
1667
  }, {
1427
1668
  key: "moveDrag",
1428
1669
  value: function moveDrag(event) {
1670
+ var _this2 = this;
1429
1671
  if (!this.dragging) return;
1430
1672
  event.preventDefault();
1431
- this.updateFromPointer(event);
1673
+ // rAF 合并:一帧最多一次 setProgress/change,视觉仍每帧更新。
1674
+ this.pendingPointer = event;
1675
+ if (this._dragRaf) return;
1676
+ this._dragRaf = requestAnimationFrame(function () {
1677
+ _this2._dragRaf = 0;
1678
+ var pending = _this2.pendingPointer;
1679
+ _this2.pendingPointer = null;
1680
+ if (pending) _this2.updateFromPointer(pending);
1681
+ });
1432
1682
  }
1433
1683
  }, {
1434
1684
  key: "endDrag",
1435
1685
  value: function endDrag(event) {
1436
1686
  if (!this.dragging) return;
1437
1687
  this.dragging = false;
1688
+ if (this._dragRaf) {
1689
+ cancelAnimationFrame(this._dragRaf);
1690
+ this._dragRaf = 0;
1691
+ }
1692
+ var pending = this.pendingPointer;
1693
+ this.pendingPointer = null;
1694
+ if (pending) this.updateFromPointer(pending);
1438
1695
  this.root.classList.remove('is-dragging');
1439
1696
  try {
1440
1697
  var _this$root$hasPointer, _this$root2;
@@ -1449,19 +1706,19 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1449
1706
  }, {
1450
1707
  key: "bindEvents",
1451
1708
  value: function bindEvents() {
1452
- var _this2 = this;
1709
+ var _this3 = this;
1453
1710
  if (this.options.draggable !== false) {
1454
1711
  this.handlers.pointerdown = function (event) {
1455
- return _this2.beginDrag(event);
1712
+ return _this3.beginDrag(event);
1456
1713
  };
1457
1714
  this.handlers.pointermove = function (event) {
1458
- return _this2.moveDrag(event);
1715
+ return _this3.moveDrag(event);
1459
1716
  };
1460
1717
  this.handlers.pointerup = function (event) {
1461
- return _this2.endDrag(event);
1718
+ return _this3.endDrag(event);
1462
1719
  };
1463
1720
  this.handlers.pointercancel = function (event) {
1464
- return _this2.endDrag(event);
1721
+ return _this3.endDrag(event);
1465
1722
  };
1466
1723
  this.root.addEventListener('pointerdown', this.handlers.pointerdown);
1467
1724
  this.root.addEventListener('pointermove', this.handlers.pointermove);
@@ -1470,23 +1727,24 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1470
1727
  }
1471
1728
  if (this.options.keyboard !== false) {
1472
1729
  this.handlers.keydown = function (event) {
1730
+ var step = (_this3.max - _this3.min) * 0.02;
1473
1731
  var actions = {
1474
- ArrowLeft: -2,
1475
- ArrowDown: -2,
1476
- ArrowRight: 2,
1477
- ArrowUp: 2,
1478
- PageDown: -10,
1479
- PageUp: 10
1732
+ ArrowLeft: -step,
1733
+ ArrowDown: -step,
1734
+ ArrowRight: step,
1735
+ ArrowUp: step,
1736
+ PageDown: -step * 5,
1737
+ PageUp: step * 5
1480
1738
  };
1481
1739
  if (event.key === 'Home') {
1482
1740
  event.preventDefault();
1483
- _this2.setProgress(_this2.min, 'keyboard');
1741
+ _this3.setProgress(_this3.min, 'keyboard');
1484
1742
  } else if (event.key === 'End') {
1485
1743
  event.preventDefault();
1486
- _this2.setProgress(_this2.max, 'keyboard');
1744
+ _this3.setProgress(_this3.max, 'keyboard');
1487
1745
  } else if (actions[event.key]) {
1488
1746
  event.preventDefault();
1489
- _this2.setProgress(_this2.value + actions[event.key], 'keyboard');
1747
+ _this3.setProgress(_this3.value + actions[event.key], 'keyboard');
1490
1748
  } else {
1491
1749
  return;
1492
1750
  }
@@ -1523,6 +1781,7 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1523
1781
  }, {
1524
1782
  key: "dispose",
1525
1783
  value: function dispose() {
1784
+ if (this._dragRaf) cancelAnimationFrame(this._dragRaf);
1526
1785
  if (this.resizeObserver) this.resizeObserver.disconnect();else window.removeEventListener('resize', this.resizeCanvas);
1527
1786
  for (var _i = 0, _Object$keys = Object.keys(this.handlers); _i < _Object$keys.length; _i++) {
1528
1787
  var name = _Object$keys[_i];
@@ -1535,11 +1794,14 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1535
1794
  }();
1536
1795
 
1537
1796
  /**
1538
- * Mount a fluid progress capsule into `container`.
1539
- *
1540
- * Options: preset (id/code/name or object), width, height, value, min, max,
1541
- * draggable, keyboard, colors, edgeStyle, quality,
1542
- * respectReducedMotion, copy, cssVars.
1797
+ * Mount a fluid progress capsule into `container`.
1798
+ *
1799
+ * Options: preset (id/code/name or object), width, height, value, min, max,
1800
+ * draggable, keyboard, colors, edgeStyle, textRatio (0-100, text region
1801
+ * width in percent), text (HTML string or DOM nodes for the text slot),
1802
+ * colorContent (HTML string or DOM nodes for the color slot),
1803
+ * showValue (show/hide the right-side percentage), quality,
1804
+ * respectReducedMotion, cssVars.
1543
1805
  */
1544
1806
  function createProgressCapsule(container) {
1545
1807
  var _options$preset, _merged$min, _merged$max;
@@ -1549,62 +1811,91 @@ function createProgressCapsule(container) {
1549
1811
  }
1550
1812
  var preset = _objectSpread2({}, getPreset('progress', (_options$preset = options.preset) !== null && _options$preset !== void 0 ? _options$preset : '星火'));
1551
1813
  var merged = normalizeOptions(DEFAULTS.progress, preset, options);
1552
- var copy = _objectSpread2(_objectSpread2({}, COPY), merged.copy || {});
1814
+ var normalizedColors = merged.colors.map(normalizeColor);
1815
+ if (normalizedColors.every(Boolean)) preset.colors = normalizedColors;
1816
+ preset.edgeStyle = merged.edgeStyle;
1817
+ var copy = COPY;
1818
+ var customLabel = typeof options.label === 'string' && options.label ? options.label : null;
1819
+ // Vue 的裸布尔属性(<ProgressCapsule disabled />)会传成空字符串,
1820
+ // 这里统一按 true 处理。
1821
+ var disabled = merged.disabled === true || merged.disabled === '' || merged.disabled === 'true';
1822
+ var effectiveDraggable = disabled ? false : merged.draggable !== false;
1823
+ var effectiveKeyboard = disabled ? false : merged.keyboard !== false;
1824
+ var dirty = {
1825
+ preset: false,
1826
+ colors: false,
1827
+ textRatio: false,
1828
+ cssVars: false,
1829
+ edgeStyle: false,
1830
+ value: false
1831
+ };
1553
1832
  var root = document.createElement('div');
1554
1833
  root.className = 'hj-capsule-root hj-progress-root';
1555
1834
  root.setAttribute('role', 'slider');
1556
1835
  root.setAttribute('tabindex', '0');
1557
- root.setAttribute('data-draggable', String(merged.draggable !== false));
1836
+ root.setAttribute('data-draggable', String(effectiveDraggable));
1837
+ if (disabled) {
1838
+ root.setAttribute('aria-disabled', 'true');
1839
+ root.classList.add('is-disabled');
1840
+ }
1558
1841
  root.setAttribute('aria-valuemin', String((_merged$min = merged.min) !== null && _merged$min !== void 0 ? _merged$min : 0));
1559
1842
  root.setAttribute('aria-valuemax', String((_merged$max = merged.max) !== null && _merged$max !== void 0 ? _merged$max : 100));
1560
1843
  root.setAttribute('aria-valuenow', String(preset.initialProgress));
1561
- root.setAttribute('aria-label', interpolate(copy.progressAria, {
1562
- brand: copy.brandName,
1563
- code: preset.code,
1564
- name: preset.name
1565
- }));
1566
- if (merged.keyboard === false) root.setAttribute('tabindex', '-1');
1844
+ var updateAria = function updateAria() {
1845
+ root.setAttribute('aria-label', customLabel || interpolate(copy.progressAria, {
1846
+ brand: copy.brandName,
1847
+ code: preset.code,
1848
+ name: preset.name
1849
+ }));
1850
+ };
1851
+ updateAria();
1852
+ if (!effectiveKeyboard) root.setAttribute('tabindex', '-1');
1567
1853
  var canvas = document.createElement('canvas');
1568
1854
  canvas.className = 'hj-progress-canvas';
1569
1855
  canvas.setAttribute('aria-hidden', 'true');
1570
- var copyEnabled = copy.enabled !== false && merged.showCopy !== false;
1571
- var copyText = function copyText(key, fallback) {
1572
- var value = copy[key];
1573
- return value === undefined ? fallback : value;
1574
- };
1575
- function buildCopyHtml() {
1576
- var html = '';
1577
- var brandText = copy.brandName || '';
1578
- var subtitleText = copyText('subtitle', preset.subtitle);
1579
- if (brandText) html += "<span class=\"hj-progress-name\">".concat(brandText, "</span>");
1580
- if (subtitleText) html += "<span class=\"hj-progress-subtitle\">".concat(subtitleText, "</span>");
1581
- return html;
1582
- }
1583
- var copyLayer = document.createElement('div');
1584
- copyLayer.className = 'hj-progress-copy';
1585
- var renderCopy = function renderCopy() {
1586
- if (copyEnabled) copyLayer.innerHTML = buildCopyHtml();
1856
+
1857
+ // Slot containers are always present but transparent by default; they only
1858
+ // provide geometry, never typography/padding/background (docs: 插槽 CSS 约定).
1859
+ var fillContent = function fillContent(layer, content) {
1860
+ layer.innerHTML = '';
1861
+ if (content == null) return;
1862
+ if (typeof content === 'string') {
1863
+ layer.innerHTML = content;
1864
+ return;
1865
+ }
1866
+ var nodes = Array.isArray(content) ? content : [content];
1867
+ var _iterator2 = _createForOfIteratorHelper(nodes),
1868
+ _step2;
1869
+ try {
1870
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1871
+ var node = _step2.value;
1872
+ if (node && typeof node.nodeType === 'number') layer.appendChild(node);
1873
+ }
1874
+ } catch (err) {
1875
+ _iterator2.e(err);
1876
+ } finally {
1877
+ _iterator2.f();
1878
+ }
1587
1879
  };
1588
- renderCopy();
1589
- if (copy.background) {
1590
- root.style.setProperty('--hj-progress-copy-bg', copy.background);
1591
- root.style.setProperty('--hj-progress-copy-pad', '6px 12px');
1880
+ var textLayer = document.createElement('div');
1881
+ textLayer.className = 'hj-progress-text hj-progress-copy';
1882
+ var visualLayer = document.createElement('div');
1883
+ visualLayer.className = 'hj-progress-visual';
1884
+ fillContent(textLayer, options.text);
1885
+ fillContent(visualLayer, options.colorContent);
1886
+ var valueElement = merged.showValue === false ? null : document.createElement('div');
1887
+ if (valueElement) {
1888
+ valueElement.className = 'hj-progress-value';
1889
+ valueElement.setAttribute('aria-hidden', 'true');
1592
1890
  }
1593
- if (copy.color) root.style.setProperty('--hj-progress-copy-color', copy.color);
1594
- var valueElement = document.createElement('div');
1595
- valueElement.className = 'hj-progress-value';
1596
- valueElement.setAttribute('aria-hidden', 'true');
1597
- var dragLabel = document.createElement('span');
1598
- dragLabel.className = 'hj-progress-drag-label';
1599
- dragLabel.setAttribute('aria-hidden', 'true');
1600
- dragLabel.textContent = copy.dragLabel;
1601
1891
  root.appendChild(canvas);
1602
- if (copyEnabled) root.appendChild(copyLayer);
1603
- root.appendChild(valueElement);
1604
- root.appendChild(dragLabel);
1892
+ root.appendChild(textLayer);
1893
+ root.appendChild(visualLayer);
1894
+ if (valueElement) root.appendChild(valueElement);
1605
1895
  container.appendChild(root);
1606
1896
  var emitter = createEmitter();
1607
1897
  var paused = merged.respectReducedMotion && prefersReducedMotion();
1898
+ var disposed = false;
1608
1899
  var applySize = function applySize() {
1609
1900
  root.style.width = parseSize(merged.width);
1610
1901
  root.style.height = parseSize(merged.height);
@@ -1613,6 +1904,9 @@ function createProgressCapsule(container) {
1613
1904
  var name = _Object$keys2[_i2];
1614
1905
  root.style.setProperty(name, vars[name]);
1615
1906
  }
1907
+ if (merged.textRatio !== undefined) {
1908
+ root.style.setProperty('--hj-text-width', "".concat(merged.textRatio, "%"));
1909
+ }
1616
1910
  };
1617
1911
  applySize();
1618
1912
  var controller = new ProgressCapsuleController({
@@ -1621,8 +1915,12 @@ function createProgressCapsule(container) {
1621
1915
  valueElement: valueElement,
1622
1916
  preset: preset,
1623
1917
  emitter: emitter,
1624
- options: merged,
1625
- copy: copy
1918
+ options: _objectSpread2(_objectSpread2({}, merged), {}, {
1919
+ draggable: effectiveDraggable,
1920
+ keyboard: effectiveKeyboard
1921
+ }),
1922
+ copy: copy,
1923
+ dirty: dirty
1626
1924
  });
1627
1925
  var overlay = null;
1628
1926
  if (merged.renderer !== 'canvas2d') {
@@ -1635,7 +1933,14 @@ function createProgressCapsule(container) {
1635
1933
  }
1636
1934
  });
1637
1935
  }
1638
- if (overlay) controller.webglActive = true;
1936
+ if (overlay) controller.webglActive = true;else if (merged.renderer !== 'canvas2d') {
1937
+ nextTick(function () {
1938
+ if (disposed) return;
1939
+ emitter.emit('error', {
1940
+ message: 'WebGL2 unavailable, using Canvas2D fallback'
1941
+ });
1942
+ });
1943
+ }
1639
1944
  var visibility = createVisibilityGuard(root);
1640
1945
  var flowTime = 0;
1641
1946
  var unsubscribe = subscribeScheduler(function (delta, now) {
@@ -1648,16 +1953,14 @@ function createProgressCapsule(container) {
1648
1953
  }, function () {
1649
1954
  return paused;
1650
1955
  });
1651
- emitter.emit('ready', {
1652
- preset: _objectSpread2({}, preset)
1956
+ nextTick(function () {
1957
+ if (disposed) return;
1958
+ emitter.emit('ready', {
1959
+ preset: _objectSpread2({}, preset)
1960
+ });
1653
1961
  });
1654
1962
  var syncDom = function syncDom() {
1655
- root.setAttribute('aria-label', interpolate(copy.progressAria, {
1656
- brand: copy.brandName,
1657
- code: preset.code,
1658
- name: preset.name
1659
- }));
1660
- renderCopy();
1963
+ updateAria();
1661
1964
  };
1662
1965
  return {
1663
1966
  element: root,
@@ -1679,8 +1982,11 @@ function createProgressCapsule(container) {
1679
1982
  },
1680
1983
  setPreset: function setPreset(ref) {
1681
1984
  var next = getPreset('progress', ref);
1985
+ dirty.preset = true;
1682
1986
  Object.assign(preset, next);
1683
- controller.preset = next;
1987
+ var nextColors = preset.colors.map(normalizeColor);
1988
+ if (nextColors.every(Boolean)) preset.colors = nextColors;
1989
+ controller.preset = preset;
1684
1990
  controller.profile = next.edgeStyle === 'tide' ? FLOW_PROFILES.tide : FLOW_PROFILES[next.id] || FLOW_PROFILES['visual-training'];
1685
1991
  controller.flowTime = stringSeed(next.id) * 31;
1686
1992
  controller.seed = stringSeed("".concat(next.id, "-reference")) * Math.PI * 2;
@@ -1690,7 +1996,7 @@ function createProgressCapsule(container) {
1690
1996
  overlay = attachProgressFlowOverlay({
1691
1997
  root: root,
1692
1998
  canvas: canvas,
1693
- preset: next,
1999
+ preset: preset,
1694
2000
  getProgress: function getProgress() {
1695
2001
  return controller.value;
1696
2002
  }
@@ -1699,13 +2005,14 @@ function createProgressCapsule(container) {
1699
2005
  controller.webglActive = Boolean(overlay);
1700
2006
  controller.resizeCanvas();
1701
2007
  emitter.emit('presetchange', {
1702
- preset: _objectSpread2({}, next)
2008
+ preset: _objectSpread2({}, preset)
1703
2009
  });
1704
2010
  return this;
1705
2011
  },
1706
2012
  setEdgeStyle: function setEdgeStyle(edgeStyle) {
1707
2013
  var value = String(edgeStyle || '').toLowerCase();
1708
2014
  if (value !== 'flow' && value !== 'tide') return this;
2015
+ dirty.edgeStyle = true;
1709
2016
  preset.edgeStyle = value;
1710
2017
  controller.profile = value === 'tide' ? FLOW_PROFILES.tide : FLOW_PROFILES[preset.id] || FLOW_PROFILES['visual-training'];
1711
2018
  if (overlay) {
@@ -1723,10 +2030,49 @@ function createProgressCapsule(container) {
1723
2030
  controller.resizeCanvas();
1724
2031
  return this;
1725
2032
  },
2033
+ setText: function setText(content) {
2034
+ fillContent(textLayer, content);
2035
+ return this;
2036
+ },
2037
+ setColorContent: function setColorContent(content) {
2038
+ fillContent(visualLayer, content);
2039
+ return this;
2040
+ },
2041
+ setTextRatio: function setTextRatio(ratio) {
2042
+ var value = Number(ratio);
2043
+ if (!Number.isFinite(value) || value < 0 || value > 100) return this;
2044
+ dirty.textRatio = true;
2045
+ merged.textRatio = value;
2046
+ root.style.setProperty('--hj-text-width', "".concat(value, "%"));
2047
+ return this;
2048
+ },
2049
+ setCssVars: function setCssVars(vars) {
2050
+ if (!vars || _typeof(vars) !== 'object') return this;
2051
+ dirty.cssVars = true;
2052
+ merged.cssVars = _objectSpread2(_objectSpread2({}, merged.cssVars || {}), vars);
2053
+ for (var _i3 = 0, _Object$keys3 = Object.keys(vars); _i3 < _Object$keys3.length; _i3++) {
2054
+ var name = _Object$keys3[_i3];
2055
+ root.style.setProperty(name, vars[name]);
2056
+ }
2057
+ return this;
2058
+ },
2059
+ setLabel: function setLabel(label) {
2060
+ customLabel = typeof label === 'string' && label ? label : null;
2061
+ updateAria();
2062
+ return this;
2063
+ },
2064
+ setValueSuffix: function setValueSuffix(suffix) {
2065
+ controller.setValueSuffix(suffix);
2066
+ return this;
2067
+ },
1726
2068
  setColors: function setColors(colors) {
1727
- if (!Array.isArray(colors) || colors.length !== 4) return this;
1728
- controller.setColors(colors);
1729
- if (overlay) overlay.setColors(colors);
2069
+ var next = Array.isArray(colors) ? colors.map(normalizeColor) : [];
2070
+ if (next.length !== 4 || next.some(function (color) {
2071
+ return !color;
2072
+ })) return this;
2073
+ dirty.colors = true;
2074
+ controller.setColors(next);
2075
+ if (overlay) overlay.setColors(next);
1730
2076
  controller.resizeCanvas();
1731
2077
  return this;
1732
2078
  },
@@ -1756,12 +2102,16 @@ function createProgressCapsule(container) {
1756
2102
  return this;
1757
2103
  },
1758
2104
  dispose: function dispose() {
2105
+ disposed = true;
1759
2106
  unsubscribe();
1760
2107
  visibility.dispose();
1761
2108
  if (overlay) overlay.dispose();
1762
2109
  controller.dispose();
1763
2110
  root.remove();
1764
- }
2111
+ },
2112
+ textRatio: merged.textRatio,
2113
+ cssVars: merged.cssVars,
2114
+ dirty: dirty
1765
2115
  };
1766
2116
  }
1767
2117