@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/dist/index.cjs CHANGED
@@ -148,6 +148,9 @@ function _objectSpread2(e) {
148
148
  }
149
149
  return e;
150
150
  }
151
+ function _readOnlyError(r) {
152
+ throw new TypeError('"' + r + '" is read-only');
153
+ }
151
154
  function _slicedToArray(r, e) {
152
155
  return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
153
156
  }
@@ -320,7 +323,7 @@ var PALETTES$1 = {
320
323
  var CAPSULE_PRESETS = [{
321
324
  id: 'original',
322
325
  code: 'NC-01',
323
- name: 'ORIGINAL',
326
+ name: '初光',
324
327
  group: 'warm',
325
328
  seed: 1.7,
326
329
  speed: 0.5,
@@ -328,7 +331,7 @@ var CAPSULE_PRESETS = [{
328
331
  }, {
329
332
  id: 'ocean',
330
333
  code: 'NC-02',
331
- name: 'OCEAN',
334
+ name: '沧溟',
332
335
  group: 'cold',
333
336
  seed: 8.2,
334
337
  speed: 0.48,
@@ -336,7 +339,7 @@ var CAPSULE_PRESETS = [{
336
339
  }, {
337
340
  id: 'klein',
338
341
  code: 'NC-03',
339
- name: 'KLEIN',
342
+ name: '玄夜',
340
343
  group: 'cold',
341
344
  seed: 14.1,
342
345
  speed: 0.49,
@@ -344,7 +347,7 @@ var CAPSULE_PRESETS = [{
344
347
  }, {
345
348
  id: 'ultraviolet',
346
349
  code: 'NC-04',
347
- name: 'ULTRAVIOLET',
350
+ name: '紫霄',
348
351
  group: 'cold',
349
352
  seed: 23.4,
350
353
  speed: 0.47,
@@ -352,7 +355,7 @@ var CAPSULE_PRESETS = [{
352
355
  }, {
353
356
  id: 'chrome',
354
357
  code: 'NC-05',
355
- name: 'CHROME',
358
+ name: '银汉',
356
359
  group: 'cold',
357
360
  seed: 37.8,
358
361
  speed: 0.42,
@@ -360,7 +363,7 @@ var CAPSULE_PRESETS = [{
360
363
  }, {
361
364
  id: 'plus',
362
365
  code: 'NC-06',
363
- name: 'PLUS',
366
+ name: '熔金',
364
367
  group: 'warm',
365
368
  seed: 51.3,
366
369
  speed: 0.5,
@@ -370,7 +373,7 @@ var CAPSULE_PRESETS = [{
370
373
  var PROGRESS_PRESETS = [{
371
374
  id: 'model-training',
372
375
  code: 'NC-10',
373
- name: 'MODEL TRAINING',
376
+ name: '星火',
374
377
  subtitle: 'SHA 4.5 + 100 2026 TKN',
375
378
  group: 'progress',
376
379
  initialProgress: 43,
@@ -379,7 +382,7 @@ var PROGRESS_PRESETS = [{
379
382
  }, {
380
383
  id: 'agent-migration',
381
384
  code: 'NC-11',
382
- name: 'AGENT MIGRATION',
385
+ name: '迁流',
383
386
  subtitle: 'TRANSFERRING PROTOCOL',
384
387
  group: 'progress',
385
388
  initialProgress: 33,
@@ -388,7 +391,7 @@ var PROGRESS_PRESETS = [{
388
391
  }, {
389
392
  id: 'visual-training',
390
393
  code: 'NC-12',
391
- name: 'VISUAL TRAINING',
394
+ name: '幻境',
392
395
  subtitle: 'GENERATING POWER ++',
393
396
  group: 'progress',
394
397
  initialProgress: 58,
@@ -397,7 +400,7 @@ var PROGRESS_PRESETS = [{
397
400
  }, {
398
401
  id: 'tide',
399
402
  code: 'NC-13',
400
- name: 'TIDE',
403
+ name: '汐潮',
401
404
  subtitle: 'MOON PULL / COAST',
402
405
  group: 'progress',
403
406
  initialProgress: 30,
@@ -407,23 +410,18 @@ var PROGRESS_PRESETS = [{
407
410
 
408
411
  var PRESETS = CAPSULE_PRESETS;
409
412
  var ALL_PRESETS = [].concat(_toConsumableArray(CAPSULE_PRESETS), _toConsumableArray(PROGRESS_PRESETS));
410
- function validatePreset(preset) {
411
- return Boolean(preset && typeof preset.id === 'string' && typeof preset.code === 'string' && typeof preset.name === 'string' && Number.isFinite(preset.seed) && Number.isFinite(preset.speed) && Array.isArray(preset.colors) && preset.colors.length === 4);
412
- }
413
- function validateProgressPreset(preset) {
414
- return Boolean(preset && typeof preset.id === 'string' && typeof preset.code === 'string' && typeof preset.name === 'string' && preset.group === 'progress' && Number.isFinite(preset.initialProgress) && ['flow', 'tide'].indexOf(preset.edgeStyle || 'flow') !== -1 && Array.isArray(preset.colors) && preset.colors.length === 4);
415
- }
413
+
414
+ /**
415
+ * Resolve a preset by its literary name (e.g. '沧溟').
416
+ * Matching is case-insensitive and ignores surrounding whitespace,
417
+ * so '沧溟' and ' 沧溟 ' both work.
418
+ */
416
419
  function getPreset(kind, ref) {
417
420
  var list = kind === 'capsule' ? CAPSULE_PRESETS : kind === 'progress' ? PROGRESS_PRESETS : null;
418
421
  if (!list) throw new Error("Unknown preset kind: ".concat(kind, " (use \"capsule\" or \"progress\")"));
419
- if (ref && _typeof(ref) === 'object') {
420
- var valid = kind === 'capsule' ? validatePreset(ref) : validateProgressPreset(ref);
421
- if (!valid) throw new Error("Invalid ".concat(kind, " preset object"));
422
- return ref;
423
- }
424
422
  var key = String(ref).trim().toLowerCase();
425
423
  var found = list.find(function (preset) {
426
- return preset.id.toLowerCase() === key || preset.code.toLowerCase() === key || preset.name.toLowerCase() === key;
424
+ return preset.name.toLowerCase() === key;
427
425
  });
428
426
  if (!found) throw new Error("Unknown ".concat(kind, " preset: ").concat(ref));
429
427
  return found;
@@ -436,9 +434,8 @@ var DEFAULTS = {
436
434
  quality: 'auto',
437
435
  renderer: 'auto',
438
436
  respectReducedMotion: true,
439
- interactive: true,
440
437
  mouseColor: true,
441
- showCopy: true
438
+ textRatio: 39
442
439
  },
443
440
  progress: {
444
441
  width: 454,
@@ -447,43 +444,250 @@ var DEFAULTS = {
447
444
  max: 100,
448
445
  draggable: true,
449
446
  keyboard: true,
447
+ disabled: false,
448
+ valueSuffix: '%',
450
449
  edgeStyle: 'flow',
451
450
  quality: 'auto',
452
451
  renderer: 'auto',
453
- showCopy: true,
452
+ textRatio: 54,
453
+ showValue: true,
454
454
  respectReducedMotion: true
455
455
  }
456
456
  };
457
457
 
458
- /**
459
- * All user-facing copy lives here so wording/brand changes never require a
460
- * global search. Templates use {brand} {code} {name} placeholders.
458
+ /**
459
+ * Internal accessibility labels and small UI text. Since the copy API was
460
+ * removed (slots own the text area), these are no longer user-overridable.
461
+ * Templates use {brand} {code} {name} placeholders.
461
462
  */
462
463
  var COPY = {
463
464
  brandName: '画境观屿',
464
- dragLabel: 'DRAG',
465
465
  valueSuffix: '%',
466
466
  progressAria: '{brand} {code} 加载进度',
467
467
  capsuleAria: '打开 {name} 沉浸预览'
468
468
  };
469
469
 
470
- function hexToRgb01$1(hex) {
471
- var normalized = hex.replace('#', '');
472
- var value = Number.parseInt(normalized, 16);
470
+ /**
471
+ * Color helpers. `normalizeColor` converts any supported CSS color
472
+ * (hex / named / rgb() / rgba()) into a 6-digit hex string, so renderers can
473
+ * keep working with #rrggbb only. rgba() alpha is intentionally dropped:
474
+ * the WebGL shader has no per-color alpha channel, and the component is
475
+ * opaque by design — use component-level `opacity` for transparency.
476
+ */
477
+
478
+ var NAMED_COLORS = {
479
+ aliceblue: '#f0f8ff',
480
+ antiquewhite: '#faebd7',
481
+ aqua: '#00ffff',
482
+ aquamarine: '#7fffd4',
483
+ azure: '#f0ffff',
484
+ beige: '#f5f5dc',
485
+ bisque: '#ffe4c4',
486
+ black: '#000000',
487
+ blanchedalmond: '#ffebcd',
488
+ blue: '#0000ff',
489
+ blueviolet: '#8a2be2',
490
+ brown: '#a52a2a',
491
+ burlywood: '#deb887',
492
+ cadetblue: '#5f9ea0',
493
+ chartreuse: '#7fff00',
494
+ chocolate: '#d2691e',
495
+ coral: '#ff7f50',
496
+ cornflowerblue: '#6495ed',
497
+ cornsilk: '#fff8dc',
498
+ crimson: '#dc143c',
499
+ cyan: '#00ffff',
500
+ darkblue: '#00008b',
501
+ darkcyan: '#008b8b',
502
+ darkgoldenrod: '#b8860b',
503
+ darkgray: '#a9a9a9',
504
+ darkgreen: '#006400',
505
+ darkgrey: '#a9a9a9',
506
+ darkkhaki: '#bdb76b',
507
+ darkmagenta: '#8b008b',
508
+ darkolivegreen: '#556b2f',
509
+ darkorange: '#ff8c00',
510
+ darkorchid: '#9932cc',
511
+ darkred: '#8b0000',
512
+ darksalmon: '#e9967a',
513
+ darkseagreen: '#8fbc8f',
514
+ darkslateblue: '#483d8b',
515
+ darkslategray: '#2f4f4f',
516
+ darkslategrey: '#2f4f4f',
517
+ darkturquoise: '#00ced1',
518
+ darkviolet: '#9400d3',
519
+ deeppink: '#ff1493',
520
+ deepskyblue: '#00bfff',
521
+ dimgray: '#696969',
522
+ dimgrey: '#696969',
523
+ dodgerblue: '#1e90ff',
524
+ firebrick: '#b22222',
525
+ floralwhite: '#fffaf0',
526
+ forestgreen: '#228b22',
527
+ fuchsia: '#ff00ff',
528
+ gainsboro: '#dcdcdc',
529
+ ghostwhite: '#f8f8ff',
530
+ gold: '#ffd700',
531
+ goldenrod: '#daa520',
532
+ gray: '#808080',
533
+ green: '#008000',
534
+ greenyellow: '#adff2f',
535
+ grey: '#808080',
536
+ honeydew: '#f0fff0',
537
+ hotpink: '#ff69b4',
538
+ indianred: '#cd5c5c',
539
+ indigo: '#4b0082',
540
+ ivory: '#fffff0',
541
+ khaki: '#f0e68c',
542
+ lavender: '#e6e6fa',
543
+ lavenderblush: '#fff0f5',
544
+ lawngreen: '#7cfc00',
545
+ lemonchiffon: '#fffacd',
546
+ lightblue: '#add8e6',
547
+ lightcoral: '#f08080',
548
+ lightcyan: '#e0ffff',
549
+ lightgoldenrodyellow: '#fafad2',
550
+ lightgray: '#d3d3d3',
551
+ lightgreen: '#90ee90',
552
+ lightgrey: '#d3d3d3',
553
+ lightpink: '#ffb6c1',
554
+ lightsalmon: '#ffa07a',
555
+ lightseagreen: '#20b2aa',
556
+ lightskyblue: '#87cefa',
557
+ lightslategray: '#778899',
558
+ lightslategrey: '#778899',
559
+ lightsteelblue: '#b0c4de',
560
+ lightyellow: '#ffffe0',
561
+ lime: '#00ff00',
562
+ limegreen: '#32cd32',
563
+ linen: '#faf0e6',
564
+ magenta: '#ff00ff',
565
+ maroon: '#800000',
566
+ mediumaquamarine: '#66cdaa',
567
+ mediumblue: '#0000cd',
568
+ mediumorchid: '#ba55d3',
569
+ mediumpurple: '#9370db',
570
+ mediumseagreen: '#3cb371',
571
+ mediumslateblue: '#7b68ee',
572
+ mediumspringgreen: '#00fa9a',
573
+ mediumturquoise: '#48d1cc',
574
+ mediumvioletred: '#c71585',
575
+ midnightblue: '#191970',
576
+ mintcream: '#f5fffa',
577
+ mistyrose: '#ffe4e1',
578
+ moccasin: '#ffe4b5',
579
+ navajowhite: '#ffdead',
580
+ navy: '#000080',
581
+ oldlace: '#fdf5e6',
582
+ olive: '#808000',
583
+ olivedrab: '#6b8e23',
584
+ orange: '#ffa500',
585
+ orangered: '#ff4500',
586
+ orchid: '#da70d6',
587
+ palegoldenrod: '#eee8aa',
588
+ palegreen: '#98fb98',
589
+ paleturquoise: '#afeeee',
590
+ palevioletred: '#db7093',
591
+ papayawhip: '#ffefd5',
592
+ peachpuff: '#ffdab9',
593
+ peru: '#cd853f',
594
+ pink: '#ffc0cb',
595
+ plum: '#dda0dd',
596
+ powderblue: '#b0e0e6',
597
+ purple: '#800080',
598
+ rebeccapurple: '#663399',
599
+ red: '#ff0000',
600
+ rosybrown: '#bc8f8f',
601
+ royalblue: '#4169e1',
602
+ saddlebrown: '#8b4513',
603
+ salmon: '#fa8072',
604
+ sandybrown: '#f4a460',
605
+ seagreen: '#2e8b57',
606
+ seashell: '#fff5ee',
607
+ sienna: '#a0522d',
608
+ silver: '#c0c0c0',
609
+ skyblue: '#87ceeb',
610
+ slateblue: '#6a5acd',
611
+ slategray: '#708090',
612
+ slategrey: '#708090',
613
+ snow: '#fffafa',
614
+ springgreen: '#00ff7f',
615
+ steelblue: '#4682b4',
616
+ tan: '#d2b48c',
617
+ teal: '#008080',
618
+ thistle: '#d8bfd8',
619
+ tomato: '#ff6347',
620
+ turquoise: '#40e0d0',
621
+ violet: '#ee82ee',
622
+ wheat: '#f5deb3',
623
+ white: '#ffffff',
624
+ whitesmoke: '#f5f5f5',
625
+ yellow: '#ffff00',
626
+ yellowgreen: '#9acd32'
627
+ };
628
+ function clampChannel(value) {
629
+ return Math.min(255, Math.max(0, Math.round(value)));
630
+ }
631
+ function normalizeRgbArgs(args) {
632
+ var parts = args.split(/[,\s/]+/).filter(Boolean);
633
+ if (parts.length < 3) return null;
634
+ var to255 = function to255(value) {
635
+ if (typeof value !== 'string' || !value) return null;
636
+ if (value.endsWith('%')) return clampChannel(parseFloat(value) / 100 * 255);
637
+ var number = Number(value);
638
+ return Number.isFinite(number) ? clampChannel(number) : null;
639
+ };
640
+ var red = to255(parts[0]);
641
+ var green = to255(parts[1]);
642
+ var blue = to255(parts[2]);
643
+ if (red === null || green === null || blue === null) return null;
644
+ return "#".concat([red, green, blue].map(function (n) {
645
+ return n.toString(16).padStart(2, '0');
646
+ }).join(''));
647
+ }
648
+
649
+ /**
650
+ * Convert any supported CSS color into `#rrggbb`. Returns null when the
651
+ * value cannot be parsed. Supports: #rgb / #rrggbb (case-insensitive),
652
+ * CSS named colors, rgb() / rgba() with comma or modern space syntax,
653
+ * including percentages. Alpha in rgba() is ignored.
654
+ */
655
+ function normalizeColor(value) {
656
+ if (typeof value !== 'string') return null;
657
+ var input = value.trim();
658
+ if (!input) return null;
659
+ var lower = input.toLowerCase();
660
+ if (NAMED_COLORS[lower]) return NAMED_COLORS[lower];
661
+ if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(input)) {
662
+ var hex = input.slice(1).toLowerCase();
663
+ if (hex.length === 3) return "#".concat(hex.split('').map(function (c) {
664
+ return c + c;
665
+ }).join(''));
666
+ return "#".concat(hex);
667
+ }
668
+ var match = input.match(/^rgba?\((.*)\)$/i);
669
+ if (match) return normalizeRgbArgs(match[1]);
670
+ return null;
671
+ }
672
+ function hexToRgb01$1(color) {
673
+ var hex = normalizeColor(color);
674
+ if (!hex) return [0, 0, 0];
675
+ var value = Number.parseInt(hex.slice(1), 16);
473
676
  return [(value >> 16 & 255) / 255, (value >> 8 & 255) / 255, (value & 255) / 255];
474
677
  }
475
- function hexToRgba(hex) {
678
+ function hexToRgba(color) {
476
679
  var alpha = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
477
- var normalized = hex.replace('#', '');
478
- var value = Number.parseInt(normalized, 16);
680
+ var hex = normalizeColor(color);
681
+ if (!hex) return 'rgba(0, 0, 0, 0)';
682
+ var value = Number.parseInt(hex.slice(1), 16);
479
683
  var red = value >> 16 & 255;
480
684
  var green = value >> 8 & 255;
481
685
  var blue = value & 255;
482
686
  return "rgba(".concat(red, ", ").concat(green, ", ").concat(blue, ", ").concat(alpha, ")");
483
687
  }
484
688
  function validateColors(colors) {
485
- return Array.isArray(colors) && colors.length === 4 && colors.every(function (c) {
486
- return typeof c === 'string' && /^#[0-9a-f]{6}$/i.test(c);
689
+ return Array.isArray(colors) && colors.length === 4 && colors.every(function (color) {
690
+ return normalizeColor(color) !== null;
487
691
  });
488
692
  }
489
693
 
@@ -561,6 +765,26 @@ var CosmicRenderer = /*#__PURE__*/function () {
561
765
  this.options.dprCap = cap;
562
766
  this.resize();
563
767
  }
768
+ }, {
769
+ key: "setMouseColor",
770
+ value: function setMouseColor(enabled) {
771
+ this.options.mouseColor = enabled !== false;
772
+ if (this.options.mouseColor) {
773
+ if (this.onPointerMove) return this;
774
+ _assertClassBrand(_CosmicRenderer_brand, this, _bindEvents).call(this);
775
+ return this;
776
+ }
777
+ if (this.onPointerMove) {
778
+ var target = this.eventTarget;
779
+ target.removeEventListener('pointermove', this.onPointerMove);
780
+ target.removeEventListener('pointerdown', this.onPointerMove);
781
+ target.removeEventListener('pointerleave', this.onPointerLeave);
782
+ this.onPointerMove = null;
783
+ this.onPointerLeave = null;
784
+ }
785
+ this.motionTarget = 0;
786
+ return this;
787
+ }
564
788
  }, {
565
789
  key: "randomize",
566
790
  value: function randomize() {
@@ -709,6 +933,8 @@ var FallbackRenderer = /*#__PURE__*/function () {
709
933
  var _this$canvas = this.canvas,
710
934
  width = _this$canvas.width,
711
935
  height = _this$canvas.height;
936
+ var t = time * (this.preset.speed || 1);
937
+ var phase = (this.preset.seed || 0) * 0.7;
712
938
  var gradient = ctx.createLinearGradient(0, 0, width, height);
713
939
  gradient.addColorStop(0, this.preset.colors[0]);
714
940
  gradient.addColorStop(0.38, this.preset.colors[1]);
@@ -718,8 +944,8 @@ var FallbackRenderer = /*#__PURE__*/function () {
718
944
  ctx.fillRect(0, 0, width, height);
719
945
  ctx.globalCompositeOperation = 'screen';
720
946
  for (var index = 0; index < 6; index += 1) {
721
- var x = (0.5 + 0.45 * Math.sin(time * 0.32 + index * 1.7)) * width;
722
- var y = (0.5 + 0.4 * Math.cos(time * 0.25 + index)) * height;
947
+ var x = (0.5 + 0.45 * Math.sin(t * 0.32 + index * 1.7 + phase)) * width;
948
+ var y = (0.5 + 0.4 * Math.cos(t * 0.25 + index + phase)) * height;
723
949
  var radius = Math.max(width, height) * (0.08 + index % 3 * 0.04);
724
950
  var glow = ctx.createRadialGradient(x, y, 0, x, y, radius);
725
951
  glow.addColorStop(0, rgb(this.preset.colors[(index + 1) % 4], 0.24));
@@ -743,7 +969,12 @@ var FallbackRenderer = /*#__PURE__*/function () {
743
969
  }
744
970
  }, {
745
971
  key: "randomize",
746
- value: function randomize() {}
972
+ value: function randomize() {
973
+ if (this.preset) this.preset.seed = Math.random() * 100;
974
+ }
975
+ }, {
976
+ key: "setMouseColor",
977
+ value: function setMouseColor() {}
747
978
  }, {
748
979
  key: "dispose",
749
980
  value: function dispose() {}
@@ -861,16 +1092,34 @@ function createVisibilityGuard(element) {
861
1092
  };
862
1093
  }
863
1094
 
1095
+ /**
1096
+ * Run a callback asynchronously, right after the current task and before the
1097
+ * next paint. Used for mount-time events (ready / error) so listeners that
1098
+ * are attached after create() still receive them. Falls back for legacy
1099
+ * browsers that lack queueMicrotask / Promise.
1100
+ */
1101
+ function nextTick(fn) {
1102
+ if (typeof queueMicrotask === 'function') {
1103
+ queueMicrotask(fn);
1104
+ } else if (typeof Promise !== 'undefined' && typeof Promise.resolve === 'function') {
1105
+ Promise.resolve().then(fn);
1106
+ } else {
1107
+ setTimeout(fn, 0);
1108
+ }
1109
+ }
1110
+
864
1111
  function prefersReducedMotion$2() {
865
1112
  return typeof matchMedia !== 'undefined' && matchMedia('(prefers-reduced-motion: reduce)').matches;
866
1113
  }
867
1114
 
868
1115
  /**
869
- * Mount a cosmic (nebula) capsule into `container`.
870
- *
871
- * Options: preset (id/code/name or object), width, height (number=px or
872
- * string with px/%/vw/vh/em/rem), colors, seed, speed, quality, interactive,
873
- * respectReducedMotion, copy, cssVars.
1116
+ * Mount a cosmic (nebula) capsule into `container`.
1117
+ *
1118
+ * Options: preset (literary name), width, height (number=px or string with
1119
+ * px/%/vw/vh/em/rem), colors, seed, speed, textRatio (0-100, text region
1120
+ * width in percent), text (HTML string or DOM nodes for the text slot),
1121
+ * colorContent (HTML string or DOM nodes for the color slot), quality,
1122
+ * renderer, respectReducedMotion, mouseColor, cssVars.
874
1123
  */
875
1124
  function createCapsule(container) {
876
1125
  var _options$preset;
@@ -878,53 +1127,73 @@ function createCapsule(container) {
878
1127
  if (!container || typeof container.appendChild !== 'function') {
879
1128
  throw new Error('createCapsule: container element is required');
880
1129
  }
881
- var preset = _objectSpread2({}, getPreset('capsule', (_options$preset = options.preset) !== null && _options$preset !== void 0 ? _options$preset : 'NC-01'));
1130
+ var preset = _objectSpread2({}, getPreset('capsule', (_options$preset = options.preset) !== null && _options$preset !== void 0 ? _options$preset : '初光'));
882
1131
  var merged = normalizeOptions(DEFAULTS.capsule, preset, options);
883
- var copy = _objectSpread2(_objectSpread2({}, COPY), merged.copy || {});
1132
+ var normalizedColors = merged.colors.map(normalizeColor);
1133
+ if (normalizedColors.every(Boolean)) preset.colors = normalizedColors;
1134
+ preset.seed = merged.seed;
1135
+ preset.speed = merged.speed;
1136
+ var customLabel = typeof options.label === 'string' && options.label ? options.label : null;
884
1137
  var root = document.createElement('div');
885
1138
  root.className = 'hj-capsule-root hj-capsule-cosmic';
886
1139
  root.dataset.group = preset.group;
887
1140
  root.dataset.mode = 'nebula';
888
1141
  root.dataset.theme = preset.theme || 'light';
889
- root.setAttribute('aria-label', copy.capsuleAria.replace('{name}', preset.name));
890
- var copyEnabled = copy.enabled !== false && merged.showCopy !== false;
891
- var copyText = function copyText(key, fallback) {
892
- var value = copy[key];
893
- return value === undefined ? fallback : value;
894
- };
895
- function buildCopyHtml() {
896
- var codeText = copyText('code', preset.code);
897
- var nameText = copyText('name', preset.name);
898
- var subtitleText = copyText('subtitle', preset.subtitle);
899
- var stateText = copyText('state', 'LIVE COSMIC STUDY');
900
- var html = '';
901
- if (codeText) html += "<span class=\"hj-capsule-code\">".concat(codeText, "</span>");
902
- if (nameText) html += "<span class=\"hj-capsule-name\">".concat(nameText, "</span>");
903
- if (subtitleText) html += "<span class=\"hj-capsule-brand\">".concat(subtitleText, "</span>");
904
- if (stateText) html += "<span class=\"hj-capsule-state\">".concat(stateText, "</span>");
905
- return html;
906
- }
907
- var copyLayer = document.createElement('div');
908
- copyLayer.className = 'hj-capsule-copy';
909
- var renderCopy = function renderCopy() {
910
- if (copyEnabled) copyLayer.innerHTML = buildCopyHtml();
1142
+ root.setAttribute('role', 'img');
1143
+ var updateAria = function updateAria() {
1144
+ root.setAttribute('aria-label', customLabel || COPY.capsuleAria.replace('{name}', preset.name));
911
1145
  };
912
- renderCopy();
913
- var isHexColor = function isHexColor(value) {
914
- return typeof value === 'string' && /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(value);
1146
+ updateAria();
1147
+
1148
+ // Slot containers are always present but transparent by default: without
1149
+ // content they are invisible, so "no slot" behaves like the old
1150
+ // showCopy=false. They only provide geometry — no typography, padding or
1151
+ // background is imposed on user content (see docs: 插槽 CSS 约定).
1152
+ var fillContent = function fillContent(layer, content) {
1153
+ layer.innerHTML = '';
1154
+ if (content == null) return;
1155
+ if (typeof content === 'string') {
1156
+ layer.innerHTML = content;
1157
+ return;
1158
+ }
1159
+ var nodes = Array.isArray(content) ? content : [content];
1160
+ var _iterator = _createForOfIteratorHelper(nodes),
1161
+ _step;
1162
+ try {
1163
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
1164
+ var node = _step.value;
1165
+ if (node && typeof node.nodeType === 'number') layer.appendChild(node);
1166
+ }
1167
+ } catch (err) {
1168
+ _iterator.e(err);
1169
+ } finally {
1170
+ _iterator.f();
1171
+ }
915
1172
  };
916
- if (copy.background) {
917
- root.style.setProperty('--hj-copy-bg', isHexColor(copy.background) ? "linear-gradient(90deg, ".concat(copy.background, " 0%, ").concat(copy.background, " 74%, ").concat(hexToRgba(copy.background, 0.97), " 84%, ").concat(hexToRgba(copy.background, 0), " 100%)") : copy.background);
918
- }
919
- if (copy.color) root.style.setProperty('--hj-copy-color', copy.color);
1173
+ var textLayer = document.createElement('div');
1174
+ textLayer.className = 'hj-capsule-text hj-capsule-copy';
1175
+ var visualLayer = document.createElement('div');
1176
+ visualLayer.className = 'hj-capsule-visual';
1177
+ fillContent(textLayer, options.text);
1178
+ fillContent(visualLayer, options.colorContent);
920
1179
  var canvas = document.createElement('canvas');
921
1180
  canvas.className = 'hj-capsule-canvas';
922
1181
  canvas.setAttribute('aria-hidden', 'true');
923
- if (copyEnabled) root.appendChild(copyLayer);
1182
+ root.appendChild(textLayer);
1183
+ root.appendChild(visualLayer);
924
1184
  root.appendChild(canvas);
925
1185
  container.appendChild(root);
926
1186
  var emitter = createEmitter();
927
1187
  var paused = merged.respectReducedMotion && prefersReducedMotion$2();
1188
+ var disposed = false;
1189
+ var dirty = {
1190
+ preset: false,
1191
+ seed: false,
1192
+ speed: false,
1193
+ colors: false,
1194
+ textRatio: false,
1195
+ cssVars: false
1196
+ };
928
1197
  var renderer;
929
1198
  var useWebgl = merged.renderer !== 'canvas2d';
930
1199
  if (useWebgl) {
@@ -934,8 +1203,11 @@ function createCapsule(container) {
934
1203
  });
935
1204
  } catch (error) {
936
1205
  renderer = new FallbackRenderer(canvas, merged);
937
- emitter.emit('error', {
938
- message: String(error && error.message ? error.message : error)
1206
+ nextTick(function () {
1207
+ if (disposed) return;
1208
+ emitter.emit('error', {
1209
+ message: String(error && error.message ? error.message : error)
1210
+ });
939
1211
  });
940
1212
  }
941
1213
  } else {
@@ -949,6 +1221,9 @@ function createCapsule(container) {
949
1221
  var name = _Object$keys[_i];
950
1222
  root.style.setProperty(name, vars[name]);
951
1223
  }
1224
+ if (merged.textRatio !== undefined) {
1225
+ root.style.setProperty('--hj-text-width', "".concat(merged.textRatio, "%"));
1226
+ }
952
1227
  renderer.resize();
953
1228
  };
954
1229
  applySize();
@@ -957,18 +1232,16 @@ function createCapsule(container) {
957
1232
  }) : null;
958
1233
  if (resizeObserver) resizeObserver.observe(root);else window.addEventListener('resize', renderer.resize);
959
1234
  var visibility = createVisibilityGuard(root);
960
- if (merged.interactive !== false) {
961
- root.addEventListener('pointerenter', function () {
962
- return emitter.emit('pointerenter', {
963
- preset: _objectSpread2({}, preset)
964
- });
1235
+ root.addEventListener('pointerenter', function () {
1236
+ return emitter.emit('pointerenter', {
1237
+ preset: _objectSpread2({}, preset)
965
1238
  });
966
- root.addEventListener('pointerleave', function () {
967
- return emitter.emit('pointerleave', {
968
- preset: _objectSpread2({}, preset)
969
- });
1239
+ });
1240
+ root.addEventListener('pointerleave', function () {
1241
+ return emitter.emit('pointerleave', {
1242
+ preset: _objectSpread2({}, preset)
970
1243
  });
971
- }
1244
+ });
972
1245
  root.addEventListener('click', function (event) {
973
1246
  emitter.emit('click', {
974
1247
  event: event,
@@ -1000,13 +1273,16 @@ function createCapsule(container) {
1000
1273
  }, function () {
1001
1274
  return paused;
1002
1275
  });
1003
- emitter.emit('ready', {
1004
- preset: _objectSpread2({}, preset)
1276
+ nextTick(function () {
1277
+ if (disposed) return;
1278
+ emitter.emit('ready', {
1279
+ preset: _objectSpread2({}, preset)
1280
+ });
1005
1281
  });
1006
- var syncCopy = function syncCopy() {
1282
+ var syncTheme = function syncTheme() {
1007
1283
  root.dataset.mode = 'nebula';
1008
1284
  root.dataset.theme = preset.theme || 'light';
1009
- renderCopy();
1285
+ updateAria();
1010
1286
  };
1011
1287
  return {
1012
1288
  element: root,
@@ -1016,9 +1292,12 @@ function createCapsule(container) {
1016
1292
  off: emitter.off,
1017
1293
  setPreset: function setPreset(ref) {
1018
1294
  var next = getPreset('capsule', ref);
1295
+ dirty.preset = true;
1019
1296
  Object.assign(preset, next);
1020
- renderer.setPreset(next);
1021
- syncCopy();
1297
+ var nextColors = preset.colors.map(normalizeColor);
1298
+ if (nextColors.every(Boolean)) preset.colors = nextColors;
1299
+ renderer.setPreset(_objectSpread2({}, preset));
1300
+ syncTheme();
1022
1301
  renderer.resize();
1023
1302
  emitter.emit('presetchange', {
1024
1303
  preset: _objectSpread2({}, next)
@@ -1026,13 +1305,64 @@ function createCapsule(container) {
1026
1305
  return this;
1027
1306
  },
1028
1307
  setColors: function setColors(colors) {
1029
- if (!Array.isArray(colors) || colors.length !== 4) return this;
1030
- preset.colors = colors;
1308
+ var next = Array.isArray(colors) ? colors.map(normalizeColor) : [];
1309
+ if (next.length !== 4 || next.some(function (color) {
1310
+ return !color;
1311
+ })) return this;
1312
+ dirty.colors = true;
1313
+ preset.colors = next;
1031
1314
  renderer.setPreset(_objectSpread2(_objectSpread2({}, preset), {}, {
1032
- colors: colors
1315
+ colors: next
1033
1316
  }));
1034
1317
  return this;
1035
1318
  },
1319
+ setSeed: function setSeed(seed) {
1320
+ var value = Number(seed);
1321
+ if (!Number.isFinite(value)) return this;
1322
+ dirty.seed = true;
1323
+ preset.seed = value;
1324
+ renderer.setPreset(_objectSpread2({}, preset));
1325
+ return this;
1326
+ },
1327
+ setSpeed: function setSpeed(speed) {
1328
+ var value = Number(speed);
1329
+ if (!Number.isFinite(value)) return this;
1330
+ dirty.speed = true;
1331
+ preset.speed = value;
1332
+ renderer.setPreset(_objectSpread2({}, preset));
1333
+ return this;
1334
+ },
1335
+ setText: function setText(content) {
1336
+ fillContent(textLayer, content);
1337
+ return this;
1338
+ },
1339
+ setColorContent: function setColorContent(content) {
1340
+ fillContent(visualLayer, content);
1341
+ return this;
1342
+ },
1343
+ setTextRatio: function setTextRatio(ratio) {
1344
+ var value = Number(ratio);
1345
+ if (!Number.isFinite(value) || value < 0 || value > 100) return this;
1346
+ dirty.textRatio = true;
1347
+ merged.textRatio = value;
1348
+ root.style.setProperty('--hj-text-width', "".concat(value, "%"));
1349
+ return this;
1350
+ },
1351
+ setCssVars: function setCssVars(vars) {
1352
+ if (!vars || _typeof(vars) !== 'object') return this;
1353
+ dirty.cssVars = true;
1354
+ merged.cssVars = _objectSpread2(_objectSpread2({}, merged.cssVars || {}), vars);
1355
+ for (var _i2 = 0, _Object$keys2 = Object.keys(vars); _i2 < _Object$keys2.length; _i2++) {
1356
+ var name = _Object$keys2[_i2];
1357
+ root.style.setProperty(name, vars[name]);
1358
+ }
1359
+ return this;
1360
+ },
1361
+ setLabel: function setLabel(label) {
1362
+ customLabel = typeof label === 'string' && label ? label : null;
1363
+ updateAria();
1364
+ return this;
1365
+ },
1036
1366
  setSize: function setSize(width, height) {
1037
1367
  if (width !== undefined) merged.width = width;
1038
1368
  if (height !== undefined) merged.height = height;
@@ -1040,7 +1370,7 @@ function createCapsule(container) {
1040
1370
  return this;
1041
1371
  },
1042
1372
  randomize: function randomize() {
1043
- renderer.randomize();
1373
+ this.setSeed(Math.random() * 100);
1044
1374
  return this;
1045
1375
  },
1046
1376
  pause: function pause() {
@@ -1057,12 +1387,16 @@ function createCapsule(container) {
1057
1387
  return this;
1058
1388
  },
1059
1389
  dispose: function dispose() {
1390
+ disposed = true;
1060
1391
  unsubscribe();
1061
1392
  visibility.dispose();
1062
1393
  if (resizeObserver) resizeObserver.disconnect();else window.removeEventListener('resize', renderer.resize);
1063
1394
  renderer.dispose();
1064
1395
  root.remove();
1065
- }
1396
+ },
1397
+ textRatio: merged.textRatio,
1398
+ cssVars: merged.cssVars,
1399
+ dirty: dirty
1066
1400
  };
1067
1401
  }
1068
1402
 
@@ -1566,7 +1900,8 @@ var FLOW_PROFILES = {
1566
1900
  };
1567
1901
  var ProgressCapsuleController = /*#__PURE__*/function () {
1568
1902
  function ProgressCapsuleController(_ref) {
1569
- var _options$min,
1903
+ var _options$valueSuffix,
1904
+ _options$min,
1570
1905
  _options$max,
1571
1906
  _options$value,
1572
1907
  _this = this;
@@ -1576,7 +1911,8 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1576
1911
  preset = _ref.preset,
1577
1912
  emitter = _ref.emitter,
1578
1913
  options = _ref.options,
1579
- copy = _ref.copy;
1914
+ copy = _ref.copy,
1915
+ dirty = _ref.dirty;
1580
1916
  _classCallCheck(this, ProgressCapsuleController);
1581
1917
  this.root = root;
1582
1918
  this.canvas = canvas;
@@ -1585,6 +1921,8 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1585
1921
  this.emitter = emitter;
1586
1922
  this.options = options;
1587
1923
  this.copy = copy;
1924
+ this.dirty = dirty;
1925
+ this.valueSuffix = (_options$valueSuffix = options.valueSuffix) !== null && _options$valueSuffix !== void 0 ? _options$valueSuffix : copy.valueSuffix;
1588
1926
  this.profile = preset.edgeStyle === 'tide' ? FLOW_PROFILES.tide : FLOW_PROFILES[preset.id] || FLOW_PROFILES['visual-training'];
1589
1927
  this.min = (_options$min = options.min) !== null && _options$min !== void 0 ? _options$min : 0;
1590
1928
  this.max = (_options$max = options.max) !== null && _options$max !== void 0 ? _options$max : 100;
@@ -1624,12 +1962,24 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1624
1962
  var rounded = Math.round(this.value);
1625
1963
  this.root.style.setProperty('--progress', this.value.toFixed(2));
1626
1964
  this.root.setAttribute('aria-valuenow', String(rounded));
1627
- this.root.setAttribute('aria-valuetext', "".concat(rounded).concat(this.copy.valueSuffix));
1628
- this.valueElement.textContent = "".concat(rounded).concat(this.copy.valueSuffix);
1629
- if (!this.suppressEvents) this.emitter.emit('change', {
1630
- value: this.value,
1631
- source: source
1632
- });
1965
+ this.root.setAttribute('aria-valuetext', "".concat(rounded).concat(this.valueSuffix));
1966
+ if (this.valueElement) this.valueElement.textContent = "".concat(rounded).concat(this.valueSuffix);
1967
+ if (!this.suppressEvents) {
1968
+ if (this.dirty) this.dirty.value = true;
1969
+ this.emitter.emit('change', {
1970
+ value: this.value,
1971
+ source: source
1972
+ });
1973
+ }
1974
+ }
1975
+ }, {
1976
+ key: "setValueSuffix",
1977
+ value: function setValueSuffix(suffix) {
1978
+ this.valueSuffix = String(suffix == null ? '' : suffix);
1979
+ var rounded = Math.round(this.value);
1980
+ if (this.valueElement) this.valueElement.textContent = "".concat(rounded).concat(this.valueSuffix);
1981
+ this.root.setAttribute('aria-valuetext', "".concat(rounded).concat(this.valueSuffix));
1982
+ return this;
1633
1983
  }
1634
1984
  }, {
1635
1985
  key: "resizeCanvas",
@@ -1804,7 +2154,8 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1804
2154
  var width = this.width;
1805
2155
  var height = this.height;
1806
2156
  if (!ctx || width <= 0 || height <= 0) return;
1807
- var shoreline = width * (this.value / 100);
2157
+ var range = Math.max(this.max - this.min, 1);
2158
+ var shoreline = width * Math.min(Math.max((this.value - this.min) / range, 0), 1);
1808
2159
  var time = this.flowTime;
1809
2160
  var _this$preset$colors = _slicedToArray(this.preset.colors, 4),
1810
2161
  dark = _this$preset$colors[0],
@@ -1919,7 +2270,7 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1919
2270
  value: function updateFromPointer(event) {
1920
2271
  var bounds = this.root.getBoundingClientRect();
1921
2272
  var ratio = bounds.width > 0 ? (event.clientX - bounds.left) / bounds.width : 0;
1922
- this.setProgress(ratio * 100, 'drag');
2273
+ this.setProgress(this.min + ratio * (this.max - this.min), 'drag');
1923
2274
  }
1924
2275
  }, {
1925
2276
  key: "beginDrag",
@@ -1927,6 +2278,8 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1927
2278
  if (event.button !== undefined && event.button !== 0) return;
1928
2279
  event.preventDefault();
1929
2280
  this.dragging = true;
2281
+ this.pendingPointer = null;
2282
+ this._dragRaf = 0;
1930
2283
  this.root.classList.add('is-dragging');
1931
2284
  try {
1932
2285
  var _this$root$setPointer, _this$root;
@@ -1940,15 +2293,31 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1940
2293
  }, {
1941
2294
  key: "moveDrag",
1942
2295
  value: function moveDrag(event) {
2296
+ var _this2 = this;
1943
2297
  if (!this.dragging) return;
1944
2298
  event.preventDefault();
1945
- this.updateFromPointer(event);
2299
+ // rAF 合并:一帧最多一次 setProgress/change,视觉仍每帧更新。
2300
+ this.pendingPointer = event;
2301
+ if (this._dragRaf) return;
2302
+ this._dragRaf = requestAnimationFrame(function () {
2303
+ _this2._dragRaf = 0;
2304
+ var pending = _this2.pendingPointer;
2305
+ _this2.pendingPointer = null;
2306
+ if (pending) _this2.updateFromPointer(pending);
2307
+ });
1946
2308
  }
1947
2309
  }, {
1948
2310
  key: "endDrag",
1949
2311
  value: function endDrag(event) {
1950
2312
  if (!this.dragging) return;
1951
2313
  this.dragging = false;
2314
+ if (this._dragRaf) {
2315
+ cancelAnimationFrame(this._dragRaf);
2316
+ this._dragRaf = 0;
2317
+ }
2318
+ var pending = this.pendingPointer;
2319
+ this.pendingPointer = null;
2320
+ if (pending) this.updateFromPointer(pending);
1952
2321
  this.root.classList.remove('is-dragging');
1953
2322
  try {
1954
2323
  var _this$root$hasPointer, _this$root2;
@@ -1963,19 +2332,19 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1963
2332
  }, {
1964
2333
  key: "bindEvents",
1965
2334
  value: function bindEvents() {
1966
- var _this2 = this;
2335
+ var _this3 = this;
1967
2336
  if (this.options.draggable !== false) {
1968
2337
  this.handlers.pointerdown = function (event) {
1969
- return _this2.beginDrag(event);
2338
+ return _this3.beginDrag(event);
1970
2339
  };
1971
2340
  this.handlers.pointermove = function (event) {
1972
- return _this2.moveDrag(event);
2341
+ return _this3.moveDrag(event);
1973
2342
  };
1974
2343
  this.handlers.pointerup = function (event) {
1975
- return _this2.endDrag(event);
2344
+ return _this3.endDrag(event);
1976
2345
  };
1977
2346
  this.handlers.pointercancel = function (event) {
1978
- return _this2.endDrag(event);
2347
+ return _this3.endDrag(event);
1979
2348
  };
1980
2349
  this.root.addEventListener('pointerdown', this.handlers.pointerdown);
1981
2350
  this.root.addEventListener('pointermove', this.handlers.pointermove);
@@ -1984,23 +2353,24 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
1984
2353
  }
1985
2354
  if (this.options.keyboard !== false) {
1986
2355
  this.handlers.keydown = function (event) {
2356
+ var step = (_this3.max - _this3.min) * 0.02;
1987
2357
  var actions = {
1988
- ArrowLeft: -2,
1989
- ArrowDown: -2,
1990
- ArrowRight: 2,
1991
- ArrowUp: 2,
1992
- PageDown: -10,
1993
- PageUp: 10
2358
+ ArrowLeft: -step,
2359
+ ArrowDown: -step,
2360
+ ArrowRight: step,
2361
+ ArrowUp: step,
2362
+ PageDown: -step * 5,
2363
+ PageUp: step * 5
1994
2364
  };
1995
2365
  if (event.key === 'Home') {
1996
2366
  event.preventDefault();
1997
- _this2.setProgress(_this2.min, 'keyboard');
2367
+ _this3.setProgress(_this3.min, 'keyboard');
1998
2368
  } else if (event.key === 'End') {
1999
2369
  event.preventDefault();
2000
- _this2.setProgress(_this2.max, 'keyboard');
2370
+ _this3.setProgress(_this3.max, 'keyboard');
2001
2371
  } else if (actions[event.key]) {
2002
2372
  event.preventDefault();
2003
- _this2.setProgress(_this2.value + actions[event.key], 'keyboard');
2373
+ _this3.setProgress(_this3.value + actions[event.key], 'keyboard');
2004
2374
  } else {
2005
2375
  return;
2006
2376
  }
@@ -2037,6 +2407,7 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2037
2407
  }, {
2038
2408
  key: "dispose",
2039
2409
  value: function dispose() {
2410
+ if (this._dragRaf) cancelAnimationFrame(this._dragRaf);
2040
2411
  if (this.resizeObserver) this.resizeObserver.disconnect();else window.removeEventListener('resize', this.resizeCanvas);
2041
2412
  for (var _i = 0, _Object$keys = Object.keys(this.handlers); _i < _Object$keys.length; _i++) {
2042
2413
  var name = _Object$keys[_i];
@@ -2049,11 +2420,14 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2049
2420
  }();
2050
2421
 
2051
2422
  /**
2052
- * Mount a fluid progress capsule into `container`.
2053
- *
2054
- * Options: preset (id/code/name or object), width, height, value, min, max,
2055
- * draggable, keyboard, colors, edgeStyle, quality,
2056
- * respectReducedMotion, copy, cssVars.
2423
+ * Mount a fluid progress capsule into `container`.
2424
+ *
2425
+ * Options: preset (id/code/name or object), width, height, value, min, max,
2426
+ * draggable, keyboard, colors, edgeStyle, textRatio (0-100, text region
2427
+ * width in percent), text (HTML string or DOM nodes for the text slot),
2428
+ * colorContent (HTML string or DOM nodes for the color slot),
2429
+ * showValue (show/hide the right-side percentage), quality,
2430
+ * respectReducedMotion, cssVars.
2057
2431
  */
2058
2432
  function createProgressCapsule(container) {
2059
2433
  var _options$preset, _merged$min, _merged$max;
@@ -2061,64 +2435,93 @@ function createProgressCapsule(container) {
2061
2435
  if (!container || typeof container.appendChild !== 'function') {
2062
2436
  throw new Error('createProgressCapsule: container element is required');
2063
2437
  }
2064
- var preset = _objectSpread2({}, getPreset('progress', (_options$preset = options.preset) !== null && _options$preset !== void 0 ? _options$preset : 'NC-10'));
2438
+ var preset = _objectSpread2({}, getPreset('progress', (_options$preset = options.preset) !== null && _options$preset !== void 0 ? _options$preset : '星火'));
2065
2439
  var merged = normalizeOptions(DEFAULTS.progress, preset, options);
2066
- var copy = _objectSpread2(_objectSpread2({}, COPY), merged.copy || {});
2440
+ var normalizedColors = merged.colors.map(normalizeColor);
2441
+ if (normalizedColors.every(Boolean)) preset.colors = normalizedColors;
2442
+ preset.edgeStyle = merged.edgeStyle;
2443
+ var copy = COPY;
2444
+ var customLabel = typeof options.label === 'string' && options.label ? options.label : null;
2445
+ // Vue 的裸布尔属性(<ProgressCapsule disabled />)会传成空字符串,
2446
+ // 这里统一按 true 处理。
2447
+ var disabled = merged.disabled === true || merged.disabled === '' || merged.disabled === 'true';
2448
+ var effectiveDraggable = disabled ? false : merged.draggable !== false;
2449
+ var effectiveKeyboard = disabled ? false : merged.keyboard !== false;
2450
+ var dirty = {
2451
+ preset: false,
2452
+ colors: false,
2453
+ textRatio: false,
2454
+ cssVars: false,
2455
+ edgeStyle: false,
2456
+ value: false
2457
+ };
2067
2458
  var root = document.createElement('div');
2068
2459
  root.className = 'hj-capsule-root hj-progress-root';
2069
2460
  root.setAttribute('role', 'slider');
2070
2461
  root.setAttribute('tabindex', '0');
2071
- root.setAttribute('data-draggable', String(merged.draggable !== false));
2462
+ root.setAttribute('data-draggable', String(effectiveDraggable));
2463
+ if (disabled) {
2464
+ root.setAttribute('aria-disabled', 'true');
2465
+ root.classList.add('is-disabled');
2466
+ }
2072
2467
  root.setAttribute('aria-valuemin', String((_merged$min = merged.min) !== null && _merged$min !== void 0 ? _merged$min : 0));
2073
2468
  root.setAttribute('aria-valuemax', String((_merged$max = merged.max) !== null && _merged$max !== void 0 ? _merged$max : 100));
2074
2469
  root.setAttribute('aria-valuenow', String(preset.initialProgress));
2075
- root.setAttribute('aria-label', interpolate(copy.progressAria, {
2076
- brand: copy.brandName,
2077
- code: preset.code,
2078
- name: preset.name
2079
- }));
2080
- if (merged.keyboard === false) root.setAttribute('tabindex', '-1');
2470
+ var updateAria = function updateAria() {
2471
+ root.setAttribute('aria-label', customLabel || interpolate(copy.progressAria, {
2472
+ brand: copy.brandName,
2473
+ code: preset.code,
2474
+ name: preset.name
2475
+ }));
2476
+ };
2477
+ updateAria();
2478
+ if (!effectiveKeyboard) root.setAttribute('tabindex', '-1');
2081
2479
  var canvas = document.createElement('canvas');
2082
2480
  canvas.className = 'hj-progress-canvas';
2083
2481
  canvas.setAttribute('aria-hidden', 'true');
2084
- var copyEnabled = copy.enabled !== false && merged.showCopy !== false;
2085
- var copyText = function copyText(key, fallback) {
2086
- var value = copy[key];
2087
- return value === undefined ? fallback : value;
2088
- };
2089
- function buildCopyHtml() {
2090
- var html = '';
2091
- var brandText = copy.brandName || '';
2092
- var subtitleText = copyText('subtitle', preset.subtitle);
2093
- if (brandText) html += "<span class=\"hj-progress-name\">".concat(brandText, "</span>");
2094
- if (subtitleText) html += "<span class=\"hj-progress-subtitle\">".concat(subtitleText, "</span>");
2095
- return html;
2096
- }
2097
- var copyLayer = document.createElement('div');
2098
- copyLayer.className = 'hj-progress-copy';
2099
- var renderCopy = function renderCopy() {
2100
- if (copyEnabled) copyLayer.innerHTML = buildCopyHtml();
2482
+
2483
+ // Slot containers are always present but transparent by default; they only
2484
+ // provide geometry, never typography/padding/background (docs: 插槽 CSS 约定).
2485
+ var fillContent = function fillContent(layer, content) {
2486
+ layer.innerHTML = '';
2487
+ if (content == null) return;
2488
+ if (typeof content === 'string') {
2489
+ layer.innerHTML = content;
2490
+ return;
2491
+ }
2492
+ var nodes = Array.isArray(content) ? content : [content];
2493
+ var _iterator2 = _createForOfIteratorHelper(nodes),
2494
+ _step2;
2495
+ try {
2496
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
2497
+ var node = _step2.value;
2498
+ if (node && typeof node.nodeType === 'number') layer.appendChild(node);
2499
+ }
2500
+ } catch (err) {
2501
+ _iterator2.e(err);
2502
+ } finally {
2503
+ _iterator2.f();
2504
+ }
2101
2505
  };
2102
- renderCopy();
2103
- if (copy.background) {
2104
- root.style.setProperty('--hj-progress-copy-bg', copy.background);
2105
- root.style.setProperty('--hj-progress-copy-pad', '6px 12px');
2506
+ var textLayer = document.createElement('div');
2507
+ textLayer.className = 'hj-progress-text hj-progress-copy';
2508
+ var visualLayer = document.createElement('div');
2509
+ visualLayer.className = 'hj-progress-visual';
2510
+ fillContent(textLayer, options.text);
2511
+ fillContent(visualLayer, options.colorContent);
2512
+ var valueElement = merged.showValue === false ? null : document.createElement('div');
2513
+ if (valueElement) {
2514
+ valueElement.className = 'hj-progress-value';
2515
+ valueElement.setAttribute('aria-hidden', 'true');
2106
2516
  }
2107
- if (copy.color) root.style.setProperty('--hj-progress-copy-color', copy.color);
2108
- var valueElement = document.createElement('div');
2109
- valueElement.className = 'hj-progress-value';
2110
- valueElement.setAttribute('aria-hidden', 'true');
2111
- var dragLabel = document.createElement('span');
2112
- dragLabel.className = 'hj-progress-drag-label';
2113
- dragLabel.setAttribute('aria-hidden', 'true');
2114
- dragLabel.textContent = copy.dragLabel;
2115
2517
  root.appendChild(canvas);
2116
- if (copyEnabled) root.appendChild(copyLayer);
2117
- root.appendChild(valueElement);
2118
- root.appendChild(dragLabel);
2518
+ root.appendChild(textLayer);
2519
+ root.appendChild(visualLayer);
2520
+ if (valueElement) root.appendChild(valueElement);
2119
2521
  container.appendChild(root);
2120
2522
  var emitter = createEmitter();
2121
2523
  var paused = merged.respectReducedMotion && prefersReducedMotion$1();
2524
+ var disposed = false;
2122
2525
  var applySize = function applySize() {
2123
2526
  root.style.width = parseSize(merged.width);
2124
2527
  root.style.height = parseSize(merged.height);
@@ -2127,6 +2530,9 @@ function createProgressCapsule(container) {
2127
2530
  var name = _Object$keys2[_i2];
2128
2531
  root.style.setProperty(name, vars[name]);
2129
2532
  }
2533
+ if (merged.textRatio !== undefined) {
2534
+ root.style.setProperty('--hj-text-width', "".concat(merged.textRatio, "%"));
2535
+ }
2130
2536
  };
2131
2537
  applySize();
2132
2538
  var controller = new ProgressCapsuleController({
@@ -2135,8 +2541,12 @@ function createProgressCapsule(container) {
2135
2541
  valueElement: valueElement,
2136
2542
  preset: preset,
2137
2543
  emitter: emitter,
2138
- options: merged,
2139
- copy: copy
2544
+ options: _objectSpread2(_objectSpread2({}, merged), {}, {
2545
+ draggable: effectiveDraggable,
2546
+ keyboard: effectiveKeyboard
2547
+ }),
2548
+ copy: copy,
2549
+ dirty: dirty
2140
2550
  });
2141
2551
  var overlay = null;
2142
2552
  if (merged.renderer !== 'canvas2d') {
@@ -2149,7 +2559,14 @@ function createProgressCapsule(container) {
2149
2559
  }
2150
2560
  });
2151
2561
  }
2152
- if (overlay) controller.webglActive = true;
2562
+ if (overlay) controller.webglActive = true;else if (merged.renderer !== 'canvas2d') {
2563
+ nextTick(function () {
2564
+ if (disposed) return;
2565
+ emitter.emit('error', {
2566
+ message: 'WebGL2 unavailable, using Canvas2D fallback'
2567
+ });
2568
+ });
2569
+ }
2153
2570
  var visibility = createVisibilityGuard(root);
2154
2571
  var flowTime = 0;
2155
2572
  var unsubscribe = subscribeScheduler(function (delta, now) {
@@ -2162,16 +2579,14 @@ function createProgressCapsule(container) {
2162
2579
  }, function () {
2163
2580
  return paused;
2164
2581
  });
2165
- emitter.emit('ready', {
2166
- preset: _objectSpread2({}, preset)
2582
+ nextTick(function () {
2583
+ if (disposed) return;
2584
+ emitter.emit('ready', {
2585
+ preset: _objectSpread2({}, preset)
2586
+ });
2167
2587
  });
2168
2588
  var syncDom = function syncDom() {
2169
- root.setAttribute('aria-label', interpolate(copy.progressAria, {
2170
- brand: copy.brandName,
2171
- code: preset.code,
2172
- name: preset.name
2173
- }));
2174
- renderCopy();
2589
+ updateAria();
2175
2590
  };
2176
2591
  return {
2177
2592
  element: root,
@@ -2193,8 +2608,11 @@ function createProgressCapsule(container) {
2193
2608
  },
2194
2609
  setPreset: function setPreset(ref) {
2195
2610
  var next = getPreset('progress', ref);
2611
+ dirty.preset = true;
2196
2612
  Object.assign(preset, next);
2197
- controller.preset = next;
2613
+ var nextColors = preset.colors.map(normalizeColor);
2614
+ if (nextColors.every(Boolean)) preset.colors = nextColors;
2615
+ controller.preset = preset;
2198
2616
  controller.profile = next.edgeStyle === 'tide' ? FLOW_PROFILES.tide : FLOW_PROFILES[next.id] || FLOW_PROFILES['visual-training'];
2199
2617
  controller.flowTime = stringSeed(next.id) * 31;
2200
2618
  controller.seed = stringSeed("".concat(next.id, "-reference")) * Math.PI * 2;
@@ -2204,7 +2622,7 @@ function createProgressCapsule(container) {
2204
2622
  overlay = attachProgressFlowOverlay({
2205
2623
  root: root,
2206
2624
  canvas: canvas,
2207
- preset: next,
2625
+ preset: preset,
2208
2626
  getProgress: function getProgress() {
2209
2627
  return controller.value;
2210
2628
  }
@@ -2213,14 +2631,74 @@ function createProgressCapsule(container) {
2213
2631
  controller.webglActive = Boolean(overlay);
2214
2632
  controller.resizeCanvas();
2215
2633
  emitter.emit('presetchange', {
2216
- preset: _objectSpread2({}, next)
2634
+ preset: _objectSpread2({}, preset)
2217
2635
  });
2218
2636
  return this;
2219
2637
  },
2638
+ setEdgeStyle: function setEdgeStyle(edgeStyle) {
2639
+ var value = String(edgeStyle || '').toLowerCase();
2640
+ if (value !== 'flow' && value !== 'tide') return this;
2641
+ dirty.edgeStyle = true;
2642
+ preset.edgeStyle = value;
2643
+ controller.profile = value === 'tide' ? FLOW_PROFILES.tide : FLOW_PROFILES[preset.id] || FLOW_PROFILES['visual-training'];
2644
+ if (overlay) {
2645
+ overlay.dispose();
2646
+ overlay = attachProgressFlowOverlay({
2647
+ root: root,
2648
+ canvas: canvas,
2649
+ preset: preset,
2650
+ getProgress: function getProgress() {
2651
+ return controller.value;
2652
+ }
2653
+ });
2654
+ }
2655
+ controller.webglActive = Boolean(overlay);
2656
+ controller.resizeCanvas();
2657
+ return this;
2658
+ },
2659
+ setText: function setText(content) {
2660
+ fillContent(textLayer, content);
2661
+ return this;
2662
+ },
2663
+ setColorContent: function setColorContent(content) {
2664
+ fillContent(visualLayer, content);
2665
+ return this;
2666
+ },
2667
+ setTextRatio: function setTextRatio(ratio) {
2668
+ var value = Number(ratio);
2669
+ if (!Number.isFinite(value) || value < 0 || value > 100) return this;
2670
+ dirty.textRatio = true;
2671
+ merged.textRatio = value;
2672
+ root.style.setProperty('--hj-text-width', "".concat(value, "%"));
2673
+ return this;
2674
+ },
2675
+ setCssVars: function setCssVars(vars) {
2676
+ if (!vars || _typeof(vars) !== 'object') return this;
2677
+ dirty.cssVars = true;
2678
+ merged.cssVars = _objectSpread2(_objectSpread2({}, merged.cssVars || {}), vars);
2679
+ for (var _i3 = 0, _Object$keys3 = Object.keys(vars); _i3 < _Object$keys3.length; _i3++) {
2680
+ var name = _Object$keys3[_i3];
2681
+ root.style.setProperty(name, vars[name]);
2682
+ }
2683
+ return this;
2684
+ },
2685
+ setLabel: function setLabel(label) {
2686
+ _readOnlyError("customLabel");
2687
+ updateAria();
2688
+ return this;
2689
+ },
2690
+ setValueSuffix: function setValueSuffix(suffix) {
2691
+ controller.setValueSuffix(suffix);
2692
+ return this;
2693
+ },
2220
2694
  setColors: function setColors(colors) {
2221
- if (!Array.isArray(colors) || colors.length !== 4) return this;
2222
- controller.setColors(colors);
2223
- if (overlay) overlay.setColors(colors);
2695
+ var next = Array.isArray(colors) ? colors.map(normalizeColor) : [];
2696
+ if (next.length !== 4 || next.some(function (color) {
2697
+ return !color;
2698
+ })) return this;
2699
+ dirty.colors = true;
2700
+ controller.setColors(next);
2701
+ if (overlay) overlay.setColors(next);
2224
2702
  controller.resizeCanvas();
2225
2703
  return this;
2226
2704
  },
@@ -2250,12 +2728,16 @@ function createProgressCapsule(container) {
2250
2728
  return this;
2251
2729
  },
2252
2730
  dispose: function dispose() {
2731
+ disposed = true;
2253
2732
  unsubscribe();
2254
2733
  visibility.dispose();
2255
2734
  if (overlay) overlay.dispose();
2256
2735
  controller.dispose();
2257
2736
  root.remove();
2258
- }
2737
+ },
2738
+ textRatio: merged.textRatio,
2739
+ cssVars: merged.cssVars,
2740
+ dirty: dirty
2259
2741
  };
2260
2742
  }
2261
2743
 
@@ -2282,7 +2764,7 @@ function createColorBackground(host) {
2282
2764
  if (!host || typeof host.appendChild !== 'function') {
2283
2765
  throw new Error('createColorBackground: host element is required');
2284
2766
  }
2285
- var preset = _objectSpread2({}, getPreset('capsule', (_options$preset = options.preset) !== null && _options$preset !== void 0 ? _options$preset : 'NC-01'));
2767
+ var preset = _objectSpread2({}, getPreset('capsule', (_options$preset = options.preset) !== null && _options$preset !== void 0 ? _options$preset : '初光'));
2286
2768
  var merged = normalizeOptions({
2287
2769
  quality: DEFAULTS.capsule.quality,
2288
2770
  renderer: DEFAULTS.capsule.renderer,
@@ -2291,6 +2773,10 @@ function createColorBackground(host) {
2291
2773
  opacity: 1,
2292
2774
  fallbackColor: true
2293
2775
  }, preset, options);
2776
+ var normalizedColors = merged.colors.map(normalizeColor);
2777
+ if (normalizedColors.every(Boolean)) preset.colors = normalizedColors;
2778
+ preset.seed = merged.seed;
2779
+ preset.speed = merged.speed;
2294
2780
  var computed = getComputedStyle(host);
2295
2781
  if (computed.position === 'static' || computed.position === '') {
2296
2782
  host.style.position = 'relative';
@@ -2311,6 +2797,16 @@ function createColorBackground(host) {
2311
2797
  host.appendChild(layer);
2312
2798
  var emitter = createEmitter();
2313
2799
  var paused = merged.respectReducedMotion && prefersReducedMotion();
2800
+ var disposed = false;
2801
+ var dirty = {
2802
+ preset: false,
2803
+ seed: false,
2804
+ speed: false,
2805
+ colors: false,
2806
+ opacity: false,
2807
+ fallbackColor: false,
2808
+ mouseColor: false
2809
+ };
2314
2810
  var renderer;
2315
2811
  var useWebgl = merged.renderer !== 'canvas2d';
2316
2812
  if (useWebgl) {
@@ -2322,8 +2818,11 @@ function createColorBackground(host) {
2322
2818
  });
2323
2819
  } catch (error) {
2324
2820
  renderer = new FallbackRenderer(canvas, merged);
2325
- emitter.emit('error', {
2326
- message: String(error && error.message ? error.message : error)
2821
+ nextTick(function () {
2822
+ if (disposed) return;
2823
+ emitter.emit('error', {
2824
+ message: String(error && error.message ? error.message : error)
2825
+ });
2327
2826
  });
2328
2827
  }
2329
2828
  } else {
@@ -2341,8 +2840,11 @@ function createColorBackground(host) {
2341
2840
  }, function () {
2342
2841
  return paused;
2343
2842
  });
2344
- emitter.emit('ready', {
2345
- preset: _objectSpread2({}, preset)
2843
+ nextTick(function () {
2844
+ if (disposed) return;
2845
+ emitter.emit('ready', {
2846
+ preset: _objectSpread2({}, preset)
2847
+ });
2346
2848
  });
2347
2849
  return {
2348
2850
  element: host,
@@ -2353,24 +2855,59 @@ function createColorBackground(host) {
2353
2855
  off: emitter.off,
2354
2856
  setPreset: function setPreset(ref) {
2355
2857
  var next = getPreset('capsule', ref);
2858
+ dirty.preset = true;
2356
2859
  Object.assign(preset, next);
2357
- renderer.setPreset(next);
2860
+ var nextColors = preset.colors.map(normalizeColor);
2861
+ if (nextColors.every(Boolean)) preset.colors = nextColors;
2862
+ renderer.setPreset(_objectSpread2({}, preset));
2358
2863
  renderer.resize();
2359
2864
  syncLayerVars();
2360
2865
  emitter.emit('presetchange', {
2361
- preset: _objectSpread2({}, next)
2866
+ preset: _objectSpread2({}, preset)
2362
2867
  });
2363
2868
  return this;
2364
2869
  },
2365
2870
  setColors: function setColors(colors) {
2366
- if (!Array.isArray(colors) || colors.length !== 4) return this;
2367
- preset.colors = colors;
2871
+ var next = Array.isArray(colors) ? colors.map(normalizeColor) : [];
2872
+ if (next.length !== 4 || next.some(function (color) {
2873
+ return !color;
2874
+ })) return this;
2875
+ dirty.colors = true;
2876
+ preset.colors = next;
2368
2877
  renderer.setPreset(_objectSpread2(_objectSpread2({}, preset), {}, {
2369
- colors: colors
2878
+ colors: next
2370
2879
  }));
2371
2880
  syncLayerVars();
2372
2881
  return this;
2373
2882
  },
2883
+ setSeed: function setSeed(seed) {
2884
+ var value = Number(seed);
2885
+ if (!Number.isFinite(value)) return this;
2886
+ dirty.seed = true;
2887
+ preset.seed = value;
2888
+ renderer.setPreset(_objectSpread2({}, preset));
2889
+ return this;
2890
+ },
2891
+ setSpeed: function setSpeed(speed) {
2892
+ var value = Number(speed);
2893
+ if (!Number.isFinite(value)) return this;
2894
+ dirty.speed = true;
2895
+ preset.speed = value;
2896
+ renderer.setPreset(_objectSpread2({}, preset));
2897
+ return this;
2898
+ },
2899
+ setFallbackColor: function setFallbackColor(value) {
2900
+ dirty.fallbackColor = true;
2901
+ merged.fallbackColor = value;
2902
+ syncLayerVars();
2903
+ return this;
2904
+ },
2905
+ setMouseColor: function setMouseColor(value) {
2906
+ dirty.mouseColor = true;
2907
+ merged.mouseColor = value !== false;
2908
+ if (typeof renderer.setMouseColor === 'function') renderer.setMouseColor(merged.mouseColor);
2909
+ return this;
2910
+ },
2374
2911
  setQuality: function setQuality(quality) {
2375
2912
  merged.quality = quality;
2376
2913
  if (typeof renderer.setDprCap === 'function') renderer.setDprCap(dprCapFor(quality));
@@ -2379,12 +2916,13 @@ function createColorBackground(host) {
2379
2916
  setOpacity: function setOpacity(value) {
2380
2917
  var opacity = Number(value);
2381
2918
  if (!Number.isFinite(opacity)) return this;
2919
+ dirty.opacity = true;
2382
2920
  merged.opacity = Math.min(1, Math.max(0, opacity));
2383
2921
  layer.style.setProperty('--dlc-color-opacity', String(merged.opacity));
2384
2922
  return this;
2385
2923
  },
2386
2924
  randomize: function randomize() {
2387
- renderer.randomize();
2925
+ this.setSeed(Math.random() * 100);
2388
2926
  return this;
2389
2927
  },
2390
2928
  pause: function pause() {
@@ -2396,12 +2934,17 @@ function createColorBackground(host) {
2396
2934
  return this;
2397
2935
  },
2398
2936
  dispose: function dispose() {
2937
+ disposed = true;
2399
2938
  unsubscribe();
2400
2939
  visibility.dispose();
2401
2940
  if (resizeObserver) resizeObserver.disconnect();else window.removeEventListener('resize', renderer.resize);
2402
2941
  renderer.dispose();
2403
2942
  layer.remove();
2404
- }
2943
+ },
2944
+ opacity: merged.opacity,
2945
+ fallbackColor: merged.fallbackColor,
2946
+ mouseColor: merged.mouseColor,
2947
+ dirty: dirty
2405
2948
  };
2406
2949
  }
2407
2950
 
@@ -2422,9 +2965,8 @@ exports.dprCapFor = dprCapFor;
2422
2965
  exports.getPreset = getPreset;
2423
2966
  exports.hexToRgb01 = hexToRgb01$1;
2424
2967
  exports.hexToRgba = hexToRgba;
2968
+ exports.normalizeColor = normalizeColor;
2425
2969
  exports.parseSize = parseSize;
2426
2970
  exports.pauseAll = pauseAll;
2427
2971
  exports.resumeAll = resumeAll;
2428
2972
  exports.validateColors = validateColors;
2429
- exports.validatePreset = validatePreset;
2430
- exports.validateProgressPreset = validateProgressPreset;