@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/index.cjs CHANGED
@@ -417,9 +417,13 @@ function getPreset(kind, ref) {
417
417
  var list = kind === 'capsule' ? CAPSULE_PRESETS : kind === 'progress' ? PROGRESS_PRESETS : null;
418
418
  if (!list) throw new Error("Unknown preset kind: ".concat(kind, " (use \"capsule\" or \"progress\")"));
419
419
  var key = String(ref).trim().toLowerCase();
420
- var found = list.find(function (preset) {
421
- return preset.name.toLowerCase() === key;
422
- });
420
+ var found = null;
421
+ for (var index = 0; index < list.length; index += 1) {
422
+ if (list[index].name.toLowerCase() === key) {
423
+ found = list[index];
424
+ break;
425
+ }
426
+ }
423
427
  if (!found) throw new Error("Unknown ".concat(kind, " preset: ").concat(ref));
424
428
  return found;
425
429
  }
@@ -440,8 +444,8 @@ var DEFAULTS = {
440
444
  min: 0,
441
445
  max: 100,
442
446
  draggable: true,
443
- keyboard: true,
444
447
  disabled: false,
448
+ readonly: false,
445
449
  valueSuffix: '%',
446
450
  edgeStyle: 'flow',
447
451
  quality: 'auto',
@@ -630,7 +634,7 @@ function normalizeRgbArgs(args) {
630
634
  if (parts.length < 3) return null;
631
635
  var to255 = function to255(value) {
632
636
  if (typeof value !== 'string' || !value) return null;
633
- if (value.endsWith('%')) return clampChannel(parseFloat(value) / 100 * 255);
637
+ if (value.charAt(value.length - 1) === '%') return clampChannel(parseFloat(value) / 100 * 255);
634
638
  var number = Number(value);
635
639
  return Number.isFinite(number) ? clampChannel(number) : null;
636
640
  };
@@ -638,9 +642,11 @@ function normalizeRgbArgs(args) {
638
642
  var green = to255(parts[1]);
639
643
  var blue = to255(parts[2]);
640
644
  if (red === null || green === null || blue === null) return null;
641
- return "#".concat([red, green, blue].map(function (n) {
642
- return n.toString(16).padStart(2, '0');
643
- }).join(''));
645
+ var hex = function hex(n) {
646
+ var text = n.toString(16);
647
+ return text.length === 1 ? "0".concat(text) : text;
648
+ };
649
+ return "#".concat(hex(red)).concat(hex(green)).concat(hex(blue));
644
650
  }
645
651
 
646
652
  /**
@@ -910,6 +916,7 @@ var FallbackRenderer = /*#__PURE__*/function () {
910
916
  this.preset = preset;
911
917
  this.context = canvas.getContext('2d');
912
918
  this.visible = true;
919
+ this.timePhase = 0;
913
920
  }
914
921
  return _createClass(FallbackRenderer, [{
915
922
  key: "resize",
@@ -930,7 +937,7 @@ var FallbackRenderer = /*#__PURE__*/function () {
930
937
  var _this$canvas = this.canvas,
931
938
  width = _this$canvas.width,
932
939
  height = _this$canvas.height;
933
- var t = time * (this.preset.speed || 1);
940
+ var t = (time + this.timePhase) * (this.preset.speed || 1);
934
941
  var phase = (this.preset.seed || 0) * 0.7;
935
942
  var gradient = ctx.createLinearGradient(0, 0, width, height);
936
943
  gradient.addColorStop(0, this.preset.colors[0]);
@@ -967,7 +974,10 @@ var FallbackRenderer = /*#__PURE__*/function () {
967
974
  }, {
968
975
  key: "randomize",
969
976
  value: function randomize() {
970
- if (this.preset) this.preset.seed = Math.random() * 100;
977
+ if (this.preset) {
978
+ this.preset.seed = Math.random() * 100;
979
+ this.timePhase = Math.random() * Math.PI * 2;
980
+ }
971
981
  }
972
982
  }, {
973
983
  key: "setMouseColor",
@@ -1220,6 +1230,8 @@ function createCapsule(container) {
1220
1230
  }
1221
1231
  if (merged.textRatio !== undefined) {
1222
1232
  root.style.setProperty('--hj-text-width', "".concat(merged.textRatio, "%"));
1233
+ var userMinWidth = merged.cssVars && merged.cssVars['--hj-text-min-width'];
1234
+ 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');
1223
1235
  }
1224
1236
  renderer.resize();
1225
1237
  };
@@ -1343,6 +1355,8 @@ function createCapsule(container) {
1343
1355
  dirty.textRatio = true;
1344
1356
  merged.textRatio = value;
1345
1357
  root.style.setProperty('--hj-text-width', "".concat(value, "%"));
1358
+ var userMinWidth = merged.cssVars && merged.cssVars['--hj-text-min-width'];
1359
+ 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');
1346
1360
  return this;
1347
1361
  },
1348
1362
  setCssVars: function setCssVars(vars) {
@@ -1361,8 +1375,14 @@ function createCapsule(container) {
1361
1375
  return this;
1362
1376
  },
1363
1377
  setSize: function setSize(width, height) {
1364
- if (width !== undefined) merged.width = width;
1365
- if (height !== undefined) merged.height = height;
1378
+ if (width !== undefined) {
1379
+ parseSize(width); // 非法尺寸直接抛错前先校验,避免污染内部状态
1380
+ merged.width = width;
1381
+ }
1382
+ if (height !== undefined) {
1383
+ parseSize(height);
1384
+ merged.height = height;
1385
+ }
1366
1386
  applySize();
1367
1387
  return this;
1368
1388
  },
@@ -1391,8 +1411,12 @@ function createCapsule(container) {
1391
1411
  renderer.dispose();
1392
1412
  root.remove();
1393
1413
  },
1394
- textRatio: merged.textRatio,
1395
- cssVars: merged.cssVars,
1414
+ get textRatio() {
1415
+ return merged.textRatio;
1416
+ },
1417
+ get cssVars() {
1418
+ return merged.cssVars;
1419
+ },
1396
1420
  dirty: dirty
1397
1421
  };
1398
1422
  }
@@ -1688,8 +1712,12 @@ function drawCloud(context, x, y, radiusX, radiusY, color, alpha) {
1688
1712
  context.translate(x, y);
1689
1713
  context.scale(1, radiusY / radiusX);
1690
1714
  var gradient = context.createRadialGradient(0, 0, 0, 0, 0, radiusX);
1691
- gradient.addColorStop(0, "".concat(color).concat(Math.round(alpha * 255).toString(16).padStart(2, '0')));
1692
- gradient.addColorStop(0.46, "".concat(color).concat(Math.round(alpha * 0.42 * 255).toString(16).padStart(2, '0')));
1715
+ var alphaHex = function alphaHex(value) {
1716
+ var text = Math.round(value).toString(16);
1717
+ return text.length === 1 ? "0".concat(text) : text;
1718
+ };
1719
+ gradient.addColorStop(0, "".concat(color).concat(alphaHex(alpha * 255)));
1720
+ gradient.addColorStop(0.46, "".concat(color).concat(alphaHex(alpha * 0.42 * 255)));
1693
1721
  gradient.addColorStop(1, "".concat(color, "00"));
1694
1722
  context.fillStyle = gradient;
1695
1723
  context.fillRect(-radiusX, -radiusX, radiusX * 2, radiusX * 2);
@@ -2139,6 +2167,11 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2139
2167
  }, {
2140
2168
  key: "setRange",
2141
2169
  value: function setRange(min, max) {
2170
+ if (min > max) {
2171
+ var swap = min;
2172
+ min = max;
2173
+ max = swap;
2174
+ }
2142
2175
  this.min = min;
2143
2176
  this.max = max;
2144
2177
  var clamped = clamp(this.value, this.min, this.max);
@@ -2274,6 +2307,14 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2274
2307
  value: function beginDrag(event) {
2275
2308
  if (event.button !== undefined && event.button !== 0) return;
2276
2309
  event.preventDefault();
2310
+ // preventDefault 会吞掉点击聚焦,主动聚焦让键盘方向键立即可用。
2311
+ try {
2312
+ this.root.focus({
2313
+ preventScroll: true
2314
+ });
2315
+ } catch (_unused) {
2316
+ this.root.focus();
2317
+ }
2277
2318
  this.dragging = true;
2278
2319
  this.pendingPointer = null;
2279
2320
  this._dragRaf = 0;
@@ -2281,7 +2322,7 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2281
2322
  try {
2282
2323
  var _this$root$setPointer, _this$root;
2283
2324
  (_this$root$setPointer = (_this$root = this.root).setPointerCapture) === null || _this$root$setPointer === void 0 || _this$root$setPointer.call(_this$root, event.pointerId);
2284
- } catch (_unused) {}
2325
+ } catch (_unused2) {}
2285
2326
  this.emitter.emit('dragstart', {
2286
2327
  value: this.value
2287
2328
  });
@@ -2321,7 +2362,7 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2321
2362
  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)) {
2322
2363
  this.root.releasePointerCapture(event.pointerId);
2323
2364
  }
2324
- } catch (_unused2) {}
2365
+ } catch (_unused3) {}
2325
2366
  this.emitter.emit('dragend', {
2326
2367
  value: this.value
2327
2368
  });
@@ -2348,32 +2389,6 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2348
2389
  this.root.addEventListener('pointerup', this.handlers.pointerup);
2349
2390
  this.root.addEventListener('pointercancel', this.handlers.pointercancel);
2350
2391
  }
2351
- if (this.options.keyboard !== false) {
2352
- this.handlers.keydown = function (event) {
2353
- var step = (_this3.max - _this3.min) * 0.02;
2354
- var actions = {
2355
- ArrowLeft: -step,
2356
- ArrowDown: -step,
2357
- ArrowRight: step,
2358
- ArrowUp: step,
2359
- PageDown: -step * 5,
2360
- PageUp: step * 5
2361
- };
2362
- if (event.key === 'Home') {
2363
- event.preventDefault();
2364
- _this3.setProgress(_this3.min, 'keyboard');
2365
- } else if (event.key === 'End') {
2366
- event.preventDefault();
2367
- _this3.setProgress(_this3.max, 'keyboard');
2368
- } else if (actions[event.key]) {
2369
- event.preventDefault();
2370
- _this3.setProgress(_this3.value + actions[event.key], 'keyboard');
2371
- } else {
2372
- return;
2373
- }
2374
- };
2375
- this.root.addEventListener('keydown', this.handlers.keydown);
2376
- }
2377
2392
  }
2378
2393
  }, {
2379
2394
  key: "update",
@@ -2420,7 +2435,7 @@ var ProgressCapsuleController = /*#__PURE__*/function () {
2420
2435
  * Mount a fluid progress capsule into `container`.
2421
2436
  *
2422
2437
  * Options: preset (id/code/name or object), width, height, value, min, max,
2423
- * draggable, keyboard, colors, edgeStyle, textRatio (0-100, text region
2438
+ * draggable, colors, edgeStyle, textRatio (0-100, text region
2424
2439
  * width in percent), text (HTML string or DOM nodes for the text slot),
2425
2440
  * colorContent (HTML string or DOM nodes for the color slot),
2426
2441
  * showValue (show/hide the right-side percentage), quality,
@@ -2434,6 +2449,11 @@ function createProgressCapsule(container) {
2434
2449
  }
2435
2450
  var preset = _objectSpread2({}, getPreset('progress', (_options$preset = options.preset) !== null && _options$preset !== void 0 ? _options$preset : '星火'));
2436
2451
  var merged = normalizeOptions(DEFAULTS.progress, preset, options);
2452
+ if (merged.min > merged.max) {
2453
+ var swap = merged.min;
2454
+ merged.min = merged.max;
2455
+ merged.max = swap;
2456
+ }
2437
2457
  var normalizedColors = merged.colors.map(normalizeColor);
2438
2458
  if (normalizedColors.every(Boolean)) preset.colors = normalizedColors;
2439
2459
  preset.edgeStyle = merged.edgeStyle;
@@ -2442,8 +2462,9 @@ function createProgressCapsule(container) {
2442
2462
  // Vue 的裸布尔属性(<ProgressCapsule disabled />)会传成空字符串,
2443
2463
  // 这里统一按 true 处理。
2444
2464
  var disabled = merged.disabled === true || merged.disabled === '' || merged.disabled === 'true';
2445
- var effectiveDraggable = disabled ? false : merged.draggable !== false;
2446
- var effectiveKeyboard = disabled ? false : merged.keyboard !== false;
2465
+ var readonly = merged.readonly === true || merged.readonly === '' || merged.readonly === 'true';
2466
+ var locked = disabled || readonly;
2467
+ var effectiveDraggable = locked ? false : merged.draggable !== false;
2447
2468
  var dirty = {
2448
2469
  preset: false,
2449
2470
  colors: false,
@@ -2455,12 +2476,16 @@ function createProgressCapsule(container) {
2455
2476
  var root = document.createElement('div');
2456
2477
  root.className = 'hj-capsule-root hj-progress-root';
2457
2478
  root.setAttribute('role', 'slider');
2458
- root.setAttribute('tabindex', '0');
2459
2479
  root.setAttribute('data-draggable', String(effectiveDraggable));
2460
2480
  if (disabled) {
2461
2481
  root.setAttribute('aria-disabled', 'true');
2462
2482
  root.classList.add('is-disabled');
2463
2483
  }
2484
+ if (readonly) {
2485
+ root.setAttribute('aria-readonly', 'true');
2486
+ root.classList.add('is-readonly');
2487
+ }
2488
+ if (locked) root.setAttribute('tabindex', '-1');
2464
2489
  root.setAttribute('aria-valuemin', String((_merged$min = merged.min) !== null && _merged$min !== void 0 ? _merged$min : 0));
2465
2490
  root.setAttribute('aria-valuemax', String((_merged$max = merged.max) !== null && _merged$max !== void 0 ? _merged$max : 100));
2466
2491
  root.setAttribute('aria-valuenow', String(preset.initialProgress));
@@ -2472,7 +2497,6 @@ function createProgressCapsule(container) {
2472
2497
  }));
2473
2498
  };
2474
2499
  updateAria();
2475
- if (!effectiveKeyboard) root.setAttribute('tabindex', '-1');
2476
2500
  var canvas = document.createElement('canvas');
2477
2501
  canvas.className = 'hj-progress-canvas';
2478
2502
  canvas.setAttribute('aria-hidden', 'true');
@@ -2539,8 +2563,7 @@ function createProgressCapsule(container) {
2539
2563
  preset: preset,
2540
2564
  emitter: emitter,
2541
2565
  options: _objectSpread2(_objectSpread2({}, merged), {}, {
2542
- draggable: effectiveDraggable,
2543
- keyboard: effectiveKeyboard
2566
+ draggable: effectiveDraggable
2544
2567
  }),
2545
2568
  copy: copy,
2546
2569
  dirty: dirty
@@ -2700,8 +2723,14 @@ function createProgressCapsule(container) {
2700
2723
  return this;
2701
2724
  },
2702
2725
  setSize: function setSize(width, height) {
2703
- if (width !== undefined) merged.width = width;
2704
- if (height !== undefined) merged.height = height;
2726
+ if (width !== undefined) {
2727
+ parseSize(width);
2728
+ merged.width = width;
2729
+ }
2730
+ if (height !== undefined) {
2731
+ parseSize(height);
2732
+ merged.height = height;
2733
+ }
2705
2734
  applySize();
2706
2735
  controller.resizeCanvas();
2707
2736
  return this;
@@ -2732,8 +2761,12 @@ function createProgressCapsule(container) {
2732
2761
  controller.dispose();
2733
2762
  root.remove();
2734
2763
  },
2735
- textRatio: merged.textRatio,
2736
- cssVars: merged.cssVars,
2764
+ get textRatio() {
2765
+ return merged.textRatio;
2766
+ },
2767
+ get cssVars() {
2768
+ return merged.cssVars;
2769
+ },
2737
2770
  dirty: dirty
2738
2771
  };
2739
2772
  }
@@ -2938,9 +2971,15 @@ function createColorBackground(host) {
2938
2971
  renderer.dispose();
2939
2972
  layer.remove();
2940
2973
  },
2941
- opacity: merged.opacity,
2942
- fallbackColor: merged.fallbackColor,
2943
- mouseColor: merged.mouseColor,
2974
+ get opacity() {
2975
+ return merged.opacity;
2976
+ },
2977
+ get fallbackColor() {
2978
+ return merged.fallbackColor;
2979
+ },
2980
+ get mouseColor() {
2981
+ return merged.mouseColor;
2982
+ },
2944
2983
  dirty: dirty
2945
2984
  };
2946
2985
  }
package/dist/index.mjs CHANGED
@@ -176,9 +176,13 @@ function getPreset(kind, ref) {
176
176
  const list = kind === 'capsule' ? CAPSULE_PRESETS : kind === 'progress' ? PROGRESS_PRESETS : null;
177
177
  if (!list) throw new Error(`Unknown preset kind: ${kind} (use "capsule" or "progress")`);
178
178
  const key = String(ref).trim().toLowerCase();
179
- const found = list.find(
180
- (preset) => preset.name.toLowerCase() === key
181
- );
179
+ let found = null;
180
+ for (let index = 0; index < list.length; index += 1) {
181
+ if (list[index].name.toLowerCase() === key) {
182
+ found = list[index];
183
+ break;
184
+ }
185
+ }
182
186
  if (!found) throw new Error(`Unknown ${kind} preset: ${ref}`);
183
187
  return found;
184
188
  }
@@ -197,10 +201,10 @@ const DEFAULTS = {
197
201
  width: 454,
198
202
  height: 104,
199
203
  min: 0,
200
- max: 100,
204
+ max: 100,
201
205
  draggable: true,
202
- keyboard: true,
203
206
  disabled: false,
207
+ readonly: false,
204
208
  valueSuffix: '%',
205
209
  edgeStyle: 'flow',
206
210
  quality: 'auto',
@@ -391,7 +395,7 @@ function normalizeRgbArgs(args) {
391
395
  if (parts.length < 3) return null;
392
396
  const to255 = (value) => {
393
397
  if (typeof value !== 'string' || !value) return null;
394
- if (value.endsWith('%')) return clampChannel((parseFloat(value) / 100) * 255);
398
+ if (value.charAt(value.length - 1) === '%') return clampChannel((parseFloat(value) / 100) * 255);
395
399
  const number = Number(value);
396
400
  return Number.isFinite(number) ? clampChannel(number) : null;
397
401
  };
@@ -399,7 +403,11 @@ function normalizeRgbArgs(args) {
399
403
  const green = to255(parts[1]);
400
404
  const blue = to255(parts[2]);
401
405
  if (red === null || green === null || blue === null) return null;
402
- return `#${[red, green, blue].map((n) => n.toString(16).padStart(2, '0')).join('')}`;
406
+ const hex = (n) => {
407
+ const text = n.toString(16);
408
+ return text.length === 1 ? `0${text}` : text;
409
+ };
410
+ return `#${hex(red)}${hex(green)}${hex(blue)}`;
403
411
  }
404
412
 
405
413
  /**
@@ -762,12 +770,13 @@ function rgb(color, alpha = 1) {
762
770
  }
763
771
 
764
772
  class FallbackRenderer {
765
- constructor(canvas, preset) {
766
- this.canvas = canvas;
767
- this.preset = preset;
768
- this.context = canvas.getContext('2d');
769
- this.visible = true;
770
- }
773
+ constructor(canvas, preset) {
774
+ this.canvas = canvas;
775
+ this.preset = preset;
776
+ this.context = canvas.getContext('2d');
777
+ this.visible = true;
778
+ this.timePhase = 0;
779
+ }
771
780
 
772
781
  resize() {
773
782
  const rect = this.canvas.getBoundingClientRect();
@@ -783,7 +792,7 @@ class FallbackRenderer {
783
792
  drawNebula(time) {
784
793
  const ctx = this.context;
785
794
  const { width, height } = this.canvas;
786
- const t = time * (this.preset.speed || 1);
795
+ const t = (time + this.timePhase) * (this.preset.speed || 1);
787
796
  const phase = (this.preset.seed || 0) * 0.7;
788
797
  const gradient = ctx.createLinearGradient(0, 0, width, height);
789
798
  gradient.addColorStop(0, this.preset.colors[0]);
@@ -818,7 +827,10 @@ class FallbackRenderer {
818
827
  }
819
828
 
820
829
  randomize() {
821
- if (this.preset) this.preset.seed = Math.random() * 100;
830
+ if (this.preset) {
831
+ this.preset.seed = Math.random() * 100;
832
+ this.timePhase = Math.random() * Math.PI * 2;
833
+ }
822
834
  }
823
835
  setMouseColor() {}
824
836
  dispose() {}
@@ -1053,6 +1065,10 @@ function createCapsule(container, options = {}) {
1053
1065
  for (const name of Object.keys(vars)) root.style.setProperty(name, vars[name]);
1054
1066
  if (merged.textRatio !== undefined) {
1055
1067
  root.style.setProperty('--hj-text-width', `${merged.textRatio}%`);
1068
+ const userMinWidth = merged.cssVars && merged.cssVars['--hj-text-min-width'];
1069
+ if (merged.textRatio === 0) root.style.setProperty('--hj-text-min-width', '0');
1070
+ else if (userMinWidth) root.style.setProperty('--hj-text-min-width', userMinWidth);
1071
+ else root.style.removeProperty('--hj-text-min-width');
1056
1072
  }
1057
1073
  renderer.resize();
1058
1074
  };
@@ -1151,6 +1167,10 @@ function createCapsule(container, options = {}) {
1151
1167
  dirty.textRatio = true;
1152
1168
  merged.textRatio = value;
1153
1169
  root.style.setProperty('--hj-text-width', `${value}%`);
1170
+ const userMinWidth = merged.cssVars && merged.cssVars['--hj-text-min-width'];
1171
+ if (value === 0) root.style.setProperty('--hj-text-min-width', '0');
1172
+ else if (userMinWidth) root.style.setProperty('--hj-text-min-width', userMinWidth);
1173
+ else root.style.removeProperty('--hj-text-min-width');
1154
1174
  return this;
1155
1175
  },
1156
1176
  setCssVars(vars) {
@@ -1166,11 +1186,17 @@ function createCapsule(container, options = {}) {
1166
1186
  return this;
1167
1187
  },
1168
1188
  setSize(width, height) {
1169
- if (width !== undefined) merged.width = width;
1170
- if (height !== undefined) merged.height = height;
1171
- applySize();
1172
- return this;
1173
- },
1189
+ if (width !== undefined) {
1190
+ parseSize(width); // 非法尺寸直接抛错前先校验,避免污染内部状态
1191
+ merged.width = width;
1192
+ }
1193
+ if (height !== undefined) {
1194
+ parseSize(height);
1195
+ merged.height = height;
1196
+ }
1197
+ applySize();
1198
+ return this;
1199
+ },
1174
1200
  randomize() {
1175
1201
  this.setSeed(Math.random() * 100);
1176
1202
  return this;
@@ -1197,8 +1223,8 @@ function createCapsule(container, options = {}) {
1197
1223
  renderer.dispose();
1198
1224
  root.remove();
1199
1225
  },
1200
- textRatio: merged.textRatio,
1201
- cssVars: merged.cssVars,
1226
+ get textRatio() { return merged.textRatio; },
1227
+ get cssVars() { return merged.cssVars; },
1202
1228
  dirty
1203
1229
  };
1204
1230
  }
@@ -1683,13 +1709,17 @@ const PALETTES = {
1683
1709
  'tide': ['#0a2239', '#2e9bff', '#7fe3ff', '#eaf9ff']
1684
1710
  };
1685
1711
 
1686
- function drawCloud(context, x, y, radiusX, radiusY, color, alpha) {
1687
- context.save();
1688
- context.translate(x, y);
1689
- context.scale(1, radiusY / radiusX);
1690
- const gradient = context.createRadialGradient(0, 0, 0, 0, 0, radiusX);
1691
- gradient.addColorStop(0, `${color}${Math.round(alpha * 255).toString(16).padStart(2, '0')}`);
1692
- gradient.addColorStop(0.46, `${color}${Math.round(alpha * 0.42 * 255).toString(16).padStart(2, '0')}`);
1712
+ function drawCloud(context, x, y, radiusX, radiusY, color, alpha) {
1713
+ context.save();
1714
+ context.translate(x, y);
1715
+ context.scale(1, radiusY / radiusX);
1716
+ const gradient = context.createRadialGradient(0, 0, 0, 0, 0, radiusX);
1717
+ const alphaHex = (value) => {
1718
+ const text = Math.round(value).toString(16);
1719
+ return text.length === 1 ? `0${text}` : text;
1720
+ };
1721
+ gradient.addColorStop(0, `${color}${alphaHex(alpha * 255)}`);
1722
+ gradient.addColorStop(0.46, `${color}${alphaHex(alpha * 0.42 * 255)}`);
1693
1723
  gradient.addColorStop(1, `${color}00`);
1694
1724
  context.fillStyle = gradient;
1695
1725
  context.fillRect(-radiusX, -radiusX, radiusX * 2, radiusX * 2);
@@ -2119,9 +2149,14 @@ class ProgressCapsuleController {
2119
2149
  ctx.restore();
2120
2150
  }
2121
2151
 
2122
- setRange(min, max) {
2123
- this.min = min;
2124
- this.max = max;
2152
+ setRange(min, max) {
2153
+ if (min > max) {
2154
+ const swap = min;
2155
+ min = max;
2156
+ max = swap;
2157
+ }
2158
+ this.min = min;
2159
+ this.max = max;
2125
2160
  const clamped = clamp(this.value, this.min, this.max);
2126
2161
  if (clamped !== this.value) this.setProgress(clamped, 'prop');
2127
2162
  }
@@ -2260,6 +2295,8 @@ class ProgressCapsuleController {
2260
2295
  beginDrag(event) {
2261
2296
  if (event.button !== undefined && event.button !== 0) return;
2262
2297
  event.preventDefault();
2298
+ // preventDefault 会吞掉点击聚焦,主动聚焦让键盘方向键立即可用。
2299
+ try { this.root.focus({ preventScroll: true }); } catch { this.root.focus(); }
2263
2300
  this.dragging = true;
2264
2301
  this.pendingPointer = null;
2265
2302
  this._dragRaf = 0;
@@ -2314,33 +2351,7 @@ class ProgressCapsuleController {
2314
2351
  this.root.addEventListener('pointercancel', this.handlers.pointercancel);
2315
2352
  }
2316
2353
 
2317
- if (this.options.keyboard !== false) {
2318
- this.handlers.keydown = (event) => {
2319
- const step = (this.max - this.min) * 0.02;
2320
- const actions = {
2321
- ArrowLeft: -step,
2322
- ArrowDown: -step,
2323
- ArrowRight: step,
2324
- ArrowUp: step,
2325
- PageDown: -step * 5,
2326
- PageUp: step * 5
2327
- };
2328
- if (event.key === 'Home') {
2329
- event.preventDefault();
2330
- this.setProgress(this.min, 'keyboard');
2331
- } else if (event.key === 'End') {
2332
- event.preventDefault();
2333
- this.setProgress(this.max, 'keyboard');
2334
- } else if (actions[event.key]) {
2335
- event.preventDefault();
2336
- this.setProgress(this.value + actions[event.key], 'keyboard');
2337
- } else {
2338
- return;
2339
- }
2340
- };
2341
- this.root.addEventListener('keydown', this.handlers.keydown);
2342
- }
2343
- }
2354
+ }
2344
2355
 
2345
2356
  update(delta, paused) {
2346
2357
  if (!paused) this.flowTime += delta;
@@ -2378,7 +2389,7 @@ class ProgressCapsuleController {
2378
2389
  * Mount a fluid progress capsule into `container`.
2379
2390
  *
2380
2391
  * Options: preset (id/code/name or object), width, height, value, min, max,
2381
- * draggable, keyboard, colors, edgeStyle, textRatio (0-100, text region
2392
+ * draggable, colors, edgeStyle, textRatio (0-100, text region
2382
2393
  * width in percent), text (HTML string or DOM nodes for the text slot),
2383
2394
  * colorContent (HTML string or DOM nodes for the color slot),
2384
2395
  * showValue (show/hide the right-side percentage), quality,
@@ -2391,6 +2402,11 @@ function createProgressCapsule(container, options = {}) {
2391
2402
 
2392
2403
  const preset = { ...getPreset('progress', options.preset ?? '星火') };
2393
2404
  const merged = normalizeOptions(DEFAULTS.progress, preset, options);
2405
+ if (merged.min > merged.max) {
2406
+ const swap = merged.min;
2407
+ merged.min = merged.max;
2408
+ merged.max = swap;
2409
+ }
2394
2410
  const normalizedColors = merged.colors.map(normalizeColor);
2395
2411
  if (normalizedColors.every(Boolean)) preset.colors = normalizedColors;
2396
2412
  preset.edgeStyle = merged.edgeStyle;
@@ -2399,8 +2415,9 @@ function createProgressCapsule(container, options = {}) {
2399
2415
  // Vue 的裸布尔属性(<ProgressCapsule disabled />)会传成空字符串,
2400
2416
  // 这里统一按 true 处理。
2401
2417
  const disabled = merged.disabled === true || merged.disabled === '' || merged.disabled === 'true';
2402
- const effectiveDraggable = disabled ? false : merged.draggable !== false;
2403
- const effectiveKeyboard = disabled ? false : merged.keyboard !== false;
2418
+ const readonly = merged.readonly === true || merged.readonly === '' || merged.readonly === 'true';
2419
+ const locked = disabled || readonly;
2420
+ const effectiveDraggable = locked ? false : merged.draggable !== false;
2404
2421
  const dirty = {
2405
2422
  preset: false,
2406
2423
  colors: false,
@@ -2413,12 +2430,16 @@ function createProgressCapsule(container, options = {}) {
2413
2430
  const root = document.createElement('div');
2414
2431
  root.className = 'hj-capsule-root hj-progress-root';
2415
2432
  root.setAttribute('role', 'slider');
2416
- root.setAttribute('tabindex', '0');
2417
2433
  root.setAttribute('data-draggable', String(effectiveDraggable));
2418
2434
  if (disabled) {
2419
2435
  root.setAttribute('aria-disabled', 'true');
2420
2436
  root.classList.add('is-disabled');
2421
2437
  }
2438
+ if (readonly) {
2439
+ root.setAttribute('aria-readonly', 'true');
2440
+ root.classList.add('is-readonly');
2441
+ }
2442
+ if (locked) root.setAttribute('tabindex', '-1');
2422
2443
  root.setAttribute('aria-valuemin', String(merged.min ?? 0));
2423
2444
  root.setAttribute('aria-valuemax', String(merged.max ?? 100));
2424
2445
  root.setAttribute('aria-valuenow', String(preset.initialProgress));
@@ -2429,8 +2450,6 @@ function createProgressCapsule(container, options = {}) {
2429
2450
  );
2430
2451
  };
2431
2452
  updateAria();
2432
- if (!effectiveKeyboard) root.setAttribute('tabindex', '-1');
2433
-
2434
2453
  const canvas = document.createElement('canvas');
2435
2454
  canvas.className = 'hj-progress-canvas';
2436
2455
  canvas.setAttribute('aria-hidden', 'true');
@@ -2492,7 +2511,7 @@ function createProgressCapsule(container, options = {}) {
2492
2511
  valueElement,
2493
2512
  preset,
2494
2513
  emitter,
2495
- options: { ...merged, draggable: effectiveDraggable, keyboard: effectiveKeyboard },
2514
+ options: { ...merged, draggable: effectiveDraggable },
2496
2515
  copy,
2497
2516
  dirty
2498
2517
  });
@@ -2633,10 +2652,16 @@ function createProgressCapsule(container, options = {}) {
2633
2652
  controller.resizeCanvas();
2634
2653
  return this;
2635
2654
  },
2636
- setSize(width, height) {
2637
- if (width !== undefined) merged.width = width;
2638
- if (height !== undefined) merged.height = height;
2639
- applySize();
2655
+ setSize(width, height) {
2656
+ if (width !== undefined) {
2657
+ parseSize(width);
2658
+ merged.width = width;
2659
+ }
2660
+ if (height !== undefined) {
2661
+ parseSize(height);
2662
+ merged.height = height;
2663
+ }
2664
+ applySize();
2640
2665
  controller.resizeCanvas();
2641
2666
  return this;
2642
2667
  },
@@ -2666,8 +2691,8 @@ function createProgressCapsule(container, options = {}) {
2666
2691
  controller.dispose();
2667
2692
  root.remove();
2668
2693
  },
2669
- textRatio: merged.textRatio,
2670
- cssVars: merged.cssVars,
2694
+ get textRatio() { return merged.textRatio; },
2695
+ get cssVars() { return merged.cssVars; },
2671
2696
  dirty
2672
2697
  };
2673
2698
  }
@@ -2887,9 +2912,9 @@ function createColorBackground(host, options = {}) {
2887
2912
  renderer.dispose();
2888
2913
  layer.remove();
2889
2914
  },
2890
- opacity: merged.opacity,
2891
- fallbackColor: merged.fallbackColor,
2892
- mouseColor: merged.mouseColor,
2915
+ get opacity() { return merged.opacity; },
2916
+ get fallbackColor() { return merged.fallbackColor; },
2917
+ get mouseColor() { return merged.mouseColor; },
2893
2918
  dirty
2894
2919
  };
2895
2920
  }