@astra-kit/ui 1.1.0 → 1.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/CHANGELOG.md +25 -0
- package/README.md +5 -3
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/dist/components/empty-state.d.ts +20 -0
- package/dist/components/empty-state.js +357 -0
- package/dist/components/metric-card.d.ts +22 -0
- package/dist/components/metric-card.js +378 -0
- package/dist/components/stepper.d.ts +39 -0
- package/dist/components/stepper.js +693 -0
- package/dist/components/timeline.d.ts +51 -0
- package/dist/components/timeline.js +1013 -0
- package/dist/components/usage-meter.d.ts +39 -0
- package/dist/components/usage-meter.js +1093 -0
- package/dist/constants/empty-state.d.ts +12 -0
- package/dist/constants/empty-state.js +12 -0
- package/dist/constants/metric-card.d.ts +12 -0
- package/dist/constants/metric-card.js +12 -0
- package/dist/constants/stepper.d.ts +52 -0
- package/dist/constants/stepper.js +23 -0
- package/dist/constants/timeline.d.ts +62 -0
- package/dist/constants/timeline.js +31 -0
- package/dist/constants/usage-meter.d.ts +100 -0
- package/dist/constants/usage-meter.js +38 -0
- package/dist/hooks/use-has-entered-view.d.ts +9 -0
- package/dist/hooks/use-has-entered-view.js +46 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/motion/arc-odometer.d.ts +53 -0
- package/dist/motion/arc-odometer.js +424 -0
- package/dist/motion/arc-text-swap.d.ts +22 -0
- package/dist/motion/arc-text-swap.js +142 -0
- package/dist/motion/arc-tokens.d.ts +1 -0
- package/dist/motion/arc-tokens.js +2 -1
- package/dist/styles.css +1 -1
- package/package.json +26 -1
|
@@ -0,0 +1,1093 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { c as _c } from "react/compiler-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* Arc's Usage meter (https://uiarc.dev, MIT License, see THIRD_PARTY_NOTICES.md): shows what fills a fixed allowance and
|
|
5
|
+
* how close it is to the limit. A segmented bar, a rolling total, a status badge and a legend that doubles as the
|
|
6
|
+
* keyboard path. Segments grow in once the meter is seen and re-flow on one spring each when values change; crossing
|
|
7
|
+
* the limit fades in a hatched overage and a limit marker, so going over never relies on colour alone.
|
|
8
|
+
*/
|
|
9
|
+
import { useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
|
10
|
+
import { AnimatePresence, animate, motion, motionValue, useMotionValue, useTransform } from "motion/react";
|
|
11
|
+
import { CircleAlert, TriangleAlert } from "lucide-react";
|
|
12
|
+
import { USAGE_METER_DEFAULT_DECIMALS, USAGE_METER_DEFAULT_FREE_LABEL, USAGE_METER_DEFAULT_LOCALE, USAGE_METER_DEFAULT_MESSAGES, USAGE_METER_DEFAULT_OVER_LABEL, USAGE_METER_DEFAULT_WARN_AT, USAGE_METER_FREE_ID, USAGE_METER_REVEAL_AMOUNT, USAGE_METER_REVEAL_STAGGER_S, USAGE_METER_SEGMENT_COLOR_COUNT, USAGE_METER_SEGMENT_GAP_PX, USAGE_METER_SEGMENT_KEY_PREFIX } from "../constants/usage-meter.js";
|
|
13
|
+
import { useHasEnteredView } from "../hooks/use-has-entered-view.js";
|
|
14
|
+
import { useIsHydrated } from "../hooks/use-is-hydrated.js";
|
|
15
|
+
import { usePrefersReducedMotion } from "../hooks/use-prefers-reduced-motion.js";
|
|
16
|
+
import { cn } from "../lib/utils.js";
|
|
17
|
+
import { ArcOdometer, startNextFrame, toPhysicalSpring } from "../motion/arc-odometer.js";
|
|
18
|
+
import { ArcTextSwap } from "../motion/arc-text-swap.js";
|
|
19
|
+
import { ARC_BLUR, ARC_DURATION, ARC_EASE, ARC_SPRING_MORPH, ARC_SPRING_SMOOTH, ARC_SPRING_SNAPPY } from "../motion/arc-tokens.js";
|
|
20
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
21
|
+
const SETTLE_SPRING = toPhysicalSpring(ARC_SPRING_SMOOTH);
|
|
22
|
+
const REVEAL_SPRING = toPhysicalSpring({
|
|
23
|
+
visualDuration: ARC_DURATION.considered + .1,
|
|
24
|
+
bounce: 0
|
|
25
|
+
});
|
|
26
|
+
const FIT_SPRING = toPhysicalSpring(ARC_SPRING_MORPH, .01);
|
|
27
|
+
/** Icons cross through a small scale and a blur a little stronger than text. */
|
|
28
|
+
const ICON_BLUR_PX = ARC_BLUR.subtle + 1;
|
|
29
|
+
const ICON_ENTER_SCALE = .6;
|
|
30
|
+
/** Smallest span of the bar, so an empty meter with a zero limit never divides by zero. */
|
|
31
|
+
const MINIMUM_SPAN = 1e-6;
|
|
32
|
+
/** Size, in pixels, of the status badge's icon and of the legend's warning icon. */
|
|
33
|
+
const BADGE_ICON_SIZE_PX = 14;
|
|
34
|
+
const LEGEND_ICON_SIZE_PX = 12;
|
|
35
|
+
const PERCENT = 100;
|
|
36
|
+
const popVariants = {
|
|
37
|
+
hidden: {
|
|
38
|
+
opacity: 0,
|
|
39
|
+
scale: ICON_ENTER_SCALE,
|
|
40
|
+
filter: `blur(${ICON_BLUR_PX}px)`
|
|
41
|
+
},
|
|
42
|
+
shown: {
|
|
43
|
+
opacity: 1,
|
|
44
|
+
scale: 1,
|
|
45
|
+
filter: "blur(0px)",
|
|
46
|
+
transition: {
|
|
47
|
+
...ARC_SPRING_SNAPPY,
|
|
48
|
+
opacity: {
|
|
49
|
+
duration: ARC_DURATION.fast,
|
|
50
|
+
ease: [...ARC_EASE.enter]
|
|
51
|
+
},
|
|
52
|
+
filter: {
|
|
53
|
+
duration: ARC_DURATION.fast,
|
|
54
|
+
ease: [...ARC_EASE.enter]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
gone: {
|
|
59
|
+
opacity: 0,
|
|
60
|
+
scale: ICON_ENTER_SCALE,
|
|
61
|
+
filter: `blur(${ICON_BLUR_PX}px)`,
|
|
62
|
+
transition: {
|
|
63
|
+
duration: ARC_DURATION.instant,
|
|
64
|
+
ease: [...ARC_EASE.standard]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const fadeVariants = {
|
|
69
|
+
hidden: { opacity: 0 },
|
|
70
|
+
shown: {
|
|
71
|
+
opacity: 1,
|
|
72
|
+
transition: { duration: ARC_DURATION.fast }
|
|
73
|
+
},
|
|
74
|
+
gone: {
|
|
75
|
+
opacity: 0,
|
|
76
|
+
transition: { duration: ARC_DURATION.instant }
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
/** Category colours: steps of the accent, strongest first, so the meter reads as one allowance rather than a rainbow. */
|
|
80
|
+
const SEGMENT_COLOR_CLASS_NAMES = [
|
|
81
|
+
"bg-(--accent)",
|
|
82
|
+
"bg-[color-mix(in_oklab,var(--accent)_62%,var(--surface))]",
|
|
83
|
+
"bg-[color-mix(in_oklab,var(--accent)_36%,var(--surface))]",
|
|
84
|
+
"bg-[color-mix(in_oklab,var(--accent)_22%,var(--surface))]"
|
|
85
|
+
];
|
|
86
|
+
/** The free space is the track itself. */
|
|
87
|
+
const TRACK_COLOR_CLASS_NAME = "bg-[color-mix(in_oklab,var(--foreground)_7%,var(--surface))]";
|
|
88
|
+
/**
|
|
89
|
+
* Legend and highlight key of a segment, namespaced apart from the remaining-space item.
|
|
90
|
+
* @param id - The segment's own id.
|
|
91
|
+
* @returns The internal key.
|
|
92
|
+
*/
|
|
93
|
+
function segmentKey(id) {
|
|
94
|
+
return `${USAGE_METER_SEGMENT_KEY_PREFIX}${id}`;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Colour class of a category by its position.
|
|
98
|
+
* @param index - Position of the category in `segments`.
|
|
99
|
+
* @returns The background class.
|
|
100
|
+
*/
|
|
101
|
+
function segmentColorClassName(index) {
|
|
102
|
+
return SEGMENT_COLOR_CLASS_NAMES[index % USAGE_METER_SEGMENT_COLOR_COUNT];
|
|
103
|
+
}
|
|
104
|
+
/** The plan status as a compact mark. Its width springs to each new message and the warning icon grows in beside it. */
|
|
105
|
+
function StatusBadge(t0) {
|
|
106
|
+
const $ = _c(22);
|
|
107
|
+
const { status, text, reduceMotion } = t0;
|
|
108
|
+
const inner = useRef(null);
|
|
109
|
+
const width = useMotionValue("auto");
|
|
110
|
+
let t1;
|
|
111
|
+
let t2;
|
|
112
|
+
if ($[0] !== reduceMotion || $[1] !== width) {
|
|
113
|
+
t1 = () => {
|
|
114
|
+
const node = inner.current;
|
|
115
|
+
if (!node || typeof ResizeObserver === "undefined") {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
let hasMeasured = false;
|
|
119
|
+
const observer = new ResizeObserver(() => {
|
|
120
|
+
const next = node.offsetWidth;
|
|
121
|
+
if (hasMeasured && !reduceMotion) {
|
|
122
|
+
animate(width, next, FIT_SPRING);
|
|
123
|
+
} else {
|
|
124
|
+
width.jump(next);
|
|
125
|
+
}
|
|
126
|
+
hasMeasured = next > 0;
|
|
127
|
+
});
|
|
128
|
+
observer.observe(node);
|
|
129
|
+
return () => observer.disconnect();
|
|
130
|
+
};
|
|
131
|
+
t2 = [reduceMotion, width];
|
|
132
|
+
$[0] = reduceMotion;
|
|
133
|
+
$[1] = width;
|
|
134
|
+
$[2] = t1;
|
|
135
|
+
$[3] = t2;
|
|
136
|
+
} else {
|
|
137
|
+
t1 = $[2];
|
|
138
|
+
t2 = $[3];
|
|
139
|
+
}
|
|
140
|
+
useLayoutEffect(t1, t2);
|
|
141
|
+
const Icon = status === "over" ? TriangleAlert : CircleAlert;
|
|
142
|
+
let t3;
|
|
143
|
+
if ($[4] !== width) {
|
|
144
|
+
t3 = { width };
|
|
145
|
+
$[4] = width;
|
|
146
|
+
$[5] = t3;
|
|
147
|
+
} else {
|
|
148
|
+
t3 = $[5];
|
|
149
|
+
}
|
|
150
|
+
let t4;
|
|
151
|
+
if ($[6] !== Icon || $[7] !== reduceMotion || $[8] !== status) {
|
|
152
|
+
t4 = status !== "ok" ? /* @__PURE__ */ _jsx(motion.span, {
|
|
153
|
+
className: cn("grid place-items-center", status === "over" ? "text-danger" : "text-warning"),
|
|
154
|
+
variants: reduceMotion ? fadeVariants : popVariants,
|
|
155
|
+
initial: "hidden",
|
|
156
|
+
animate: "shown",
|
|
157
|
+
exit: "gone",
|
|
158
|
+
children: /* @__PURE__ */ _jsx(Icon, {
|
|
159
|
+
size: BADGE_ICON_SIZE_PX,
|
|
160
|
+
strokeWidth: 2,
|
|
161
|
+
"aria-hidden": "true"
|
|
162
|
+
})
|
|
163
|
+
}, status) : null;
|
|
164
|
+
$[6] = Icon;
|
|
165
|
+
$[7] = reduceMotion;
|
|
166
|
+
$[8] = status;
|
|
167
|
+
$[9] = t4;
|
|
168
|
+
} else {
|
|
169
|
+
t4 = $[9];
|
|
170
|
+
}
|
|
171
|
+
let t5;
|
|
172
|
+
if ($[10] !== t4) {
|
|
173
|
+
t5 = /* @__PURE__ */ _jsx(AnimatePresence, {
|
|
174
|
+
mode: "popLayout",
|
|
175
|
+
initial: false,
|
|
176
|
+
children: t4
|
|
177
|
+
});
|
|
178
|
+
$[10] = t4;
|
|
179
|
+
$[11] = t5;
|
|
180
|
+
} else {
|
|
181
|
+
t5 = $[11];
|
|
182
|
+
}
|
|
183
|
+
let t6;
|
|
184
|
+
if ($[12] !== reduceMotion || $[13] !== text) {
|
|
185
|
+
t6 = /* @__PURE__ */ _jsx(ArcTextSwap, {
|
|
186
|
+
text,
|
|
187
|
+
reduceMotion,
|
|
188
|
+
className: "min-w-0",
|
|
189
|
+
lineClassName: "truncate"
|
|
190
|
+
});
|
|
191
|
+
$[12] = reduceMotion;
|
|
192
|
+
$[13] = text;
|
|
193
|
+
$[14] = t6;
|
|
194
|
+
} else {
|
|
195
|
+
t6 = $[14];
|
|
196
|
+
}
|
|
197
|
+
let t7;
|
|
198
|
+
if ($[15] !== t5 || $[16] !== t6) {
|
|
199
|
+
t7 = /* @__PURE__ */ _jsxs("span", {
|
|
200
|
+
ref: inner,
|
|
201
|
+
className: "inline-flex max-w-full min-w-0 flex-none items-center gap-1.5 px-(--space-3) whitespace-nowrap",
|
|
202
|
+
children: [t5, t6]
|
|
203
|
+
});
|
|
204
|
+
$[15] = t5;
|
|
205
|
+
$[16] = t6;
|
|
206
|
+
$[17] = t7;
|
|
207
|
+
} else {
|
|
208
|
+
t7 = $[17];
|
|
209
|
+
}
|
|
210
|
+
let t8;
|
|
211
|
+
if ($[18] !== status || $[19] !== t3 || $[20] !== t7) {
|
|
212
|
+
t8 = /* @__PURE__ */ _jsx(motion.span, {
|
|
213
|
+
"data-slot": "usage-meter-status",
|
|
214
|
+
"data-status": status,
|
|
215
|
+
style: t3,
|
|
216
|
+
className: "inline-flex h-7 max-w-full min-w-0 shrink justify-end overflow-hidden rounded-(--radius-pill) bg-surface-muted text-xs leading-none font-medium text-text-secondary transition-[background-color,color] duration-(--duration-standard) ease-(--ease-standard) data-[status=near]:bg-[color-mix(in_oklab,var(--warning)_14%,var(--surface))] data-[status=near]:text-foreground data-[status=over]:bg-[color-mix(in_oklab,var(--danger)_12%,var(--surface))] data-[status=over]:text-foreground",
|
|
217
|
+
children: t7
|
|
218
|
+
});
|
|
219
|
+
$[18] = status;
|
|
220
|
+
$[19] = t3;
|
|
221
|
+
$[20] = t7;
|
|
222
|
+
$[21] = t8;
|
|
223
|
+
} else {
|
|
224
|
+
t8 = $[21];
|
|
225
|
+
}
|
|
226
|
+
return t8;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* The span of the bar: the limit, or everything used once that is more. Computed values read only base values, because
|
|
230
|
+
* a value derived from another derived value can read it stale when several base values jump in the same frame.
|
|
231
|
+
* @param amounts - Used amount of every segment.
|
|
232
|
+
* @param limit - The shown limit.
|
|
233
|
+
* @returns The amount the full bar stands for.
|
|
234
|
+
*/
|
|
235
|
+
function readSpan(amounts, limit) {
|
|
236
|
+
return Math.max(limit.get(), amounts.reduce((sum, amount) => sum + amount.get(), 0), MINIMUM_SPAN);
|
|
237
|
+
}
|
|
238
|
+
/** One category on the bar. It starts where the ones before it end, so growth anywhere pushes the rest along. */
|
|
239
|
+
function SegmentBar(t0) {
|
|
240
|
+
const $ = _c(20);
|
|
241
|
+
const { index, amounts, limit, width, highlight } = t0;
|
|
242
|
+
let t1;
|
|
243
|
+
if ($[0] !== amounts || $[1] !== index || $[2] !== limit || $[3] !== width) {
|
|
244
|
+
t1 = () => {
|
|
245
|
+
let start = 0;
|
|
246
|
+
for (let position = 0; position < index; position++) {
|
|
247
|
+
start = start + amounts[position].get();
|
|
248
|
+
}
|
|
249
|
+
return start / readSpan(amounts, limit) * width.get();
|
|
250
|
+
};
|
|
251
|
+
$[0] = amounts;
|
|
252
|
+
$[1] = index;
|
|
253
|
+
$[2] = limit;
|
|
254
|
+
$[3] = width;
|
|
255
|
+
$[4] = t1;
|
|
256
|
+
} else {
|
|
257
|
+
t1 = $[4];
|
|
258
|
+
}
|
|
259
|
+
const x = useTransform(t1);
|
|
260
|
+
let t2;
|
|
261
|
+
if ($[5] !== amounts || $[6] !== index || $[7] !== limit || $[8] !== width) {
|
|
262
|
+
t2 = () => {
|
|
263
|
+
const trackWidth = width.get();
|
|
264
|
+
const span = readSpan(amounts, limit);
|
|
265
|
+
let start_0 = 0;
|
|
266
|
+
for (let position_0 = 0; position_0 < index; position_0++) {
|
|
267
|
+
start_0 = start_0 + amounts[position_0].get();
|
|
268
|
+
}
|
|
269
|
+
const amount = amounts[index].get();
|
|
270
|
+
if (!trackWidth) {
|
|
271
|
+
return 0;
|
|
272
|
+
}
|
|
273
|
+
const size = amount / span * trackWidth;
|
|
274
|
+
const rest = trackWidth - start_0 / span * trackWidth - size;
|
|
275
|
+
return Math.max(0, size - Math.min(USAGE_METER_SEGMENT_GAP_PX, size, Math.max(0, rest))) / trackWidth;
|
|
276
|
+
};
|
|
277
|
+
$[5] = amounts;
|
|
278
|
+
$[6] = index;
|
|
279
|
+
$[7] = limit;
|
|
280
|
+
$[8] = width;
|
|
281
|
+
$[9] = t2;
|
|
282
|
+
} else {
|
|
283
|
+
t2 = $[9];
|
|
284
|
+
}
|
|
285
|
+
const scaleX = useTransform(t2);
|
|
286
|
+
let t3;
|
|
287
|
+
if ($[10] !== scaleX || $[11] !== x) {
|
|
288
|
+
t3 = {
|
|
289
|
+
x,
|
|
290
|
+
scaleX,
|
|
291
|
+
originX: 0
|
|
292
|
+
};
|
|
293
|
+
$[10] = scaleX;
|
|
294
|
+
$[11] = x;
|
|
295
|
+
$[12] = t3;
|
|
296
|
+
} else {
|
|
297
|
+
t3 = $[12];
|
|
298
|
+
}
|
|
299
|
+
let t4;
|
|
300
|
+
if ($[13] !== index) {
|
|
301
|
+
t4 = cn("absolute inset-0 transition-opacity duration-(--duration-fast) ease-(--ease-standard) data-[highlight=off]:opacity-28", segmentColorClassName(index));
|
|
302
|
+
$[13] = index;
|
|
303
|
+
$[14] = t4;
|
|
304
|
+
} else {
|
|
305
|
+
t4 = $[14];
|
|
306
|
+
}
|
|
307
|
+
let t5;
|
|
308
|
+
if ($[15] !== highlight || $[16] !== index || $[17] !== t3 || $[18] !== t4) {
|
|
309
|
+
t5 = /* @__PURE__ */ _jsx(motion.span, {
|
|
310
|
+
"data-slot": "usage-meter-segment",
|
|
311
|
+
"data-index": index,
|
|
312
|
+
"data-highlight": highlight,
|
|
313
|
+
style: t3,
|
|
314
|
+
className: t4
|
|
315
|
+
});
|
|
316
|
+
$[15] = highlight;
|
|
317
|
+
$[16] = index;
|
|
318
|
+
$[17] = t3;
|
|
319
|
+
$[18] = t4;
|
|
320
|
+
$[19] = t5;
|
|
321
|
+
} else {
|
|
322
|
+
t5 = $[19];
|
|
323
|
+
}
|
|
324
|
+
return t5;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Formats an amount with the meter's decimals, locale and unit.
|
|
328
|
+
* @param value - Amount to format.
|
|
329
|
+
* @param options - Locale, decimals, unit, and whether trailing zero decimals are dropped (for the limit).
|
|
330
|
+
* @returns The formatted amount, such as "8,4 GB".
|
|
331
|
+
*/
|
|
332
|
+
function formatAmount(value, { locale, decimals, unit, trimZeros = false }) {
|
|
333
|
+
const number = new Intl.NumberFormat(locale, {
|
|
334
|
+
minimumFractionDigits: trimZeros ? 0 : decimals,
|
|
335
|
+
maximumFractionDigits: decimals
|
|
336
|
+
}).format(value);
|
|
337
|
+
return unit ? `${number} ${unit}` : number;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* A segmented bar showing what uses a fixed allowance, with a rolling total, a status badge and an interactive legend.
|
|
341
|
+
* @param props - Label, segments, limit, unit, legend labels, copy overrides and native div attributes.
|
|
342
|
+
* @returns The usage meter.
|
|
343
|
+
*/
|
|
344
|
+
function UsageMeter(t0) {
|
|
345
|
+
const $ = _c(72);
|
|
346
|
+
let className;
|
|
347
|
+
let label;
|
|
348
|
+
let limit;
|
|
349
|
+
let messages;
|
|
350
|
+
let props;
|
|
351
|
+
let rawSegments;
|
|
352
|
+
let t1;
|
|
353
|
+
let t2;
|
|
354
|
+
let t3;
|
|
355
|
+
let t4;
|
|
356
|
+
let t5;
|
|
357
|
+
let t6;
|
|
358
|
+
if ($[0] !== t0) {
|
|
359
|
+
({label, segments: rawSegments, limit, unit: t1, decimals: t2, freeLabel: t3, overLabel: t4, warnAt: t5, messages, locale: t6, className, ...props} = t0);
|
|
360
|
+
$[0] = t0;
|
|
361
|
+
$[1] = className;
|
|
362
|
+
$[2] = label;
|
|
363
|
+
$[3] = limit;
|
|
364
|
+
$[4] = messages;
|
|
365
|
+
$[5] = props;
|
|
366
|
+
$[6] = rawSegments;
|
|
367
|
+
$[7] = t1;
|
|
368
|
+
$[8] = t2;
|
|
369
|
+
$[9] = t3;
|
|
370
|
+
$[10] = t4;
|
|
371
|
+
$[11] = t5;
|
|
372
|
+
$[12] = t6;
|
|
373
|
+
} else {
|
|
374
|
+
className = $[1];
|
|
375
|
+
label = $[2];
|
|
376
|
+
limit = $[3];
|
|
377
|
+
messages = $[4];
|
|
378
|
+
props = $[5];
|
|
379
|
+
rawSegments = $[6];
|
|
380
|
+
t1 = $[7];
|
|
381
|
+
t2 = $[8];
|
|
382
|
+
t3 = $[9];
|
|
383
|
+
t4 = $[10];
|
|
384
|
+
t5 = $[11];
|
|
385
|
+
t6 = $[12];
|
|
386
|
+
}
|
|
387
|
+
const unit = t1 === undefined ? "" : t1;
|
|
388
|
+
const decimals = t2 === undefined ? USAGE_METER_DEFAULT_DECIMALS : t2;
|
|
389
|
+
const freeLabel = t3 === undefined ? USAGE_METER_DEFAULT_FREE_LABEL : t3;
|
|
390
|
+
const overLabel = t4 === undefined ? USAGE_METER_DEFAULT_OVER_LABEL : t4;
|
|
391
|
+
const warnAt = t5 === undefined ? USAGE_METER_DEFAULT_WARN_AT : t5;
|
|
392
|
+
const locale = t6 === undefined ? USAGE_METER_DEFAULT_LOCALE : t6;
|
|
393
|
+
const copy = {
|
|
394
|
+
...USAGE_METER_DEFAULT_MESSAGES,
|
|
395
|
+
...messages
|
|
396
|
+
};
|
|
397
|
+
const reduceMotion = usePrefersReducedMotion();
|
|
398
|
+
const isHydrated = useIsHydrated();
|
|
399
|
+
const root = useRef(null);
|
|
400
|
+
const trackRef = useRef(null);
|
|
401
|
+
const legendRef = useRef(null);
|
|
402
|
+
const hasEnteredView = useHasEnteredView(root, USAGE_METER_REVEAL_AMOUNT);
|
|
403
|
+
const titleId = useId();
|
|
404
|
+
let t7;
|
|
405
|
+
if ($[13] !== titleId) {
|
|
406
|
+
let t8;
|
|
407
|
+
if ($[15] === Symbol.for("react.memo_cache_sentinel")) {
|
|
408
|
+
t8 = /[^a-zA-Z0-9_-]/g;
|
|
409
|
+
$[15] = t8;
|
|
410
|
+
} else {
|
|
411
|
+
t8 = $[15];
|
|
412
|
+
}
|
|
413
|
+
t7 = titleId.replace(t8, "");
|
|
414
|
+
$[13] = titleId;
|
|
415
|
+
$[14] = t7;
|
|
416
|
+
} else {
|
|
417
|
+
t7 = $[14];
|
|
418
|
+
}
|
|
419
|
+
const hatchId = `usage-meter-hatch${t7}`;
|
|
420
|
+
const isReady = isHydrated && (hasEnteredView || reduceMotion);
|
|
421
|
+
const decimalFactor = 10 ** decimals;
|
|
422
|
+
let t8;
|
|
423
|
+
if ($[16] !== decimalFactor) {
|
|
424
|
+
t8 = (value) => Math.round(value * decimalFactor) / decimalFactor;
|
|
425
|
+
$[16] = decimalFactor;
|
|
426
|
+
$[17] = t8;
|
|
427
|
+
} else {
|
|
428
|
+
t8 = $[17];
|
|
429
|
+
}
|
|
430
|
+
const round = t8;
|
|
431
|
+
let t9;
|
|
432
|
+
if ($[18] !== round) {
|
|
433
|
+
t9 = (segment) => ({
|
|
434
|
+
...segment,
|
|
435
|
+
value: round(segment.value)
|
|
436
|
+
});
|
|
437
|
+
$[18] = round;
|
|
438
|
+
$[19] = t9;
|
|
439
|
+
} else {
|
|
440
|
+
t9 = $[19];
|
|
441
|
+
}
|
|
442
|
+
const segments = rawSegments.map(t9);
|
|
443
|
+
const total = round(segments.reduce(_temp, 0));
|
|
444
|
+
const free = round(Math.max(0, limit - total));
|
|
445
|
+
const over = round(Math.max(0, total - limit));
|
|
446
|
+
const status = total > limit ? "over" : total >= limit * warnAt ? "near" : "ok";
|
|
447
|
+
let t10;
|
|
448
|
+
if ($[20] !== decimals || $[21] !== locale || $[22] !== unit) {
|
|
449
|
+
t10 = (value_0) => formatAmount(value_0, {
|
|
450
|
+
locale,
|
|
451
|
+
decimals,
|
|
452
|
+
unit
|
|
453
|
+
});
|
|
454
|
+
$[20] = decimals;
|
|
455
|
+
$[21] = locale;
|
|
456
|
+
$[22] = unit;
|
|
457
|
+
$[23] = t10;
|
|
458
|
+
} else {
|
|
459
|
+
t10 = $[23];
|
|
460
|
+
}
|
|
461
|
+
const format = t10;
|
|
462
|
+
const values = {
|
|
463
|
+
label,
|
|
464
|
+
unit,
|
|
465
|
+
limit: formatAmount(limit, {
|
|
466
|
+
locale,
|
|
467
|
+
decimals,
|
|
468
|
+
unit,
|
|
469
|
+
trimZeros: true
|
|
470
|
+
}),
|
|
471
|
+
total: format(total),
|
|
472
|
+
free: format(free),
|
|
473
|
+
over: format(over)
|
|
474
|
+
};
|
|
475
|
+
const [amountStore] = useState(_temp2);
|
|
476
|
+
let t11;
|
|
477
|
+
if ($[24] !== amountStore) {
|
|
478
|
+
t11 = (segment_1) => {
|
|
479
|
+
let amount = amountStore.get(segment_1.id);
|
|
480
|
+
if (!amount) {
|
|
481
|
+
amount = motionValue(0);
|
|
482
|
+
amountStore.set(segment_1.id, amount);
|
|
483
|
+
}
|
|
484
|
+
return amount;
|
|
485
|
+
};
|
|
486
|
+
$[24] = amountStore;
|
|
487
|
+
$[25] = t11;
|
|
488
|
+
} else {
|
|
489
|
+
t11 = $[25];
|
|
490
|
+
}
|
|
491
|
+
const amounts = segments.map(t11);
|
|
492
|
+
const shownLimit = useMotionValue(limit);
|
|
493
|
+
const trackWidth = useMotionValue(0);
|
|
494
|
+
const limitX = useTransform(() => Math.round(shownLimit.get() / readSpan(amounts, shownLimit) * trackWidth.get()));
|
|
495
|
+
const overClip = useTransform(() => `inset(0 0 0 ${Math.round(shownLimit.get() / readSpan(amounts, shownLimit) * trackWidth.get()) + USAGE_METER_SEGMENT_GAP_PX}px)`);
|
|
496
|
+
const markerOpacity = useMotionValue(0);
|
|
497
|
+
const amountIds = segments.map(_temp3).join("|");
|
|
498
|
+
useEffect(() => {
|
|
499
|
+
const watched = amountIds.split("|").flatMap((id) => amountStore.get(id) ?? []);
|
|
500
|
+
const isUsageOver = () => watched.reduce(_temp4, 0) > shownLimit.get();
|
|
501
|
+
let isOver = isUsageOver();
|
|
502
|
+
markerOpacity.jump(isOver ? 1 : 0);
|
|
503
|
+
let fading;
|
|
504
|
+
const check = () => {
|
|
505
|
+
const next = isUsageOver();
|
|
506
|
+
if (next === isOver) {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
isOver = next;
|
|
510
|
+
fading?.stop();
|
|
511
|
+
if (reduceMotion) {
|
|
512
|
+
markerOpacity.jump(next ? 1 : 0);
|
|
513
|
+
} else {
|
|
514
|
+
fading = animate(markerOpacity, next ? 1 : 0, {
|
|
515
|
+
duration: ARC_DURATION.fast,
|
|
516
|
+
ease: [...ARC_EASE.standard]
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
const stops = [...watched.map((amount_1) => amount_1.on("change", check)), shownLimit.on("change", check)];
|
|
521
|
+
return () => {
|
|
522
|
+
stops.forEach(_temp5);
|
|
523
|
+
fading?.stop();
|
|
524
|
+
};
|
|
525
|
+
}, [
|
|
526
|
+
amountIds,
|
|
527
|
+
amountStore,
|
|
528
|
+
markerOpacity,
|
|
529
|
+
reduceMotion,
|
|
530
|
+
shownLimit
|
|
531
|
+
]);
|
|
532
|
+
let t12;
|
|
533
|
+
let t13;
|
|
534
|
+
if ($[26] !== trackWidth) {
|
|
535
|
+
t12 = () => {
|
|
536
|
+
const node = trackRef.current;
|
|
537
|
+
if (!node) {
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
trackWidth.set(node.clientWidth);
|
|
541
|
+
if (typeof ResizeObserver === "undefined") {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
const observer = new ResizeObserver(() => trackWidth.set(node.clientWidth));
|
|
545
|
+
observer.observe(node);
|
|
546
|
+
return () => observer.disconnect();
|
|
547
|
+
};
|
|
548
|
+
t13 = [trackWidth];
|
|
549
|
+
$[26] = trackWidth;
|
|
550
|
+
$[27] = t12;
|
|
551
|
+
$[28] = t13;
|
|
552
|
+
} else {
|
|
553
|
+
t12 = $[27];
|
|
554
|
+
t13 = $[28];
|
|
555
|
+
}
|
|
556
|
+
useLayoutEffect(t12, t13);
|
|
557
|
+
const segmentTargets = JSON.stringify(segments.map(_temp6));
|
|
558
|
+
const hasRevealed = useRef(false);
|
|
559
|
+
useEffect(() => {
|
|
560
|
+
if (!isReady) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
const isFirstReveal = !hasRevealed.current;
|
|
564
|
+
hasRevealed.current = true;
|
|
565
|
+
const targets = JSON.parse(segmentTargets);
|
|
566
|
+
const stops_0 = targets.map((t14, index) => {
|
|
567
|
+
const [id_0, value_1] = t14;
|
|
568
|
+
const amount_2 = amountStore.get(id_0);
|
|
569
|
+
if (!amount_2 || amount_2.get() === value_1) {
|
|
570
|
+
return null;
|
|
571
|
+
}
|
|
572
|
+
if (reduceMotion) {
|
|
573
|
+
amount_2.jump(value_1);
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
const transition = isFirstReveal ? {
|
|
577
|
+
...REVEAL_SPRING,
|
|
578
|
+
delay: index * USAGE_METER_REVEAL_STAGGER_S
|
|
579
|
+
} : SETTLE_SPRING;
|
|
580
|
+
return startNextFrame(() => animate(amount_2, value_1, transition));
|
|
581
|
+
});
|
|
582
|
+
return () => stops_0.forEach(_temp7);
|
|
583
|
+
}, [
|
|
584
|
+
segmentTargets,
|
|
585
|
+
isReady,
|
|
586
|
+
reduceMotion,
|
|
587
|
+
amountStore
|
|
588
|
+
]);
|
|
589
|
+
let t15;
|
|
590
|
+
let t16;
|
|
591
|
+
if ($[29] !== limit || $[30] !== reduceMotion || $[31] !== shownLimit) {
|
|
592
|
+
t15 = () => {
|
|
593
|
+
if (shownLimit.get() === limit) {
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
if (reduceMotion) {
|
|
597
|
+
shownLimit.jump(limit);
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
return startNextFrame(() => animate(shownLimit, limit, SETTLE_SPRING));
|
|
601
|
+
};
|
|
602
|
+
t16 = [
|
|
603
|
+
limit,
|
|
604
|
+
reduceMotion,
|
|
605
|
+
shownLimit
|
|
606
|
+
];
|
|
607
|
+
$[29] = limit;
|
|
608
|
+
$[30] = reduceMotion;
|
|
609
|
+
$[31] = shownLimit;
|
|
610
|
+
$[32] = t15;
|
|
611
|
+
$[33] = t16;
|
|
612
|
+
} else {
|
|
613
|
+
t15 = $[32];
|
|
614
|
+
t16 = $[33];
|
|
615
|
+
}
|
|
616
|
+
useEffect(t15, t16);
|
|
617
|
+
const [hovered, setHovered] = useState(null);
|
|
618
|
+
const [focused, setFocused] = useState(null);
|
|
619
|
+
const [pinned, setPinned] = useState(null);
|
|
620
|
+
const [rovingIndex, setRovingIndex] = useState(0);
|
|
621
|
+
const items = [...segments.map(_temp8), {
|
|
622
|
+
id: USAGE_METER_FREE_ID,
|
|
623
|
+
label: status === "over" ? overLabel : freeLabel,
|
|
624
|
+
value: status === "over" ? over : free
|
|
625
|
+
}];
|
|
626
|
+
const tabStopIndex = Math.min(rovingIndex, items.length - 1);
|
|
627
|
+
const active = hovered ?? focused ?? pinned;
|
|
628
|
+
const activeItem = items.find((item) => item.id === active) ?? null;
|
|
629
|
+
let t17;
|
|
630
|
+
if ($[34] !== active) {
|
|
631
|
+
t17 = (id_1) => active ? active === id_1 ? "on" : "off" : undefined;
|
|
632
|
+
$[34] = active;
|
|
633
|
+
$[35] = t17;
|
|
634
|
+
} else {
|
|
635
|
+
t17 = $[35];
|
|
636
|
+
}
|
|
637
|
+
const highlightOf = t17;
|
|
638
|
+
const idAt = (clientX) => {
|
|
639
|
+
const rect = trackRef.current?.getBoundingClientRect();
|
|
640
|
+
if (!rect?.width) {
|
|
641
|
+
return null;
|
|
642
|
+
}
|
|
643
|
+
const at = (clientX - rect.left) / rect.width * Math.max(limit, total);
|
|
644
|
+
if (at > limit) {
|
|
645
|
+
return USAGE_METER_FREE_ID;
|
|
646
|
+
}
|
|
647
|
+
let end = 0;
|
|
648
|
+
for (const segment_5 of segments) {
|
|
649
|
+
end = end + segment_5.value;
|
|
650
|
+
if (at <= end) {
|
|
651
|
+
return segmentKey(segment_5.id);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return USAGE_METER_FREE_ID;
|
|
655
|
+
};
|
|
656
|
+
const onTrackMove = (event) => {
|
|
657
|
+
if (event.pointerType === "mouse") {
|
|
658
|
+
setHovered(idAt(event.clientX));
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
const onTrackTap = (event_0) => {
|
|
662
|
+
if (event_0.pointerType === "mouse") {
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
const id_2 = idAt(event_0.clientX);
|
|
666
|
+
setPinned((current) => current === id_2 ? null : id_2);
|
|
667
|
+
};
|
|
668
|
+
const onLegendKeyDown = (event_1) => {
|
|
669
|
+
if (event_1.key === "Escape") {
|
|
670
|
+
if (pinned || focused) {
|
|
671
|
+
event_1.preventDefault();
|
|
672
|
+
setPinned(null);
|
|
673
|
+
}
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
const targets_0 = {
|
|
677
|
+
ArrowRight: tabStopIndex + 1,
|
|
678
|
+
ArrowDown: tabStopIndex + 1,
|
|
679
|
+
ArrowLeft: tabStopIndex - 1,
|
|
680
|
+
ArrowUp: tabStopIndex - 1,
|
|
681
|
+
Home: 0,
|
|
682
|
+
End: items.length - 1
|
|
683
|
+
};
|
|
684
|
+
const next_0 = targets_0[event_1.key];
|
|
685
|
+
if (next_0 === undefined) {
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
event_1.preventDefault();
|
|
689
|
+
const index_0 = (next_0 + items.length) % items.length;
|
|
690
|
+
setRovingIndex(index_0);
|
|
691
|
+
legendRef.current?.querySelectorAll("button")[index_0]?.focus();
|
|
692
|
+
};
|
|
693
|
+
const headline = isReady ? activeItem ? activeItem.value : total : 0;
|
|
694
|
+
const share = activeItem && limit > 0 ? Math.round(activeItem.value / limit * PERCENT) : 0;
|
|
695
|
+
const caption = !activeItem ? copy.usedCaption(values) : activeItem.id === USAGE_METER_FREE_ID ? status === "over" ? copy.overCaption(values) : copy.freeCaption(values) : copy.segmentCaption({
|
|
696
|
+
...values,
|
|
697
|
+
segment: activeItem.label,
|
|
698
|
+
share
|
|
699
|
+
});
|
|
700
|
+
const badge = status === "over" ? copy.overBadge(values) : status === "near" ? copy.nearBadge(values) : copy.freeBadge(values);
|
|
701
|
+
let t18;
|
|
702
|
+
if ($[36] !== format) {
|
|
703
|
+
t18 = (segment_6) => `${segment_6.label} ${format(segment_6.value)}`;
|
|
704
|
+
$[36] = format;
|
|
705
|
+
$[37] = t18;
|
|
706
|
+
} else {
|
|
707
|
+
t18 = $[37];
|
|
708
|
+
}
|
|
709
|
+
const barSummary = copy.barSummary({
|
|
710
|
+
...values,
|
|
711
|
+
status,
|
|
712
|
+
segments: segments.map(t18).join(", ")
|
|
713
|
+
});
|
|
714
|
+
const notice = status === "over" ? `over:${over}` : status;
|
|
715
|
+
let t19;
|
|
716
|
+
if ($[38] !== notice) {
|
|
717
|
+
t19 = {
|
|
718
|
+
notice,
|
|
719
|
+
message: ""
|
|
720
|
+
};
|
|
721
|
+
$[38] = notice;
|
|
722
|
+
$[39] = t19;
|
|
723
|
+
} else {
|
|
724
|
+
t19 = $[39];
|
|
725
|
+
}
|
|
726
|
+
const [announced, setAnnounced] = useState(t19);
|
|
727
|
+
if (announced.notice !== notice) {
|
|
728
|
+
const message = status === "over" ? copy.overAnnouncement(values) : status === "near" ? copy.nearAnnouncement(values) : copy.okAnnouncement(values);
|
|
729
|
+
setAnnounced({
|
|
730
|
+
notice,
|
|
731
|
+
message
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
let t20;
|
|
735
|
+
if ($[40] !== className) {
|
|
736
|
+
t20 = cn("grid min-w-0 gap-(--space-4) text-foreground", className);
|
|
737
|
+
$[40] = className;
|
|
738
|
+
$[41] = t20;
|
|
739
|
+
} else {
|
|
740
|
+
t20 = $[41];
|
|
741
|
+
}
|
|
742
|
+
let t21;
|
|
743
|
+
if ($[42] !== label || $[43] !== titleId) {
|
|
744
|
+
t21 = /* @__PURE__ */ _jsx("span", {
|
|
745
|
+
id: titleId,
|
|
746
|
+
className: "min-w-0 text-base leading-(--leading-body) font-medium tracking-(--tracking-body) text-balance text-foreground",
|
|
747
|
+
children: label
|
|
748
|
+
});
|
|
749
|
+
$[42] = label;
|
|
750
|
+
$[43] = titleId;
|
|
751
|
+
$[44] = t21;
|
|
752
|
+
} else {
|
|
753
|
+
t21 = $[44];
|
|
754
|
+
}
|
|
755
|
+
let t22;
|
|
756
|
+
if ($[45] === Symbol.for("react.memo_cache_sentinel")) {
|
|
757
|
+
t22 = () => setHovered(null);
|
|
758
|
+
$[45] = t22;
|
|
759
|
+
} else {
|
|
760
|
+
t22 = $[45];
|
|
761
|
+
}
|
|
762
|
+
let t23;
|
|
763
|
+
if ($[46] === Symbol.for("react.memo_cache_sentinel")) {
|
|
764
|
+
t23 = cn("relative isolate h-3.5 overflow-hidden rounded-(--radius-pill) [-webkit-tap-highlight-color:transparent]", TRACK_COLOR_CLASS_NAME);
|
|
765
|
+
$[46] = t23;
|
|
766
|
+
} else {
|
|
767
|
+
t23 = $[46];
|
|
768
|
+
}
|
|
769
|
+
const t24 = segments.map((segment_7, index_1) => /* @__PURE__ */ _jsx(SegmentBar, {
|
|
770
|
+
index: index_1,
|
|
771
|
+
amounts,
|
|
772
|
+
limit: shownLimit,
|
|
773
|
+
width: trackWidth,
|
|
774
|
+
highlight: highlightOf(segmentKey(segment_7.id))
|
|
775
|
+
}, segment_7.id));
|
|
776
|
+
let t25;
|
|
777
|
+
if ($[47] !== highlightOf) {
|
|
778
|
+
t25 = highlightOf(USAGE_METER_FREE_ID);
|
|
779
|
+
$[47] = highlightOf;
|
|
780
|
+
$[48] = t25;
|
|
781
|
+
} else {
|
|
782
|
+
t25 = $[48];
|
|
783
|
+
}
|
|
784
|
+
let t26;
|
|
785
|
+
if ($[49] !== markerOpacity || $[50] !== overClip) {
|
|
786
|
+
t26 = {
|
|
787
|
+
clipPath: overClip,
|
|
788
|
+
opacity: markerOpacity
|
|
789
|
+
};
|
|
790
|
+
$[49] = markerOpacity;
|
|
791
|
+
$[50] = overClip;
|
|
792
|
+
$[51] = t26;
|
|
793
|
+
} else {
|
|
794
|
+
t26 = $[51];
|
|
795
|
+
}
|
|
796
|
+
let t27;
|
|
797
|
+
if ($[52] === Symbol.for("react.memo_cache_sentinel")) {
|
|
798
|
+
t27 = /* @__PURE__ */ _jsx("rect", {
|
|
799
|
+
width: 2.5,
|
|
800
|
+
height: 6,
|
|
801
|
+
className: "fill-surface"
|
|
802
|
+
});
|
|
803
|
+
$[52] = t27;
|
|
804
|
+
} else {
|
|
805
|
+
t27 = $[52];
|
|
806
|
+
}
|
|
807
|
+
let t28;
|
|
808
|
+
if ($[53] !== hatchId) {
|
|
809
|
+
t28 = /* @__PURE__ */ _jsx("defs", { children: /* @__PURE__ */ _jsx("pattern", {
|
|
810
|
+
id: hatchId,
|
|
811
|
+
width: 6,
|
|
812
|
+
height: 6,
|
|
813
|
+
patternUnits: "userSpaceOnUse",
|
|
814
|
+
patternTransform: "rotate(45)",
|
|
815
|
+
children: t27
|
|
816
|
+
}) });
|
|
817
|
+
$[53] = hatchId;
|
|
818
|
+
$[54] = t28;
|
|
819
|
+
} else {
|
|
820
|
+
t28 = $[54];
|
|
821
|
+
}
|
|
822
|
+
let t29;
|
|
823
|
+
if ($[55] === Symbol.for("react.memo_cache_sentinel")) {
|
|
824
|
+
t29 = /* @__PURE__ */ _jsx("rect", {
|
|
825
|
+
width: "100%",
|
|
826
|
+
height: "100%",
|
|
827
|
+
className: "fill-danger opacity-0 transition-opacity duration-(--duration-fast) ease-(--ease-standard) group-data-[highlight=on]/overflow:opacity-100"
|
|
828
|
+
});
|
|
829
|
+
$[55] = t29;
|
|
830
|
+
} else {
|
|
831
|
+
t29 = $[55];
|
|
832
|
+
}
|
|
833
|
+
const t30 = `url(#${hatchId})`;
|
|
834
|
+
let t31;
|
|
835
|
+
if ($[56] !== t30) {
|
|
836
|
+
t31 = /* @__PURE__ */ _jsx("rect", {
|
|
837
|
+
width: "100%",
|
|
838
|
+
height: "100%",
|
|
839
|
+
fill: t30
|
|
840
|
+
});
|
|
841
|
+
$[56] = t30;
|
|
842
|
+
$[57] = t31;
|
|
843
|
+
} else {
|
|
844
|
+
t31 = $[57];
|
|
845
|
+
}
|
|
846
|
+
let t32;
|
|
847
|
+
if ($[58] !== t25 || $[59] !== t26 || $[60] !== t28 || $[61] !== t31) {
|
|
848
|
+
t32 = /* @__PURE__ */ _jsxs(motion.svg, {
|
|
849
|
+
"data-slot": "usage-meter-overflow",
|
|
850
|
+
"data-highlight": t25,
|
|
851
|
+
style: t26,
|
|
852
|
+
"aria-hidden": "true",
|
|
853
|
+
focusable: "false",
|
|
854
|
+
className: "group/overflow pointer-events-none absolute inset-0 size-full",
|
|
855
|
+
children: [
|
|
856
|
+
t28,
|
|
857
|
+
t29,
|
|
858
|
+
t31
|
|
859
|
+
]
|
|
860
|
+
});
|
|
861
|
+
$[58] = t25;
|
|
862
|
+
$[59] = t26;
|
|
863
|
+
$[60] = t28;
|
|
864
|
+
$[61] = t31;
|
|
865
|
+
$[62] = t32;
|
|
866
|
+
} else {
|
|
867
|
+
t32 = $[62];
|
|
868
|
+
}
|
|
869
|
+
let t33;
|
|
870
|
+
if ($[63] !== limitX || $[64] !== markerOpacity) {
|
|
871
|
+
t33 = /* @__PURE__ */ _jsx(motion.span, {
|
|
872
|
+
"data-slot": "usage-meter-limit",
|
|
873
|
+
"aria-hidden": "true",
|
|
874
|
+
style: {
|
|
875
|
+
x: limitX,
|
|
876
|
+
opacity: markerOpacity
|
|
877
|
+
},
|
|
878
|
+
className: "pointer-events-none absolute inset-y-0 -left-px w-0.5 rounded-[1px] bg-foreground"
|
|
879
|
+
});
|
|
880
|
+
$[63] = limitX;
|
|
881
|
+
$[64] = markerOpacity;
|
|
882
|
+
$[65] = t33;
|
|
883
|
+
} else {
|
|
884
|
+
t33 = $[65];
|
|
885
|
+
}
|
|
886
|
+
const t34 = "usage-meter-legend";
|
|
887
|
+
const t35 = "group";
|
|
888
|
+
const t36 = copy.legendLabel(values);
|
|
889
|
+
const t37 = "-mx-(--space-2) grid grid-cols-[repeat(auto-fit,minmax(108px,1fr))] gap-0.5";
|
|
890
|
+
const t38 = items.map((item_0, index_2) => {
|
|
891
|
+
const isOverage = item_0.id === USAGE_METER_FREE_ID && status === "over";
|
|
892
|
+
const isFree = item_0.id === USAGE_METER_FREE_ID;
|
|
893
|
+
return /* @__PURE__ */ _jsxs("button", {
|
|
894
|
+
type: "button",
|
|
895
|
+
"data-slot": "usage-meter-legend-item",
|
|
896
|
+
"data-highlight": highlightOf(item_0.id),
|
|
897
|
+
"aria-pressed": pinned === item_0.id,
|
|
898
|
+
"aria-label": `${item_0.label}, ${format(item_0.value)}`,
|
|
899
|
+
tabIndex: index_2 === tabStopIndex ? 0 : -1,
|
|
900
|
+
onClick: () => {
|
|
901
|
+
setRovingIndex(index_2);
|
|
902
|
+
setPinned((current_0) => current_0 === item_0.id ? null : item_0.id);
|
|
903
|
+
},
|
|
904
|
+
onFocus: () => {
|
|
905
|
+
setRovingIndex(index_2);
|
|
906
|
+
setFocused(item_0.id);
|
|
907
|
+
},
|
|
908
|
+
onBlur: () => setFocused(null),
|
|
909
|
+
onPointerEnter: (event_2) => {
|
|
910
|
+
if (event_2.pointerType === "mouse") {
|
|
911
|
+
setHovered(item_0.id);
|
|
912
|
+
}
|
|
913
|
+
},
|
|
914
|
+
onPointerLeave: (event_3) => {
|
|
915
|
+
if (event_3.pointerType === "mouse") {
|
|
916
|
+
setHovered(null);
|
|
917
|
+
}
|
|
918
|
+
},
|
|
919
|
+
className: "grid min-w-0 cursor-pointer justify-items-start gap-0.5 rounded-[calc(var(--radius-control)-6px)] border-0 bg-transparent p-(--space-2) text-left [font:inherit] text-inherit [-webkit-tap-highlight-color:transparent] transition-[background-color,opacity] duration-(--duration-fast) ease-(--ease-standard) hover-fine:bg-surface-muted aria-pressed:bg-surface-muted data-[highlight=off]:opacity-45",
|
|
920
|
+
children: [/* @__PURE__ */ _jsxs("span", {
|
|
921
|
+
className: "flex max-w-full min-w-0 items-center gap-(--space-2) text-sm leading-(--leading-body) text-text-secondary",
|
|
922
|
+
children: [/* @__PURE__ */ _jsx("span", {
|
|
923
|
+
"aria-hidden": "true",
|
|
924
|
+
className: "grid size-3 flex-none place-items-center",
|
|
925
|
+
children: /* @__PURE__ */ _jsx(AnimatePresence, {
|
|
926
|
+
mode: "popLayout",
|
|
927
|
+
initial: false,
|
|
928
|
+
children: isOverage ? /* @__PURE__ */ _jsx(motion.span, {
|
|
929
|
+
className: "col-start-1 row-start-1 grid place-items-center text-danger",
|
|
930
|
+
variants: reduceMotion ? fadeVariants : popVariants,
|
|
931
|
+
initial: "hidden",
|
|
932
|
+
animate: "shown",
|
|
933
|
+
exit: "gone",
|
|
934
|
+
children: /* @__PURE__ */ _jsx(TriangleAlert, {
|
|
935
|
+
size: LEGEND_ICON_SIZE_PX,
|
|
936
|
+
strokeWidth: 2
|
|
937
|
+
})
|
|
938
|
+
}, "alert") : /* @__PURE__ */ _jsx(motion.span, {
|
|
939
|
+
className: cn("col-start-1 row-start-1 size-2.5 rounded-[3px]", isFree ? cn(TRACK_COLOR_CLASS_NAME, "shadow-[inset_0_0_0_1px_var(--border-strong)]") : segmentColorClassName(index_2)),
|
|
940
|
+
variants: reduceMotion ? fadeVariants : popVariants,
|
|
941
|
+
initial: "hidden",
|
|
942
|
+
animate: "shown",
|
|
943
|
+
exit: "gone"
|
|
944
|
+
}, "swatch")
|
|
945
|
+
})
|
|
946
|
+
}), /* @__PURE__ */ _jsx("span", {
|
|
947
|
+
className: "min-w-0 flex-1",
|
|
948
|
+
children: /* @__PURE__ */ _jsx(ArcTextSwap, {
|
|
949
|
+
text: item_0.label,
|
|
950
|
+
reduceMotion,
|
|
951
|
+
lineClassName: "truncate"
|
|
952
|
+
})
|
|
953
|
+
})]
|
|
954
|
+
}), /* @__PURE__ */ _jsxs("span", {
|
|
955
|
+
className: "flex items-baseline gap-1 pl-5 text-base leading-(--leading-body) font-medium text-foreground",
|
|
956
|
+
children: [/* @__PURE__ */ _jsx(ArcOdometer, {
|
|
957
|
+
value: item_0.value,
|
|
958
|
+
decimals,
|
|
959
|
+
locale,
|
|
960
|
+
reduceMotion
|
|
961
|
+
}), unit ? /* @__PURE__ */ _jsx("span", {
|
|
962
|
+
className: "text-sm font-normal text-text-secondary",
|
|
963
|
+
children: unit
|
|
964
|
+
}) : null]
|
|
965
|
+
})]
|
|
966
|
+
}, item_0.id);
|
|
967
|
+
});
|
|
968
|
+
let t39;
|
|
969
|
+
if ($[66] !== onLegendKeyDown || $[67] !== t36 || $[68] !== t38) {
|
|
970
|
+
t39 = /* @__PURE__ */ _jsx("div", {
|
|
971
|
+
ref: legendRef,
|
|
972
|
+
"data-slot": t34,
|
|
973
|
+
role: t35,
|
|
974
|
+
"aria-label": t36,
|
|
975
|
+
onKeyDown: onLegendKeyDown,
|
|
976
|
+
className: t37,
|
|
977
|
+
children: t38
|
|
978
|
+
});
|
|
979
|
+
$[66] = onLegendKeyDown;
|
|
980
|
+
$[67] = t36;
|
|
981
|
+
$[68] = t38;
|
|
982
|
+
$[69] = t39;
|
|
983
|
+
} else {
|
|
984
|
+
t39 = $[69];
|
|
985
|
+
}
|
|
986
|
+
let t40;
|
|
987
|
+
if ($[70] !== announced.message) {
|
|
988
|
+
t40 = /* @__PURE__ */ _jsx("p", {
|
|
989
|
+
className: "sr-only",
|
|
990
|
+
"aria-live": "polite",
|
|
991
|
+
"aria-atomic": "true",
|
|
992
|
+
children: announced.message
|
|
993
|
+
});
|
|
994
|
+
$[70] = announced.message;
|
|
995
|
+
$[71] = t40;
|
|
996
|
+
} else {
|
|
997
|
+
t40 = $[71];
|
|
998
|
+
}
|
|
999
|
+
return /* @__PURE__ */ _jsxs("div", {
|
|
1000
|
+
ref: root,
|
|
1001
|
+
"data-slot": "usage-meter",
|
|
1002
|
+
"data-status": status,
|
|
1003
|
+
role: "group",
|
|
1004
|
+
"aria-labelledby": titleId,
|
|
1005
|
+
className: t20,
|
|
1006
|
+
...props,
|
|
1007
|
+
children: [
|
|
1008
|
+
/* @__PURE__ */ _jsxs("div", {
|
|
1009
|
+
className: "flex min-h-7 min-w-0 items-center justify-between gap-(--space-3)",
|
|
1010
|
+
children: [t21, /* @__PURE__ */ _jsx(StatusBadge, {
|
|
1011
|
+
status,
|
|
1012
|
+
text: badge,
|
|
1013
|
+
reduceMotion
|
|
1014
|
+
})]
|
|
1015
|
+
}),
|
|
1016
|
+
/* @__PURE__ */ _jsxs("p", {
|
|
1017
|
+
className: "m-0 flex min-w-0 items-baseline gap-(--space-2)",
|
|
1018
|
+
children: [
|
|
1019
|
+
/* @__PURE__ */ _jsx("span", {
|
|
1020
|
+
className: "sr-only",
|
|
1021
|
+
children: copy.usedSummary(values)
|
|
1022
|
+
}),
|
|
1023
|
+
/* @__PURE__ */ _jsx("span", {
|
|
1024
|
+
"aria-hidden": "true",
|
|
1025
|
+
className: "flex-none font-display text-3xl leading-(--leading-display) font-medium tracking-(--tracking-display)",
|
|
1026
|
+
children: /* @__PURE__ */ _jsx(ArcOdometer, {
|
|
1027
|
+
value: headline,
|
|
1028
|
+
decimals,
|
|
1029
|
+
locale,
|
|
1030
|
+
reduceMotion
|
|
1031
|
+
})
|
|
1032
|
+
}),
|
|
1033
|
+
/* @__PURE__ */ _jsx("span", {
|
|
1034
|
+
"data-slot": "usage-meter-caption",
|
|
1035
|
+
"aria-hidden": "true",
|
|
1036
|
+
className: "min-w-0 flex-1 text-sm text-text-secondary",
|
|
1037
|
+
children: /* @__PURE__ */ _jsx(ArcTextSwap, {
|
|
1038
|
+
text: caption,
|
|
1039
|
+
reduceMotion,
|
|
1040
|
+
lineClassName: "truncate"
|
|
1041
|
+
})
|
|
1042
|
+
})
|
|
1043
|
+
]
|
|
1044
|
+
}),
|
|
1045
|
+
/* @__PURE__ */ _jsxs("div", {
|
|
1046
|
+
className: "relative py-[5px]",
|
|
1047
|
+
children: [/* @__PURE__ */ _jsxs("div", {
|
|
1048
|
+
ref: trackRef,
|
|
1049
|
+
"data-slot": "usage-meter-track",
|
|
1050
|
+
role: "img",
|
|
1051
|
+
"aria-label": barSummary,
|
|
1052
|
+
"data-active": active ?? undefined,
|
|
1053
|
+
onPointerMove: onTrackMove,
|
|
1054
|
+
onPointerLeave: t22,
|
|
1055
|
+
onPointerUp: onTrackTap,
|
|
1056
|
+
className: t23,
|
|
1057
|
+
children: [t24, t32]
|
|
1058
|
+
}), t33]
|
|
1059
|
+
}),
|
|
1060
|
+
t39,
|
|
1061
|
+
t40
|
|
1062
|
+
]
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
function _temp8(segment_4) {
|
|
1066
|
+
return {
|
|
1067
|
+
id: segmentKey(segment_4.id),
|
|
1068
|
+
label: segment_4.label,
|
|
1069
|
+
value: segment_4.value
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
function _temp7(stop_0) {
|
|
1073
|
+
return stop_0?.();
|
|
1074
|
+
}
|
|
1075
|
+
function _temp6(segment_3) {
|
|
1076
|
+
return [segment_3.id, segment_3.value];
|
|
1077
|
+
}
|
|
1078
|
+
function _temp5(stop) {
|
|
1079
|
+
return stop();
|
|
1080
|
+
}
|
|
1081
|
+
function _temp4(sum_0, amount_0) {
|
|
1082
|
+
return sum_0 + amount_0.get();
|
|
1083
|
+
}
|
|
1084
|
+
function _temp3(segment_2) {
|
|
1085
|
+
return segment_2.id;
|
|
1086
|
+
}
|
|
1087
|
+
function _temp2() {
|
|
1088
|
+
return new Map();
|
|
1089
|
+
}
|
|
1090
|
+
function _temp(sum, segment_0) {
|
|
1091
|
+
return sum + segment_0.value;
|
|
1092
|
+
}
|
|
1093
|
+
export { UsageMeter };
|