livegauge 0.0.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 ADDED
@@ -0,0 +1,1080 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ Gauge: () => Gauge
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/Gauge.tsx
28
+ var import_react3 = require("react");
29
+
30
+ // src/theme.ts
31
+ function parseColorRgb(color) {
32
+ const hex = color.match(/^#([0-9a-f]{3,8})$/i);
33
+ if (hex) {
34
+ let h = hex[1];
35
+ if (h.length === 3) h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2];
36
+ return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
37
+ }
38
+ const rgb = color.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/);
39
+ if (rgb) return [+rgb[1], +rgb[2], +rgb[3]];
40
+ return [128, 128, 128];
41
+ }
42
+ function rgba(r, g, b, a) {
43
+ return `rgba(${r}, ${g}, ${b}, ${a})`;
44
+ }
45
+ function resolveTheme(color, mode) {
46
+ const [r, g, b] = parseColorRgb(color);
47
+ const isDark = mode === "dark";
48
+ return {
49
+ accent: color,
50
+ accentRgb: [r, g, b],
51
+ arcTrack: isDark ? "rgba(255, 255, 255, 0.08)" : "rgba(0, 0, 0, 0.07)",
52
+ arcFill: color,
53
+ needleColor: isDark ? "#e5e5e5" : "#1a1a1a",
54
+ needleShadow: isDark ? "rgba(0, 0, 0, 0.5)" : "rgba(0, 0, 0, 0.2)",
55
+ dotUp: "#22c55e",
56
+ dotDown: "#ef4444",
57
+ dotFlat: color,
58
+ glowUp: "rgba(34, 197, 94, 0.25)",
59
+ glowDown: "rgba(239, 68, 68, 0.25)",
60
+ glowFlat: rgba(r, g, b, 0.2),
61
+ tickColor: isDark ? "rgba(255, 255, 255, 0.2)" : "rgba(0, 0, 0, 0.15)",
62
+ tickLabelColor: isDark ? "rgba(255, 255, 255, 0.45)" : "rgba(0, 0, 0, 0.4)",
63
+ valueColor: isDark ? "#e5e5e5" : "#1a1a1a",
64
+ labelColor: isDark ? "rgba(255, 255, 255, 0.45)" : "rgba(0, 0, 0, 0.4)",
65
+ bgRgb: isDark ? [10, 10, 10] : [255, 255, 255],
66
+ labelFont: '11px "SF Mono", Menlo, Monaco, "Cascadia Code", monospace',
67
+ valueFont: '600 28px "SF Mono", Menlo, monospace',
68
+ tickFont: '10px "SF Mono", Menlo, Monaco, "Cascadia Code", monospace'
69
+ };
70
+ }
71
+
72
+ // src/useGaugeEngine.ts
73
+ var import_react = require("react");
74
+
75
+ // src/math/lerp.ts
76
+ function lerp(current, target, speed, dt = 16.67) {
77
+ const factor = 1 - Math.pow(1 - speed, dt / 16.67);
78
+ return current + (target - current) * factor;
79
+ }
80
+
81
+ // src/canvas/dpr.ts
82
+ function getDpr() {
83
+ if (typeof window === "undefined") return 1;
84
+ return Math.min(window.devicePixelRatio || 1, 3);
85
+ }
86
+ function applyDpr(ctx, dpr, w, h) {
87
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
88
+ ctx.clearRect(0, 0, w, h);
89
+ }
90
+
91
+ // src/draw/arc.ts
92
+ function drawArcTrack(ctx, layout, palette) {
93
+ ctx.beginPath();
94
+ ctx.arc(layout.cx, layout.cy, layout.radius, layout.startAngle, layout.endAngle, false);
95
+ ctx.strokeStyle = palette.arcTrack;
96
+ ctx.lineWidth = layout.arcWidth;
97
+ ctx.lineCap = "round";
98
+ ctx.stroke();
99
+ }
100
+ function drawArcZones(ctx, layout, zones, arcWidth) {
101
+ const { cx, cy, radius } = layout;
102
+ const outerR = radius + arcWidth;
103
+ const innerR = Math.max(0, radius - arcWidth);
104
+ const capAngle = arcWidth / 2 / radius + 0.02;
105
+ for (let i = 0; i < zones.length; i++) {
106
+ const zone = zones[i];
107
+ const startA = layout.valueToAngle(zone.from);
108
+ const endA = layout.valueToAngle(zone.to);
109
+ if (Math.abs(endA - startA) < 1e-3) continue;
110
+ const isFirst = i === 0;
111
+ const isLast = i === zones.length - 1;
112
+ if (isFirst || isLast) {
113
+ ctx.save();
114
+ ctx.beginPath();
115
+ const clipStart = isFirst ? startA - capAngle : startA;
116
+ const clipEnd = isLast ? endA + capAngle : endA;
117
+ ctx.arc(cx, cy, outerR, clipStart, clipEnd, false);
118
+ ctx.arc(cx, cy, innerR, clipEnd, clipStart, true);
119
+ ctx.closePath();
120
+ ctx.clip();
121
+ ctx.beginPath();
122
+ ctx.arc(cx, cy, radius, startA, endA, false);
123
+ ctx.strokeStyle = zone.color;
124
+ ctx.lineWidth = arcWidth;
125
+ ctx.lineCap = "round";
126
+ ctx.stroke();
127
+ ctx.restore();
128
+ } else {
129
+ ctx.beginPath();
130
+ ctx.arc(cx, cy, radius, startA, endA, false);
131
+ ctx.strokeStyle = zone.color;
132
+ ctx.lineWidth = arcWidth;
133
+ ctx.lineCap = "butt";
134
+ ctx.stroke();
135
+ }
136
+ }
137
+ }
138
+ function drawArcFill(ctx, layout, palette, valueAngle) {
139
+ const span = Math.abs(valueAngle - layout.startAngle);
140
+ if (span < 2e-3) return;
141
+ ctx.beginPath();
142
+ ctx.arc(layout.cx, layout.cy, layout.radius, layout.startAngle, valueAngle, false);
143
+ ctx.strokeStyle = palette.arcFill;
144
+ ctx.lineWidth = layout.arcWidth;
145
+ ctx.lineCap = "round";
146
+ ctx.stroke();
147
+ }
148
+ function drawMinMaxLabels(ctx, layout, palette, min, max, formatValue) {
149
+ ctx.font = palette.tickFont;
150
+ ctx.fillStyle = palette.tickLabelColor;
151
+ ctx.textBaseline = "top";
152
+ const yOffset = layout.arcWidth / 2 + 6;
153
+ const minX = layout.cx + Math.cos(layout.startAngle) * layout.radius;
154
+ const minY = layout.cy + Math.sin(layout.startAngle) * layout.radius;
155
+ ctx.textAlign = "left";
156
+ ctx.fillText(formatValue(min), minX - 4, minY + yOffset);
157
+ const maxX = layout.cx + Math.cos(layout.endAngle) * layout.radius;
158
+ const maxY = layout.cy + Math.sin(layout.endAngle) * layout.radius;
159
+ ctx.textAlign = "right";
160
+ ctx.fillText(formatValue(max), maxX + 4, maxY + yOffset);
161
+ }
162
+
163
+ // src/draw/needle.ts
164
+ function drawNeedle(ctx, layout, palette, angle, momentum, momentumGlowAlpha = 0, showDot = true) {
165
+ const { cx, cy, radius } = layout;
166
+ const needleLen = radius - layout.arcWidth / 2 - 6;
167
+ const tipX = cx + Math.cos(angle) * needleLen;
168
+ const tipY = cy + Math.sin(angle) * needleLen;
169
+ if (showDot && momentumGlowAlpha > 0.01) {
170
+ const glowColor = momentum === "up" ? palette.glowUp : momentum === "down" ? palette.glowDown : palette.glowFlat;
171
+ ctx.save();
172
+ ctx.globalAlpha = momentumGlowAlpha * 0.6;
173
+ ctx.shadowColor = glowColor;
174
+ ctx.shadowBlur = 18;
175
+ ctx.beginPath();
176
+ ctx.arc(tipX, tipY, 6, 0, Math.PI * 2);
177
+ ctx.fillStyle = glowColor;
178
+ ctx.fill();
179
+ ctx.restore();
180
+ }
181
+ ctx.save();
182
+ ctx.shadowColor = palette.needleShadow;
183
+ ctx.shadowBlur = 8;
184
+ ctx.shadowOffsetY = 2;
185
+ const perpAngle = angle + Math.PI / 2;
186
+ const baseW = 3.5;
187
+ const bx1 = cx + Math.cos(perpAngle) * baseW;
188
+ const by1 = cy + Math.sin(perpAngle) * baseW;
189
+ const bx2 = cx - Math.cos(perpAngle) * baseW;
190
+ const by2 = cy - Math.sin(perpAngle) * baseW;
191
+ ctx.beginPath();
192
+ ctx.moveTo(bx1, by1);
193
+ ctx.lineTo(tipX, tipY);
194
+ ctx.lineTo(bx2, by2);
195
+ ctx.closePath();
196
+ ctx.fillStyle = palette.needleColor;
197
+ ctx.fill();
198
+ ctx.restore();
199
+ ctx.beginPath();
200
+ ctx.arc(cx, cy, 5, 0, Math.PI * 2);
201
+ ctx.fillStyle = palette.needleColor;
202
+ ctx.fill();
203
+ ctx.beginPath();
204
+ ctx.arc(cx, cy, 2.5, 0, Math.PI * 2);
205
+ ctx.fillStyle = palette.accent;
206
+ ctx.fill();
207
+ }
208
+ var CIRCLE_PULSE_INTERVAL = 1500;
209
+ var CIRCLE_PULSE_DURATION = 900;
210
+ function drawCirclePointer(ctx, layout, palette, angle, momentum, momentumGlowAlpha = 0, pulse = false, now_ms = performance.now()) {
211
+ const { cx, cy, radius, arcWidth } = layout;
212
+ const pointerRadius = arcWidth / 2 + 2;
213
+ const px = cx + Math.cos(angle) * radius;
214
+ const py = cy + Math.sin(angle) * radius;
215
+ const baseAlpha = ctx.globalAlpha;
216
+ if (pulse) {
217
+ const t = now_ms % CIRCLE_PULSE_INTERVAL / CIRCLE_PULSE_DURATION;
218
+ if (t < 1) {
219
+ const ringRadius = pointerRadius + t * 12;
220
+ const pulseAlpha = 0.35 * (1 - t);
221
+ ctx.beginPath();
222
+ ctx.arc(px, py, ringRadius, 0, Math.PI * 2);
223
+ ctx.strokeStyle = palette.dotFlat;
224
+ ctx.lineWidth = 1.5;
225
+ ctx.globalAlpha = baseAlpha * pulseAlpha;
226
+ ctx.stroke();
227
+ ctx.globalAlpha = baseAlpha;
228
+ }
229
+ }
230
+ if (momentumGlowAlpha > 0.01) {
231
+ const glowColor = momentum === "up" ? palette.glowUp : momentum === "down" ? palette.glowDown : palette.glowFlat;
232
+ ctx.save();
233
+ ctx.globalAlpha = momentumGlowAlpha * 0.5;
234
+ ctx.shadowColor = glowColor;
235
+ ctx.shadowBlur = 16;
236
+ ctx.beginPath();
237
+ ctx.arc(px, py, pointerRadius + 2, 0, Math.PI * 2);
238
+ ctx.fillStyle = glowColor;
239
+ ctx.fill();
240
+ ctx.restore();
241
+ }
242
+ ctx.save();
243
+ ctx.shadowColor = "rgba(0,0,0,0.3)";
244
+ ctx.shadowBlur = 6;
245
+ ctx.shadowOffsetY = 1;
246
+ ctx.beginPath();
247
+ ctx.arc(px, py, pointerRadius, 0, Math.PI * 2);
248
+ ctx.fillStyle = "#ffffff";
249
+ ctx.fill();
250
+ ctx.restore();
251
+ }
252
+
253
+ // src/draw/ticks.ts
254
+ function autoTickCount(radius) {
255
+ if (radius < 60) return 5;
256
+ if (radius < 100) return 7;
257
+ if (radius < 160) return 9;
258
+ return 11;
259
+ }
260
+ function drawTicks(ctx, layout, palette, min, max, tickCount, showLabels, formatValue) {
261
+ const { cx, cy, radius, arcWidth } = layout;
262
+ const outerR = radius + arcWidth / 2 + 2;
263
+ const majorLen = 8;
264
+ const minorLen = 4;
265
+ const totalAngle = layout.endAngle - layout.startAngle;
266
+ const majorSteps = tickCount - 1;
267
+ for (let i = 0; i <= majorSteps; i++) {
268
+ const t = i / majorSteps;
269
+ const angle = layout.startAngle + t * totalAngle;
270
+ const isMajor = true;
271
+ const len = isMajor ? majorLen : minorLen;
272
+ const innerR = outerR;
273
+ const outerTick = outerR + len;
274
+ const cosA = Math.cos(angle);
275
+ const sinA = Math.sin(angle);
276
+ ctx.beginPath();
277
+ ctx.moveTo(cx + cosA * innerR, cy + sinA * innerR);
278
+ ctx.lineTo(cx + cosA * outerTick, cy + sinA * outerTick);
279
+ ctx.strokeStyle = palette.tickColor;
280
+ ctx.lineWidth = isMajor ? 1.5 : 1;
281
+ ctx.lineCap = "round";
282
+ ctx.stroke();
283
+ if (i < majorSteps) {
284
+ const nextT = (i + 1) / majorSteps;
285
+ const midT = (t + nextT) / 2;
286
+ const midAngle = layout.startAngle + midT * totalAngle;
287
+ const cosM = Math.cos(midAngle);
288
+ const sinM = Math.sin(midAngle);
289
+ ctx.beginPath();
290
+ ctx.moveTo(cx + cosM * innerR, cy + sinM * innerR);
291
+ ctx.lineTo(cx + cosM * (outerR + minorLen), cy + sinM * (outerR + minorLen));
292
+ ctx.strokeStyle = palette.tickColor;
293
+ ctx.lineWidth = 1;
294
+ ctx.lineCap = "round";
295
+ ctx.stroke();
296
+ }
297
+ if (showLabels && isMajor) {
298
+ const value = min + t * (max - min);
299
+ const labelR = outerTick + 10;
300
+ const lx = cx + cosA * labelR;
301
+ const ly = cy + sinA * labelR;
302
+ ctx.font = palette.tickFont;
303
+ ctx.fillStyle = palette.tickLabelColor;
304
+ ctx.textBaseline = "middle";
305
+ if (t < 0.1) {
306
+ ctx.textAlign = "right";
307
+ } else if (t > 0.9) {
308
+ ctx.textAlign = "left";
309
+ } else if (t < 0.4) {
310
+ ctx.textAlign = "right";
311
+ } else if (t > 0.6) {
312
+ ctx.textAlign = "left";
313
+ } else {
314
+ ctx.textAlign = "center";
315
+ }
316
+ ctx.fillText(formatValue(value), lx, ly);
317
+ }
318
+ }
319
+ }
320
+
321
+ // src/draw/dot.ts
322
+ var PULSE_INTERVAL = 1500;
323
+ var PULSE_DURATION = 900;
324
+ function drawDot(ctx, x, y, palette, momentum, pulse = true, now_ms = performance.now()) {
325
+ const baseAlpha = ctx.globalAlpha;
326
+ const dotColor = momentum === "up" ? palette.dotUp : momentum === "down" ? palette.dotDown : palette.dotFlat;
327
+ const glowColor = momentum === "up" ? palette.glowUp : momentum === "down" ? palette.glowDown : palette.glowFlat;
328
+ if (pulse) {
329
+ const t = now_ms % PULSE_INTERVAL / PULSE_DURATION;
330
+ if (t < 1) {
331
+ const radius = 6 + t * 10;
332
+ const pulseAlpha = 0.35 * (1 - t);
333
+ ctx.beginPath();
334
+ ctx.arc(x, y, radius, 0, Math.PI * 2);
335
+ ctx.strokeStyle = dotColor;
336
+ ctx.lineWidth = 1.5;
337
+ ctx.globalAlpha = baseAlpha * pulseAlpha;
338
+ ctx.stroke();
339
+ }
340
+ }
341
+ ctx.save();
342
+ ctx.globalAlpha = baseAlpha * 0.4;
343
+ ctx.shadowColor = glowColor;
344
+ ctx.shadowBlur = 12;
345
+ ctx.beginPath();
346
+ ctx.arc(x, y, 4, 0, Math.PI * 2);
347
+ ctx.fillStyle = glowColor;
348
+ ctx.fill();
349
+ ctx.restore();
350
+ ctx.globalAlpha = baseAlpha;
351
+ ctx.beginPath();
352
+ ctx.arc(x, y, 5, 0, Math.PI * 2);
353
+ ctx.fillStyle = dotColor;
354
+ ctx.fill();
355
+ ctx.beginPath();
356
+ ctx.arc(x, y, 2.5, 0, Math.PI * 2);
357
+ ctx.fillStyle = "#ffffff";
358
+ ctx.fill();
359
+ ctx.globalAlpha = baseAlpha;
360
+ }
361
+
362
+ // src/draw/loading.ts
363
+ var SWEEP_SPEED = 12e-4;
364
+ var SWEEP_ARC_LEN = Math.PI * 0.4;
365
+ var BREATH_SPEED = 2e-3;
366
+ function loadingBreath(now_ms) {
367
+ return 0.3 + 0.15 * Math.sin(now_ms * BREATH_SPEED);
368
+ }
369
+ function drawLoading(ctx, layout, palette, now_ms) {
370
+ const totalAngle = layout.endAngle - layout.startAngle;
371
+ const breath = loadingBreath(now_ms);
372
+ ctx.save();
373
+ ctx.globalAlpha = breath * 0.5;
374
+ ctx.beginPath();
375
+ ctx.arc(layout.cx, layout.cy, layout.radius, layout.startAngle, layout.endAngle, false);
376
+ ctx.strokeStyle = palette.arcTrack;
377
+ ctx.lineWidth = layout.arcWidth;
378
+ ctx.lineCap = "round";
379
+ ctx.stroke();
380
+ ctx.restore();
381
+ const sweepT = now_ms * SWEEP_SPEED % 1;
382
+ const eased = sweepT < 0.5 ? 2 * sweepT * sweepT : 1 - Math.pow(-2 * sweepT + 2, 2) / 2;
383
+ const sweepCenter = layout.startAngle + eased * totalAngle;
384
+ const halfLen = SWEEP_ARC_LEN / 2;
385
+ const sweepStart = Math.max(layout.startAngle, sweepCenter - halfLen);
386
+ const sweepEnd = Math.min(layout.endAngle, sweepCenter + halfLen);
387
+ ctx.save();
388
+ ctx.globalAlpha = breath;
389
+ ctx.beginPath();
390
+ ctx.arc(layout.cx, layout.cy, layout.radius, sweepStart, sweepEnd, false);
391
+ ctx.strokeStyle = palette.accent;
392
+ ctx.lineWidth = layout.arcWidth;
393
+ ctx.lineCap = "round";
394
+ ctx.stroke();
395
+ ctx.restore();
396
+ }
397
+
398
+ // src/draw/particles.ts
399
+ function createParticleState() {
400
+ return { particles: [], cooldown: 0, burstCount: 0 };
401
+ }
402
+ var MAX_PARTICLES = 80;
403
+ var PARTICLE_LIFETIME = 1;
404
+ var COOLDOWN_MS = 400;
405
+ var MAGNITUDE_THRESHOLD = 0.08;
406
+ var MAX_BURSTS = 3;
407
+ function spawnOnSwing(state, momentum, dotX, dotY, swingMagnitude, accentColor, dt, options) {
408
+ state.cooldown = Math.max(0, state.cooldown - dt);
409
+ if (momentum === "flat") return 0;
410
+ if (state.cooldown > 0) return 0;
411
+ if (swingMagnitude < MAGNITUDE_THRESHOLD) {
412
+ state.burstCount = 0;
413
+ return 0;
414
+ }
415
+ if (momentum === "down" && options?.downMomentum !== true) return 0;
416
+ if (state.burstCount >= MAX_BURSTS) return 0;
417
+ state.cooldown = COOLDOWN_MS;
418
+ const scale = options?.scale ?? 1;
419
+ const isUp = momentum === "up";
420
+ const mag = Math.min(swingMagnitude * 5, 1);
421
+ const burstFalloff = mag > 0.6 ? 1 : [1, 0.6, 0.35][state.burstCount] ?? 0.35;
422
+ state.burstCount++;
423
+ const count = Math.round((12 + mag * 20) * scale * burstFalloff);
424
+ const speedMultiplier = 1 + mag * 0.8;
425
+ for (let i = 0; i < count && state.particles.length < MAX_PARTICLES; i++) {
426
+ const baseAngle = isUp ? -Math.PI / 2 : Math.PI / 2;
427
+ const spread = Math.PI * 1.2;
428
+ const angle = baseAngle + (Math.random() - 0.5) * spread;
429
+ const speed = (60 + Math.random() * 100) * speedMultiplier;
430
+ state.particles.push({
431
+ x: dotX + (Math.random() - 0.5) * 24,
432
+ y: dotY + (Math.random() - 0.5) * 8,
433
+ vx: Math.cos(angle) * speed,
434
+ vy: Math.sin(angle) * speed,
435
+ life: 1,
436
+ size: (1 + Math.random() * 1.2) * scale * burstFalloff,
437
+ color: accentColor
438
+ });
439
+ }
440
+ return burstFalloff;
441
+ }
442
+ function drawParticles(ctx, state, dt) {
443
+ if (state.particles.length === 0) return;
444
+ const dtSec = dt / 1e3;
445
+ ctx.save();
446
+ let writeIdx = 0;
447
+ for (let i = 0; i < state.particles.length; i++) {
448
+ const p = state.particles[i];
449
+ p.life -= dtSec / PARTICLE_LIFETIME;
450
+ if (p.life <= 0) continue;
451
+ p.x += p.vx * dtSec;
452
+ p.y += p.vy * dtSec;
453
+ p.vx *= 0.95;
454
+ p.vy *= 0.95;
455
+ ctx.globalAlpha = p.life * 0.55;
456
+ ctx.fillStyle = p.color;
457
+ ctx.beginPath();
458
+ ctx.arc(p.x, p.y, p.size * (0.5 + p.life * 0.5), 0, Math.PI * 2);
459
+ ctx.fill();
460
+ state.particles[writeIdx++] = p;
461
+ }
462
+ state.particles.length = writeIdx;
463
+ ctx.restore();
464
+ }
465
+
466
+ // src/draw/index.ts
467
+ var SHAKE_DECAY_RATE = 2e-3;
468
+ var SHAKE_MIN_AMPLITUDE = 0.2;
469
+ function createShakeState() {
470
+ return { amplitude: 0 };
471
+ }
472
+ function drawGaugeFrame(ctx, layout, palette, opts) {
473
+ const reveal = opts.chartReveal;
474
+ if (opts.loading && reveal < 0.01) {
475
+ drawLoading(ctx, layout, palette, opts.now_ms);
476
+ return;
477
+ }
478
+ const shake = opts.shakeState;
479
+ let shakeX = 0;
480
+ let shakeY = 0;
481
+ if (shake && shake.amplitude > SHAKE_MIN_AMPLITUDE) {
482
+ shakeX = (Math.random() - 0.5) * 2 * shake.amplitude;
483
+ shakeY = (Math.random() - 0.5) * 2 * shake.amplitude;
484
+ ctx.save();
485
+ ctx.translate(shakeX, shakeY);
486
+ }
487
+ if (shake) {
488
+ const decayRate = Math.pow(SHAKE_DECAY_RATE, opts.dt / 1e3);
489
+ shake.amplitude *= decayRate;
490
+ if (shake.amplitude < SHAKE_MIN_AMPLITUDE) shake.amplitude = 0;
491
+ }
492
+ const revealRamp = (start, end) => {
493
+ const t = Math.max(0, Math.min(1, (reveal - start) / (end - start)));
494
+ return t * t * (3 - 2 * t);
495
+ };
496
+ const trackAlpha = revealRamp(0, 0.4);
497
+ if (trackAlpha > 0.01) {
498
+ ctx.save();
499
+ ctx.globalAlpha = trackAlpha;
500
+ drawArcTrack(ctx, layout, palette);
501
+ ctx.restore();
502
+ }
503
+ if (opts.zones && opts.zones.length > 0 && trackAlpha > 0.01) {
504
+ ctx.save();
505
+ ctx.globalAlpha = trackAlpha * 0.6;
506
+ drawArcZones(ctx, layout, opts.zones, layout.arcWidth);
507
+ ctx.restore();
508
+ }
509
+ const fillAlpha = revealRamp(0.2, 0.7);
510
+ if (fillAlpha > 0.01) {
511
+ ctx.save();
512
+ ctx.globalAlpha = fillAlpha;
513
+ drawArcFill(ctx, layout, palette, opts.valueAngle);
514
+ ctx.restore();
515
+ }
516
+ if (opts.showTicks) {
517
+ const tickAlpha = revealRamp(0.15, 0.6);
518
+ if (tickAlpha > 0.01) {
519
+ ctx.save();
520
+ ctx.globalAlpha = tickAlpha;
521
+ drawTicks(
522
+ ctx,
523
+ layout,
524
+ palette,
525
+ opts.min,
526
+ opts.max,
527
+ opts.tickCount,
528
+ opts.showTickLabels,
529
+ opts.formatValue
530
+ );
531
+ ctx.restore();
532
+ }
533
+ }
534
+ {
535
+ const labelAlpha = revealRamp(0.15, 0.6);
536
+ if (labelAlpha > 0.01 && !opts.showTickLabels) {
537
+ ctx.save();
538
+ ctx.globalAlpha = labelAlpha;
539
+ drawMinMaxLabels(ctx, layout, palette, opts.min, opts.max, opts.formatValue);
540
+ ctx.restore();
541
+ }
542
+ }
543
+ const needleAlpha = revealRamp(0.3, 0.8);
544
+ if (needleAlpha > 0.01) {
545
+ ctx.save();
546
+ ctx.globalAlpha = needleAlpha;
547
+ if (opts.pointer === "circle") {
548
+ drawCirclePointer(
549
+ ctx,
550
+ layout,
551
+ palette,
552
+ opts.valueAngle,
553
+ opts.momentum,
554
+ opts.momentumGlowAlpha,
555
+ opts.showPulse,
556
+ opts.now_ms
557
+ );
558
+ } else {
559
+ drawNeedle(
560
+ ctx,
561
+ layout,
562
+ palette,
563
+ opts.valueAngle,
564
+ opts.momentum,
565
+ opts.momentumGlowAlpha,
566
+ opts.showDot
567
+ );
568
+ }
569
+ ctx.restore();
570
+ }
571
+ {
572
+ const tipLen = layout.radius - layout.arcWidth / 2 - 6;
573
+ const tipX = layout.cx + Math.cos(opts.valueAngle) * tipLen;
574
+ const tipY = layout.cy + Math.sin(opts.valueAngle) * tipLen;
575
+ if (opts.showDot && opts.pointer !== "circle") {
576
+ const dotAlpha = revealRamp(0.4, 0.9);
577
+ if (dotAlpha > 0.01) {
578
+ ctx.save();
579
+ ctx.globalAlpha = dotAlpha;
580
+ drawDot(ctx, tipX, tipY, palette, opts.momentum, opts.showPulse, opts.now_ms);
581
+ ctx.restore();
582
+ }
583
+ }
584
+ if (opts.particleState && reveal > 0.9) {
585
+ const burstIntensity = spawnOnSwing(
586
+ opts.particleState,
587
+ opts.momentum,
588
+ tipX,
589
+ tipY,
590
+ opts.swingMagnitude,
591
+ palette.accent,
592
+ opts.dt,
593
+ opts.particleOptions
594
+ );
595
+ if (burstIntensity > 0 && shake) {
596
+ shake.amplitude = (3 + opts.swingMagnitude * 4) * burstIntensity;
597
+ }
598
+ drawParticles(ctx, opts.particleState, opts.dt);
599
+ }
600
+ }
601
+ if (opts.loading && reveal < 1) {
602
+ ctx.save();
603
+ ctx.globalAlpha = 1 - reveal;
604
+ drawLoading(ctx, layout, palette, opts.now_ms);
605
+ ctx.restore();
606
+ }
607
+ if (shake && (shakeX !== 0 || shakeY !== 0)) {
608
+ ctx.restore();
609
+ }
610
+ }
611
+
612
+ // src/useGaugeEngine.ts
613
+ var MAX_DELTA_MS = 50;
614
+ var CHART_REVEAL_SPEED = 0.14;
615
+ var CHART_REVEAL_SPEED_FWD = 0.09;
616
+ var MOMENTUM_GLOW_SPEED = 0.08;
617
+ var VALUE_HISTORY_SIZE = 30;
618
+ var SWING_MAGNITUDE_SPEED = 0.06;
619
+ function useGaugeEngine(canvasRef, containerRef, config) {
620
+ const configRef = (0, import_react.useRef)(config);
621
+ configRef.current = config;
622
+ const displayValueRef = (0, import_react.useRef)(config.value);
623
+ const displayMinRef = (0, import_react.useRef)(config.min);
624
+ const displayMaxRef = (0, import_react.useRef)(config.max);
625
+ const rangeInitedRef = (0, import_react.useRef)(false);
626
+ const sizeRef = (0, import_react.useRef)({ w: 0, h: 0 });
627
+ const layoutRef = (0, import_react.useRef)(null);
628
+ const ctxRef = (0, import_react.useRef)(null);
629
+ const rafRef = (0, import_react.useRef)(0);
630
+ const lastFrameRef = (0, import_react.useRef)(0);
631
+ const reducedMotionRef = (0, import_react.useRef)(false);
632
+ const chartRevealRef = (0, import_react.useRef)(0);
633
+ const particleStateRef = (0, import_react.useRef)(createParticleState());
634
+ const shakeStateRef = (0, import_react.useRef)(createShakeState());
635
+ const momentumGlowRef = (0, import_react.useRef)(0);
636
+ const swingMagnitudeRef = (0, import_react.useRef)(0);
637
+ const valueHistoryRef = (0, import_react.useRef)([]);
638
+ const lastMomentumRef = (0, import_react.useRef)("flat");
639
+ (0, import_react.useEffect)(() => {
640
+ const container = containerRef.current;
641
+ if (!container) return;
642
+ const ro = new ResizeObserver((entries) => {
643
+ const entry = entries[0];
644
+ if (!entry) return;
645
+ const { width, height } = entry.contentRect;
646
+ sizeRef.current = { w: width, h: height };
647
+ });
648
+ ro.observe(container);
649
+ const rect = container.getBoundingClientRect();
650
+ sizeRef.current = { w: rect.width, h: rect.height };
651
+ return () => ro.disconnect();
652
+ }, [containerRef]);
653
+ (0, import_react.useEffect)(() => {
654
+ const mql = window.matchMedia("(prefers-reduced-motion: reduce)");
655
+ reducedMotionRef.current = mql.matches;
656
+ const onChange = (e) => {
657
+ reducedMotionRef.current = e.matches;
658
+ };
659
+ mql.addEventListener("change", onChange);
660
+ return () => mql.removeEventListener("change", onChange);
661
+ }, []);
662
+ (0, import_react.useEffect)(() => {
663
+ const onVisibility = () => {
664
+ if (!document.hidden && !rafRef.current) {
665
+ rafRef.current = requestAnimationFrame(draw);
666
+ }
667
+ };
668
+ document.addEventListener("visibilitychange", onVisibility);
669
+ return () => document.removeEventListener("visibilitychange", onVisibility);
670
+ }, []);
671
+ const draw = (0, import_react.useCallback)(() => {
672
+ if (document.hidden) {
673
+ rafRef.current = 0;
674
+ return;
675
+ }
676
+ const canvas = canvasRef.current;
677
+ const { w, h } = sizeRef.current;
678
+ if (!canvas || w === 0 || h === 0) {
679
+ rafRef.current = requestAnimationFrame(draw);
680
+ return;
681
+ }
682
+ const cfg = configRef.current;
683
+ const dpr = getDpr();
684
+ const now_ms = performance.now();
685
+ const dt = lastFrameRef.current ? Math.min(now_ms - lastFrameRef.current, MAX_DELTA_MS) : 16.67;
686
+ lastFrameRef.current = now_ms;
687
+ const targetW = Math.round(w * dpr);
688
+ const targetH = Math.round(h * dpr);
689
+ if (canvas.width !== targetW || canvas.height !== targetH) {
690
+ canvas.width = targetW;
691
+ canvas.height = targetH;
692
+ canvas.style.width = `${w}px`;
693
+ canvas.style.height = `${h}px`;
694
+ }
695
+ let ctx = ctxRef.current;
696
+ if (!ctx || ctx.canvas !== canvas) {
697
+ ctx = canvas.getContext("2d");
698
+ ctxRef.current = ctx;
699
+ }
700
+ if (!ctx) {
701
+ rafRef.current = requestAnimationFrame(draw);
702
+ return;
703
+ }
704
+ applyDpr(ctx, dpr, w, h);
705
+ const noMotion = reducedMotionRef.current;
706
+ const speed = noMotion ? 1 : cfg.lerpSpeed;
707
+ const smoothValue = lerp(displayValueRef.current, cfg.value, speed, dt);
708
+ displayValueRef.current = smoothValue;
709
+ if (!rangeInitedRef.current) {
710
+ displayMinRef.current = cfg.min;
711
+ displayMaxRef.current = cfg.max;
712
+ rangeInitedRef.current = true;
713
+ } else {
714
+ displayMinRef.current = lerp(displayMinRef.current, cfg.min, 0.06, dt);
715
+ displayMaxRef.current = lerp(displayMaxRef.current, cfg.max, 0.06, dt);
716
+ }
717
+ const displayMin = displayMinRef.current;
718
+ const displayMax = displayMaxRef.current;
719
+ const range = displayMax - displayMin || 1;
720
+ const arcWidth = 12;
721
+ const paddingH = 20;
722
+ const hasValueDisplay = cfg.valueDisplayRef != null;
723
+ const paddingBottom = hasValueDisplay ? cfg.label ? 58 : 44 : 24;
724
+ const tickSpace = cfg.showTicks && cfg.showTickLabels ? 30 : cfg.showTicks ? 14 : 0;
725
+ const availableW = w - paddingH * 2 - tickSpace * 2;
726
+ const availableH = h - paddingBottom - tickSpace - 8;
727
+ const radius = Math.max(20, Math.min(availableW / 2, availableH) - arcWidth / 2);
728
+ const cx = w / 2;
729
+ const cy = h - paddingBottom;
730
+ const startAngle = cfg.startAngle;
731
+ const endAngle = cfg.endAngle;
732
+ const totalAngle = endAngle - startAngle;
733
+ const valueToAngle = (v) => {
734
+ const t = Math.max(0, Math.min(1, (v - displayMin) / range));
735
+ return startAngle + t * totalAngle;
736
+ };
737
+ const layout = {
738
+ w,
739
+ h,
740
+ cx,
741
+ cy,
742
+ radius,
743
+ arcWidth,
744
+ startAngle,
745
+ endAngle,
746
+ valueToAngle
747
+ };
748
+ layoutRef.current = layout;
749
+ const history = valueHistoryRef.current;
750
+ const lastEntry = history[history.length - 1];
751
+ if (!lastEntry || lastEntry.value !== cfg.value) {
752
+ history.push({ time: now_ms / 1e3, value: cfg.value });
753
+ if (history.length > VALUE_HISTORY_SIZE) {
754
+ history.splice(0, history.length - VALUE_HISTORY_SIZE);
755
+ }
756
+ }
757
+ let momentum = "flat";
758
+ if (cfg.showMomentum && history.length >= 5) {
759
+ if (cfg.momentumOverride) {
760
+ momentum = cfg.momentumOverride;
761
+ } else {
762
+ const points = history.map((h2) => ({ time: h2.time, value: h2.value }));
763
+ let min = Infinity, max = -Infinity;
764
+ for (const p of points) {
765
+ if (p.value < min) min = p.value;
766
+ if (p.value > max) max = p.value;
767
+ }
768
+ const pRange = max - min;
769
+ if (pRange > 0) {
770
+ const tailStart = Math.max(0, points.length - 5);
771
+ const first = points[tailStart].value;
772
+ const last = points[points.length - 1].value;
773
+ const delta = last - first;
774
+ const threshold = pRange * 0.12;
775
+ if (delta > threshold) momentum = "up";
776
+ else if (delta < -threshold) momentum = "down";
777
+ }
778
+ }
779
+ }
780
+ lastMomentumRef.current = momentum;
781
+ const targetSwing = momentum !== "flat" ? Math.min(1, Math.abs(cfg.value - (history[Math.max(0, history.length - 5)]?.value ?? cfg.value)) / (range * 0.1 || 1)) : 0;
782
+ swingMagnitudeRef.current = lerp(swingMagnitudeRef.current, targetSwing, SWING_MAGNITUDE_SPEED, dt);
783
+ const glowTarget = momentum !== "flat" ? 1 : 0;
784
+ momentumGlowRef.current = lerp(momentumGlowRef.current, glowTarget, MOMENTUM_GLOW_SPEED, dt);
785
+ const hasData = !cfg.loading;
786
+ const revealTarget = hasData ? 1 : 0;
787
+ const revealSpeed = noMotion ? 1 : revealTarget > chartRevealRef.current ? CHART_REVEAL_SPEED_FWD : CHART_REVEAL_SPEED;
788
+ chartRevealRef.current = lerp(chartRevealRef.current, revealTarget, revealSpeed, dt);
789
+ if (chartRevealRef.current > 0.999) chartRevealRef.current = 1;
790
+ if (chartRevealRef.current < 1e-3) chartRevealRef.current = 0;
791
+ const chartReveal = chartRevealRef.current;
792
+ const valueAngle = valueToAngle(smoothValue);
793
+ const tickCount = cfg.tickCount > 0 ? cfg.tickCount : autoTickCount(radius);
794
+ drawGaugeFrame(ctx, layout, cfg.palette, {
795
+ smoothValue,
796
+ valueAngle,
797
+ min: displayMin,
798
+ max: displayMax,
799
+ momentum,
800
+ momentumGlowAlpha: momentumGlowRef.current,
801
+ zones: cfg.zones,
802
+ showTicks: cfg.showTicks,
803
+ tickCount,
804
+ showTickLabels: cfg.showTickLabels,
805
+ showDot: cfg.showDot,
806
+ showPulse: cfg.showPulse,
807
+ pointer: cfg.pointer,
808
+ formatValue: cfg.formatValue,
809
+ dt,
810
+ now_ms,
811
+ chartReveal,
812
+ loading: cfg.loading,
813
+ particleState: cfg.degenOptions ? particleStateRef.current : void 0,
814
+ particleOptions: cfg.degenOptions,
815
+ swingMagnitude: swingMagnitudeRef.current,
816
+ shakeState: cfg.degenOptions ? shakeStateRef.current : void 0
817
+ });
818
+ const valEl = cfg.valueDisplayRef?.current;
819
+ if (valEl) {
820
+ const wrapper = valEl.parentElement;
821
+ if (cfg.loading) {
822
+ if (wrapper) wrapper.style.opacity = "0";
823
+ } else {
824
+ if (wrapper) wrapper.style.opacity = "1";
825
+ valEl.textContent = cfg.formatValue(smoothValue);
826
+ if (cfg.showMomentum) {
827
+ const mc = momentum === "up" ? "#22c55e" : momentum === "down" ? "#ef4444" : "";
828
+ if (mc) valEl.style.color = mc;
829
+ else valEl.style.removeProperty("color");
830
+ } else {
831
+ valEl.style.removeProperty("color");
832
+ }
833
+ }
834
+ if (wrapper) {
835
+ if (cfg.pointer === "circle") {
836
+ wrapper.style.bottom = `${paddingBottom - 5}px`;
837
+ } else {
838
+ wrapper.style.bottom = "4px";
839
+ }
840
+ }
841
+ }
842
+ rafRef.current = requestAnimationFrame(draw);
843
+ }, [canvasRef]);
844
+ (0, import_react.useEffect)(() => {
845
+ rafRef.current = requestAnimationFrame(draw);
846
+ return () => cancelAnimationFrame(rafRef.current);
847
+ }, [draw]);
848
+ return layoutRef;
849
+ }
850
+
851
+ // src/useTooltip.ts
852
+ var import_react2 = require("react");
853
+ function useTooltip(config) {
854
+ const configRef = (0, import_react2.useRef)(config);
855
+ configRef.current = config;
856
+ const onMouseMove = (0, import_react2.useCallback)((e) => {
857
+ const cfg = configRef.current;
858
+ if (!cfg.enabled) return;
859
+ const canvas = cfg.canvasRef.current;
860
+ const tooltip = cfg.tooltipRef.current;
861
+ if (!canvas || !tooltip) return;
862
+ const rect = canvas.getBoundingClientRect();
863
+ const x = e.clientX - rect.left;
864
+ const y = e.clientY - rect.top;
865
+ const val = cfg.posToValue(x, y);
866
+ if (val === null) {
867
+ tooltip.style.opacity = "0";
868
+ tooltip.style.pointerEvents = "none";
869
+ return;
870
+ }
871
+ tooltip.textContent = cfg.formatValue(val);
872
+ tooltip.style.opacity = "1";
873
+ const tw = tooltip.offsetWidth;
874
+ const th = tooltip.offsetHeight;
875
+ let tx = e.clientX - rect.left - tw / 2;
876
+ let ty = e.clientY - rect.top - th - 10;
877
+ if (tx < 2) tx = 2;
878
+ if (tx + tw > rect.width - 2) tx = rect.width - tw - 2;
879
+ if (ty < 2) ty = e.clientY - rect.top + 14;
880
+ tooltip.style.left = `${tx}px`;
881
+ tooltip.style.top = `${ty}px`;
882
+ }, []);
883
+ const onMouseLeave = (0, import_react2.useCallback)(() => {
884
+ const tooltip = configRef.current.tooltipRef.current;
885
+ if (tooltip) {
886
+ tooltip.style.opacity = "0";
887
+ tooltip.style.pointerEvents = "none";
888
+ }
889
+ }, []);
890
+ (0, import_react2.useEffect)(() => {
891
+ const canvas = config.canvasRef.current;
892
+ if (!canvas) return;
893
+ canvas.addEventListener("mousemove", onMouseMove);
894
+ canvas.addEventListener("mouseleave", onMouseLeave);
895
+ return () => {
896
+ canvas.removeEventListener("mousemove", onMouseMove);
897
+ canvas.removeEventListener("mouseleave", onMouseLeave);
898
+ };
899
+ }, [config.canvasRef, onMouseMove, onMouseLeave]);
900
+ }
901
+
902
+ // src/Gauge.tsx
903
+ var import_jsx_runtime = require("react/jsx-runtime");
904
+ var defaultFormatValue = (v) => v.toFixed(0);
905
+ function Gauge({
906
+ value,
907
+ min = 0,
908
+ max = 100,
909
+ theme = "dark",
910
+ color = "#3b82f6",
911
+ zones,
912
+ ticks = true,
913
+ tickLabels = false,
914
+ arcWidth,
915
+ showValue = true,
916
+ label,
917
+ momentum = true,
918
+ degen: degenProp,
919
+ loading = false,
920
+ lerpSpeed = 0.08,
921
+ pointer = "needle",
922
+ dot = false,
923
+ pulse = false,
924
+ tooltip = false,
925
+ formatValue = defaultFormatValue,
926
+ startAngle = Math.PI,
927
+ endAngle = Math.PI * 2,
928
+ className,
929
+ style
930
+ }) {
931
+ const canvasRef = (0, import_react3.useRef)(null);
932
+ const containerRef = (0, import_react3.useRef)(null);
933
+ const valueDisplayRef = (0, import_react3.useRef)(null);
934
+ const tooltipRef = (0, import_react3.useRef)(null);
935
+ const palette = (0, import_react3.useMemo)(() => {
936
+ const p = resolveTheme(color, theme);
937
+ if (arcWidth != null) {
938
+ }
939
+ return p;
940
+ }, [color, theme, arcWidth]);
941
+ const isDark = theme === "dark";
942
+ const showMomentum = momentum !== false;
943
+ const momentumOverride = typeof momentum === "string" ? momentum : void 0;
944
+ const degenEnabled = degenProp != null && degenProp !== false;
945
+ const degenOptions = degenEnabled ? typeof degenProp === "object" ? degenProp : {} : void 0;
946
+ const tickCount = typeof ticks === "number" ? ticks : 0;
947
+ const showTicks = ticks !== false;
948
+ const safeValue = value != null && Number.isFinite(value) ? value : 0;
949
+ const layoutRef = useGaugeEngine(canvasRef, containerRef, {
950
+ value: safeValue,
951
+ min,
952
+ max,
953
+ palette,
954
+ lerpSpeed,
955
+ zones,
956
+ showTicks,
957
+ tickCount,
958
+ showTickLabels: tickLabels,
959
+ showDot: dot,
960
+ showPulse: pulse,
961
+ pointer,
962
+ showMomentum,
963
+ momentumOverride,
964
+ degenOptions,
965
+ loading,
966
+ formatValue,
967
+ valueDisplayRef: showValue ? valueDisplayRef : void 0,
968
+ startAngle,
969
+ endAngle,
970
+ label
971
+ });
972
+ const posToValue = (0, import_react3.useCallback)((cssX, cssY) => {
973
+ const lay = layoutRef.current;
974
+ if (!lay) return null;
975
+ const dx = cssX - lay.cx;
976
+ const dy = cssY - lay.cy;
977
+ const dist = Math.sqrt(dx * dx + dy * dy);
978
+ const halfArc = lay.arcWidth / 2;
979
+ if (dist < lay.radius - halfArc - 14 || dist > lay.radius + halfArc + 14) return null;
980
+ let angle = Math.atan2(dy, dx);
981
+ if (angle < 0) angle += Math.PI * 2;
982
+ const totalAngle = lay.endAngle - lay.startAngle;
983
+ let normStart = lay.startAngle % (Math.PI * 2);
984
+ if (normStart < 0) normStart += Math.PI * 2;
985
+ let rel = angle - normStart;
986
+ if (rel < -0.1) rel += Math.PI * 2;
987
+ if (rel < -0.05 || rel > totalAngle + 0.05) return null;
988
+ const t = Math.max(0, Math.min(1, rel / totalAngle));
989
+ return min + t * (max - min);
990
+ }, [layoutRef, min, max]);
991
+ useTooltip({
992
+ enabled: tooltip,
993
+ canvasRef,
994
+ tooltipRef,
995
+ theme,
996
+ formatValue,
997
+ posToValue
998
+ });
999
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1000
+ "div",
1001
+ {
1002
+ ref: containerRef,
1003
+ className,
1004
+ style: {
1005
+ width: "100%",
1006
+ height: "100%",
1007
+ position: "relative",
1008
+ ...style
1009
+ },
1010
+ children: [
1011
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1012
+ "canvas",
1013
+ {
1014
+ ref: canvasRef,
1015
+ style: { display: "block", cursor: tooltip ? "crosshair" : void 0 }
1016
+ }
1017
+ ),
1018
+ tooltip && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1019
+ "div",
1020
+ {
1021
+ ref: tooltipRef,
1022
+ style: {
1023
+ position: "absolute",
1024
+ top: 0,
1025
+ left: 0,
1026
+ pointerEvents: "none",
1027
+ opacity: 0,
1028
+ transition: "opacity 0.12s",
1029
+ padding: "4px 8px",
1030
+ borderRadius: 4,
1031
+ fontSize: 11,
1032
+ fontWeight: 600,
1033
+ fontFamily: '"SF Mono", Menlo, monospace',
1034
+ whiteSpace: "nowrap",
1035
+ background: isDark ? "rgba(255,255,255,0.92)" : "rgba(0,0,0,0.85)",
1036
+ color: isDark ? "#111" : "#fff",
1037
+ boxShadow: "0 2px 8px rgba(0,0,0,0.18)"
1038
+ }
1039
+ }
1040
+ ),
1041
+ showValue && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
1042
+ display: "flex",
1043
+ flexDirection: "column",
1044
+ alignItems: "center",
1045
+ position: "absolute",
1046
+ left: 0,
1047
+ right: 0,
1048
+ bottom: 4,
1049
+ pointerEvents: "none",
1050
+ transition: "opacity 0.3s"
1051
+ }, children: [
1052
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1053
+ "span",
1054
+ {
1055
+ ref: valueDisplayRef,
1056
+ style: {
1057
+ fontSize: 28,
1058
+ fontWeight: 600,
1059
+ fontFamily: '"SF Mono", Menlo, monospace',
1060
+ color: isDark ? "rgba(255,255,255,0.85)" : "#111",
1061
+ transition: "color 0.3s",
1062
+ letterSpacing: "-0.02em"
1063
+ }
1064
+ }
1065
+ ),
1066
+ label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
1067
+ fontSize: 11,
1068
+ fontFamily: "system-ui, -apple-system, sans-serif",
1069
+ color: isDark ? "rgba(255,255,255,0.4)" : "rgba(0,0,0,0.35)",
1070
+ marginTop: 2
1071
+ }, children: label })
1072
+ ] })
1073
+ ]
1074
+ }
1075
+ );
1076
+ }
1077
+ // Annotate the CommonJS export names for ESM import in node:
1078
+ 0 && (module.exports = {
1079
+ Gauge
1080
+ });