virtual-ui-lib 1.0.72 → 1.0.74

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.mjs CHANGED
@@ -3059,6 +3059,469 @@ var RatingStars = ({
3059
3059
  ));
3060
3060
  })), reviewCount > 0 && /* @__PURE__ */ React17.createElement("span", { style: { fontSize: "11px", color: "rgba(255,255,255,0.3)" } }, reviewCount.toLocaleString(), " reviews"))), !readOnly && rating === 0 && /* @__PURE__ */ React17.createElement("p", { style: { fontSize: "11px", color: "rgba(255,255,255,0.2)", margin: 0 } }, allowHalf ? "Hover to rate \u2022 Half stars supported" : "Click to rate"));
3061
3061
  };
3062
+
3063
+ // src/components/StatCard/StatCard.jsx
3064
+ import React18, { useEffect as useEffect7, useRef as useRef3, useState as useState16 } from "react";
3065
+ var StatCard = ({
3066
+ title = "Active Users",
3067
+ value = "128K",
3068
+ numericValue = 128e3,
3069
+ change = "+12.4%",
3070
+ isPositive = true,
3071
+ icon = "\u{1F465}",
3072
+ bg = "#ffffff",
3073
+ accent = "#3b82f6",
3074
+ radius = "16px",
3075
+ showBadge = true,
3076
+ showIcon = true,
3077
+ barPercent = 68
3078
+ }) => {
3079
+ const [count, setCount] = useState16(0);
3080
+ const [barWidth, setBarWidth] = useState16(0);
3081
+ const [visible, setVisible] = useState16(false);
3082
+ const [entered, setEntered] = useState16(false);
3083
+ const ref = useRef3(null);
3084
+ useEffect7(() => {
3085
+ const observer = new IntersectionObserver(
3086
+ ([entry]) => {
3087
+ if (entry.isIntersecting) {
3088
+ setVisible(true);
3089
+ observer.disconnect();
3090
+ }
3091
+ },
3092
+ { threshold: 0.3 }
3093
+ );
3094
+ if (ref.current) observer.observe(ref.current);
3095
+ return () => observer.disconnect();
3096
+ }, []);
3097
+ useEffect7(() => {
3098
+ if (!visible) return;
3099
+ setEntered(true);
3100
+ const duration = 1400;
3101
+ const start = performance.now();
3102
+ const step = (now) => {
3103
+ const p = Math.min((now - start) / duration, 1);
3104
+ const eased = 1 - Math.pow(1 - p, 3);
3105
+ setCount(Math.floor(eased * numericValue));
3106
+ if (p < 1) requestAnimationFrame(step);
3107
+ };
3108
+ requestAnimationFrame(step);
3109
+ }, [visible, numericValue]);
3110
+ useEffect7(() => {
3111
+ if (!visible) return;
3112
+ const t = setTimeout(() => setBarWidth(barPercent), 200);
3113
+ return () => clearTimeout(t);
3114
+ }, [visible, barPercent]);
3115
+ const formatCount = (n) => {
3116
+ if (numericValue >= 1e6) return (n / 1e6).toFixed(1) + "M";
3117
+ if (numericValue >= 1e3) return (n / 1e3).toFixed(1) + "K";
3118
+ return n.toLocaleString();
3119
+ };
3120
+ const alpha = (hex, op) => {
3121
+ const r = parseInt(hex.slice(1, 3), 16);
3122
+ const g = parseInt(hex.slice(3, 5), 16);
3123
+ const b = parseInt(hex.slice(5, 7), 16);
3124
+ return `rgba(${r},${g},${b},${op})`;
3125
+ };
3126
+ const uid = accent.replace("#", "sc");
3127
+ return /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement("style", null, `
3128
+ @import url('https://fonts.googleapis.com/css2?family=Sora:wght@400;600;700;800&display=swap');
3129
+
3130
+ .sc-${uid} {
3131
+ font-family: 'Sora', sans-serif;
3132
+ background: ${bg};
3133
+ border-radius: ${radius};
3134
+ padding: 24px;
3135
+ display: inline-flex;
3136
+ flex-direction: column;
3137
+ gap: 14px;
3138
+ border: 1px solid rgba(0,0,0,0.07);
3139
+ box-shadow: 0 2px 16px rgba(0,0,0,0.06);
3140
+ min-width: 200px;
3141
+ position: relative;
3142
+ overflow: hidden;
3143
+ opacity: 0;
3144
+ transform: translateY(24px);
3145
+ transition: opacity 0.5s ease, transform 0.5s ease, box-shadow 0.25s ease;
3146
+ }
3147
+
3148
+ .sc-${uid}.entered {
3149
+ opacity: 1;
3150
+ transform: translateY(0);
3151
+ }
3152
+
3153
+ .sc-${uid}:hover {
3154
+ transform: translateY(-5px) !important;
3155
+ box-shadow: 0 16px 40px ${alpha(accent, 0.18)};
3156
+ }
3157
+
3158
+ /* Shimmer sweep on mount */
3159
+ .sc-${uid}::before {
3160
+ content: '';
3161
+ position: absolute;
3162
+ inset: 0;
3163
+ background: linear-gradient(105deg, transparent 40%, ${alpha(accent, 0.08)} 50%, transparent 60%);
3164
+ transform: translateX(-100%);
3165
+ transition: transform 0s;
3166
+ }
3167
+ .sc-${uid}.entered::before {
3168
+ animation: sc-shimmer-${uid} 0.9s ease 0.3s forwards;
3169
+ }
3170
+ @keyframes sc-shimmer-${uid} {
3171
+ to { transform: translateX(200%); }
3172
+ }
3173
+
3174
+ /* Pulse ring on icon */
3175
+ .sc-icon-${uid} {
3176
+ font-size: 1.3rem;
3177
+ background: ${alpha(accent, 0.1)};
3178
+ width: 42px;
3179
+ height: 42px;
3180
+ border-radius: 10px;
3181
+ display: flex;
3182
+ align-items: center;
3183
+ justify-content: center;
3184
+ position: relative;
3185
+ }
3186
+ .sc-icon-${uid}::after {
3187
+ content: '';
3188
+ position: absolute;
3189
+ inset: -4px;
3190
+ border-radius: 14px;
3191
+ border: 2px solid ${alpha(accent, 0.25)};
3192
+ animation: sc-pulse-${uid} 2s ease-in-out infinite;
3193
+ }
3194
+ @keyframes sc-pulse-${uid} {
3195
+ 0%, 100% { transform: scale(1); opacity: 0.6; }
3196
+ 50% { transform: scale(1.12); opacity: 0; }
3197
+ }
3198
+
3199
+ .sc-top-${uid} {
3200
+ display: flex;
3201
+ justify-content: space-between;
3202
+ align-items: center;
3203
+ }
3204
+
3205
+ .sc-badge-up-${uid} {
3206
+ font-size: 0.72rem;
3207
+ font-weight: 700;
3208
+ color: #16a34a;
3209
+ background: #dcfce7;
3210
+ padding: 3px 10px;
3211
+ border-radius: 999px;
3212
+ letter-spacing: 0.02em;
3213
+ animation: sc-badgepop-${uid} 0.4s cubic-bezier(.34,1.56,.64,1) 0.6s both;
3214
+ }
3215
+ .sc-badge-down-${uid} {
3216
+ font-size: 0.72rem;
3217
+ font-weight: 700;
3218
+ color: #dc2626;
3219
+ background: #fee2e2;
3220
+ padding: 3px 10px;
3221
+ border-radius: 999px;
3222
+ letter-spacing: 0.02em;
3223
+ animation: sc-badgepop-${uid} 0.4s cubic-bezier(.34,1.56,.64,1) 0.6s both;
3224
+ }
3225
+ @keyframes sc-badgepop-${uid} {
3226
+ from { transform: scale(0.5); opacity: 0; }
3227
+ to { transform: scale(1); opacity: 1; }
3228
+ }
3229
+
3230
+ .sc-value-${uid} {
3231
+ font-size: 2rem;
3232
+ font-weight: 800;
3233
+ color: #0f172a;
3234
+ line-height: 1;
3235
+ font-variant-numeric: tabular-nums;
3236
+ }
3237
+
3238
+ .sc-label-${uid} {
3239
+ font-size: 0.78rem;
3240
+ font-weight: 600;
3241
+ color: #94a3b8;
3242
+ text-transform: uppercase;
3243
+ letter-spacing: 0.07em;
3244
+ }
3245
+
3246
+ .sc-track-${uid} {
3247
+ height: 5px;
3248
+ border-radius: 999px;
3249
+ background: rgba(0,0,0,0.06);
3250
+ overflow: hidden;
3251
+ }
3252
+ .sc-fill-${uid} {
3253
+ height: 100%;
3254
+ border-radius: 999px;
3255
+ background: linear-gradient(90deg, ${alpha(accent, 0.5)}, ${accent});
3256
+ width: 0%;
3257
+ transition: width 1.2s cubic-bezier(0.22, 1, 0.36, 1) 0.4s;
3258
+ box-shadow: 0 0 8px ${alpha(accent, 0.5)};
3259
+ }
3260
+ `), /* @__PURE__ */ React18.createElement(
3261
+ "div",
3262
+ {
3263
+ ref,
3264
+ className: `sc-${uid}${entered ? " entered" : ""}`
3265
+ },
3266
+ /* @__PURE__ */ React18.createElement("div", { className: `sc-top-${uid}` }, showIcon && /* @__PURE__ */ React18.createElement("div", { className: `sc-icon-${uid}` }, icon), showBadge && /* @__PURE__ */ React18.createElement("span", { className: isPositive ? `sc-badge-up-${uid}` : `sc-badge-down-${uid}` }, isPositive ? "\u25B2" : "\u25BC", " ", change)),
3267
+ /* @__PURE__ */ React18.createElement("div", { className: `sc-value-${uid}` }, visible ? formatCount(count) : "0"),
3268
+ /* @__PURE__ */ React18.createElement("div", { className: `sc-label-${uid}` }, title),
3269
+ /* @__PURE__ */ React18.createElement("div", { className: `sc-track-${uid}` }, /* @__PURE__ */ React18.createElement(
3270
+ "div",
3271
+ {
3272
+ className: `sc-fill-${uid}`,
3273
+ style: { width: `${barWidth}%` }
3274
+ }
3275
+ ))
3276
+ ));
3277
+ };
3278
+
3279
+ // src/components/ProgressBar/ProgressBar.jsx
3280
+ import React19, { useEffect as useEffect8, useRef as useRef4, useState as useState17 } from "react";
3281
+ var ProgressBar = ({
3282
+ label = "Progress",
3283
+ percentage = 75,
3284
+ accent = "#6366f1",
3285
+ bg = "#ffffff",
3286
+ height = 12,
3287
+ showLabel = true,
3288
+ showPercent = true,
3289
+ type = "default",
3290
+ // "default" | "striped" | "circular" | "gradient" | "steps"
3291
+ steps = 5
3292
+ // only for type="steps"
3293
+ }) => {
3294
+ const [filled, setFilled] = useState17(0);
3295
+ const [visible, setVisible] = useState17(false);
3296
+ const ref = useRef4(null);
3297
+ useEffect8(() => {
3298
+ const obs = new IntersectionObserver(
3299
+ ([e]) => {
3300
+ if (e.isIntersecting) {
3301
+ setVisible(true);
3302
+ obs.disconnect();
3303
+ }
3304
+ },
3305
+ { threshold: 0.3 }
3306
+ );
3307
+ if (ref.current) obs.observe(ref.current);
3308
+ return () => obs.disconnect();
3309
+ }, []);
3310
+ useEffect8(() => {
3311
+ if (!visible) return;
3312
+ const duration = 1200;
3313
+ const start = performance.now();
3314
+ const target = Math.min(100, Math.max(0, percentage));
3315
+ const tick = (now) => {
3316
+ const p = Math.min((now - start) / duration, 1);
3317
+ const eased = 1 - Math.pow(1 - p, 4);
3318
+ setFilled(Math.round(eased * target));
3319
+ if (p < 1) requestAnimationFrame(tick);
3320
+ };
3321
+ requestAnimationFrame(tick);
3322
+ }, [visible, percentage]);
3323
+ const alpha = (hex, op) => {
3324
+ const r = parseInt(hex.slice(1, 3), 16);
3325
+ const g = parseInt(hex.slice(3, 5), 16);
3326
+ const b = parseInt(hex.slice(5, 7), 16);
3327
+ return `rgba(${r},${g},${b},${op})`;
3328
+ };
3329
+ const uid = (accent + label + type).replace(/[^a-z0-9]/gi, "x");
3330
+ const badgeColor = filled >= 80 ? "#16a34a" : filled >= 50 ? "#d97706" : "#dc2626";
3331
+ const badgeBg = filled >= 80 ? "#dcfce7" : filled >= 50 ? "#fef3c7" : "#fee2e2";
3332
+ const wrapStyle = {
3333
+ fontFamily: "'Sora', sans-serif",
3334
+ background: bg,
3335
+ borderRadius: "14px",
3336
+ padding: "20px 22px",
3337
+ display: "flex",
3338
+ flexDirection: "column",
3339
+ gap: "10px",
3340
+ border: "1px solid rgba(0,0,0,0.07)",
3341
+ boxShadow: "0 2px 12px rgba(0,0,0,0.05)",
3342
+ opacity: visible ? 1 : 0,
3343
+ transform: visible ? "translateY(0)" : "translateY(16px)",
3344
+ transition: "opacity 0.45s ease, transform 0.45s ease"
3345
+ };
3346
+ const rowStyle = { display: "flex", justifyContent: "space-between", alignItems: "center" };
3347
+ const labelEl = showLabel && /* @__PURE__ */ React19.createElement("span", { style: { fontSize: "0.85rem", fontWeight: 600, color: "#334155" } }, label);
3348
+ const badgeEl = showPercent && /* @__PURE__ */ React19.createElement("span", { style: {
3349
+ fontSize: "0.72rem",
3350
+ fontWeight: 700,
3351
+ color: badgeColor,
3352
+ background: badgeBg,
3353
+ padding: "3px 10px",
3354
+ borderRadius: "999px",
3355
+ transition: "color 0.4s,background 0.4s",
3356
+ fontVariantNumeric: "tabular-nums"
3357
+ } }, filled, "%");
3358
+ if (type === "default") return /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement("style", null, `
3359
+ @import url('https://fonts.googleapis.com/css2?family=Sora:wght@400;600;700&display=swap');
3360
+ @keyframes pb-pulse-${uid} {
3361
+ 0%,100%{opacity:.9;transform:translateY(-50%) scale(1)}
3362
+ 50%{opacity:.4;transform:translateY(-50%) scale(1.5)}
3363
+ }
3364
+ `), /* @__PURE__ */ React19.createElement("div", { ref, style: wrapStyle }, /* @__PURE__ */ React19.createElement("div", { style: rowStyle }, labelEl, badgeEl), /* @__PURE__ */ React19.createElement("div", { style: { width: "100%", height, borderRadius: "999px", background: "#f1f5f9", overflow: "hidden", position: "relative" } }, /* @__PURE__ */ React19.createElement("div", { style: {
3365
+ height: "100%",
3366
+ width: `${filled}%`,
3367
+ borderRadius: "999px",
3368
+ background: `linear-gradient(90deg,${alpha(accent, 0.7)},${accent})`,
3369
+ boxShadow: `0 0 10px ${alpha(accent, 0.35)}`,
3370
+ position: "relative",
3371
+ transition: "width 0.05s linear"
3372
+ } }, /* @__PURE__ */ React19.createElement("div", { style: {
3373
+ position: "absolute",
3374
+ right: 0,
3375
+ top: "50%",
3376
+ width: height + 4,
3377
+ height: height + 4,
3378
+ borderRadius: "50%",
3379
+ background: accent,
3380
+ boxShadow: `0 0 8px 2px ${alpha(accent, 0.5)}`,
3381
+ animation: `pb-pulse-${uid} 1.5s ease-in-out infinite`
3382
+ } }))), /* @__PURE__ */ React19.createElement("div", { style: rowStyle }, /* @__PURE__ */ React19.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, filled < 100 ? `${filled} of 100 completed` : "Completed \u2713"), /* @__PURE__ */ React19.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, filled >= 80 ? "Almost there!" : filled >= 50 ? "Halfway done" : "Just started"))));
3383
+ if (type === "striped") return /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement("style", null, `
3384
+ @import url('https://fonts.googleapis.com/css2?family=Sora:wght@400;600;700&display=swap');
3385
+ @keyframes pb-stripe-${uid} { from{background-position:0 0} to{background-position:32px 0} }
3386
+ @keyframes pb-pulse-${uid} {
3387
+ 0%,100%{opacity:.9;transform:translateY(-50%) scale(1)}
3388
+ 50%{opacity:.4;transform:translateY(-50%) scale(1.5)}
3389
+ }
3390
+ `), /* @__PURE__ */ React19.createElement("div", { ref, style: wrapStyle }, /* @__PURE__ */ React19.createElement("div", { style: rowStyle }, labelEl, badgeEl), /* @__PURE__ */ React19.createElement("div", { style: { width: "100%", height, borderRadius: "999px", background: "#f1f5f9", overflow: "hidden", position: "relative" } }, /* @__PURE__ */ React19.createElement("div", { style: {
3391
+ height: "100%",
3392
+ width: `${filled}%`,
3393
+ borderRadius: "999px",
3394
+ background: `linear-gradient(90deg,${alpha(accent, 0.7)},${accent})`,
3395
+ boxShadow: `0 0 10px ${alpha(accent, 0.35)}`,
3396
+ position: "relative",
3397
+ transition: "width 0.05s linear"
3398
+ } }, /* @__PURE__ */ React19.createElement("div", { style: {
3399
+ position: "absolute",
3400
+ inset: 0,
3401
+ borderRadius: "999px",
3402
+ background: "repeating-linear-gradient(45deg,transparent,transparent 8px,rgba(255,255,255,0.18) 8px,rgba(255,255,255,0.18) 16px)",
3403
+ animation: `pb-stripe-${uid} 0.7s linear infinite`
3404
+ } }), /* @__PURE__ */ React19.createElement("div", { style: {
3405
+ position: "absolute",
3406
+ right: 0,
3407
+ top: "50%",
3408
+ width: height + 4,
3409
+ height: height + 4,
3410
+ borderRadius: "50%",
3411
+ background: accent,
3412
+ boxShadow: `0 0 8px 2px ${alpha(accent, 0.5)}`,
3413
+ animation: `pb-pulse-${uid} 1.5s ease-in-out infinite`
3414
+ } }))), /* @__PURE__ */ React19.createElement("div", { style: rowStyle }, /* @__PURE__ */ React19.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, filled < 100 ? `${filled} of 100 completed` : "Completed \u2713"), /* @__PURE__ */ React19.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, filled >= 80 ? "Almost there!" : filled >= 50 ? "Halfway done" : "Just started"))));
3415
+ if (type === "circular") {
3416
+ const r = 54;
3417
+ const cx = 70;
3418
+ const cy = 70;
3419
+ const circ = 2 * Math.PI * r;
3420
+ const offset = circ - filled / 100 * circ;
3421
+ return /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement("style", null, `
3422
+ @import url('https://fonts.googleapis.com/css2?family=Sora:wght@400;600;700;800&display=swap');
3423
+ @keyframes pb-spin-${uid} { from{stroke-dashoffset:${circ}} to{stroke-dashoffset:${offset}} }
3424
+ `), /* @__PURE__ */ React19.createElement("div", { ref, style: { ...wrapStyle, alignItems: "center", gap: 16 } }, /* @__PURE__ */ React19.createElement("svg", { width: "140", height: "140", viewBox: "0 0 140 140" }, /* @__PURE__ */ React19.createElement("circle", { cx, cy, r, fill: "none", stroke: "#f1f5f9", strokeWidth: "10" }), /* @__PURE__ */ React19.createElement(
3425
+ "circle",
3426
+ {
3427
+ cx,
3428
+ cy,
3429
+ r,
3430
+ fill: "none",
3431
+ stroke: accent,
3432
+ strokeWidth: "10",
3433
+ strokeLinecap: "round",
3434
+ strokeDasharray: circ,
3435
+ strokeDashoffset: offset,
3436
+ transform: `rotate(-90 ${cx} ${cy})`,
3437
+ style: { transition: "stroke-dashoffset 0.05s linear", filter: `drop-shadow(0 0 6px ${alpha(accent, 0.5)})` }
3438
+ }
3439
+ ), /* @__PURE__ */ React19.createElement(
3440
+ "text",
3441
+ {
3442
+ x: cx,
3443
+ y: cy - 8,
3444
+ textAnchor: "middle",
3445
+ dominantBaseline: "middle",
3446
+ style: { fontFamily: "'Sora',sans-serif", fontSize: "1.5rem", fontWeight: 800, fill: "#0f172a" }
3447
+ },
3448
+ filled,
3449
+ "%"
3450
+ ), /* @__PURE__ */ React19.createElement(
3451
+ "text",
3452
+ {
3453
+ x: cx,
3454
+ y: cy + 14,
3455
+ textAnchor: "middle",
3456
+ dominantBaseline: "middle",
3457
+ style: { fontFamily: "'Sora',sans-serif", fontSize: "0.68rem", fontWeight: 600, fill: "#94a3b8", letterSpacing: "0.05em" }
3458
+ },
3459
+ filled >= 80 ? "GREAT" : filled >= 50 ? "GOOD" : "LOW"
3460
+ )), showLabel && /* @__PURE__ */ React19.createElement("span", { style: { fontSize: "0.85rem", fontWeight: 600, color: "#334155" } }, label)));
3461
+ }
3462
+ if (type === "gradient") {
3463
+ const colors = ["#ef4444", "#f97316", "#eab308", "#22c55e", "#6366f1"];
3464
+ const gradStr = colors.map((c, i) => `${c} ${i * 25}%`).join(",");
3465
+ return /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement("style", null, `
3466
+ @import url('https://fonts.googleapis.com/css2?family=Sora:wght@400;600;700&display=swap');
3467
+ @keyframes pb-pulse-${uid} {
3468
+ 0%,100%{opacity:.9;transform:translateY(-50%) scale(1)}
3469
+ 50%{opacity:.4;transform:translateY(-50%) scale(1.5)}
3470
+ }
3471
+ `), /* @__PURE__ */ React19.createElement("div", { ref, style: wrapStyle }, /* @__PURE__ */ React19.createElement("div", { style: rowStyle }, labelEl, badgeEl), /* @__PURE__ */ React19.createElement("div", { style: { width: "100%", height, borderRadius: "999px", background: "#f1f5f9", overflow: "hidden", position: "relative" } }, /* @__PURE__ */ React19.createElement("div", { style: { position: "absolute", inset: 0, background: `linear-gradient(90deg,${gradStr})`, opacity: 0.15 } }), /* @__PURE__ */ React19.createElement("div", { style: {
3472
+ height: "100%",
3473
+ width: `${filled}%`,
3474
+ borderRadius: "999px",
3475
+ background: `linear-gradient(90deg,${gradStr})`,
3476
+ transition: "width 0.05s linear",
3477
+ position: "relative"
3478
+ } }, /* @__PURE__ */ React19.createElement("div", { style: {
3479
+ position: "absolute",
3480
+ right: 0,
3481
+ top: "50%",
3482
+ width: height + 4,
3483
+ height: height + 4,
3484
+ borderRadius: "50%",
3485
+ background: "#fff",
3486
+ border: `2px solid ${accent}`,
3487
+ animation: `pb-pulse-${uid} 1.5s ease-in-out infinite`
3488
+ } }))), /* @__PURE__ */ React19.createElement("div", { style: rowStyle }, /* @__PURE__ */ React19.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, filled < 100 ? `${filled} of 100` : "Completed \u2713"), /* @__PURE__ */ React19.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, filled >= 80 ? "Almost there!" : filled >= 50 ? "Halfway done" : "Just started"))));
3489
+ }
3490
+ if (type === "steps") {
3491
+ const completedSteps = Math.round(filled / 100 * steps);
3492
+ return /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement("style", null, `
3493
+ @import url('https://fonts.googleapis.com/css2?family=Sora:wght@400;600;700&display=swap');
3494
+ @keyframes pb-popin-${uid} {
3495
+ from{transform:scale(0.5);opacity:0}
3496
+ to{transform:scale(1);opacity:1}
3497
+ }
3498
+ `), /* @__PURE__ */ React19.createElement("div", { ref, style: wrapStyle }, /* @__PURE__ */ React19.createElement("div", { style: rowStyle }, labelEl, badgeEl), /* @__PURE__ */ React19.createElement("div", { style: { display: "flex", alignItems: "center", gap: 0 } }, Array.from({ length: steps }, (_, i) => {
3499
+ const done = i < completedSteps;
3500
+ const active = i === completedSteps - 1;
3501
+ return /* @__PURE__ */ React19.createElement(React19.Fragment, { key: i }, /* @__PURE__ */ React19.createElement("div", { style: {
3502
+ width: 32,
3503
+ height: 32,
3504
+ borderRadius: "50%",
3505
+ background: done ? accent : "#f1f5f9",
3506
+ border: active ? `2px solid ${accent}` : done ? "none" : "2px solid #e2e8f0",
3507
+ display: "flex",
3508
+ alignItems: "center",
3509
+ justifyContent: "center",
3510
+ flexShrink: 0,
3511
+ boxShadow: active ? `0 0 12px ${alpha(accent, 0.4)}` : "none",
3512
+ transition: "background 0.3s,box-shadow 0.3s",
3513
+ animation: done ? `pb-popin-${uid} 0.3s ease ${i * 0.08}s both` : "none"
3514
+ } }, done ? /* @__PURE__ */ React19.createElement("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none" }, /* @__PURE__ */ React19.createElement("path", { d: "M2.5 7l3.5 3.5 5.5-6", stroke: "#fff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })) : /* @__PURE__ */ React19.createElement("span", { style: { fontSize: "0.7rem", fontWeight: 700, color: "#cbd5e1" } }, i + 1)), i < steps - 1 && /* @__PURE__ */ React19.createElement("div", { style: {
3515
+ flex: 1,
3516
+ height: 3,
3517
+ borderRadius: "999px",
3518
+ background: i < completedSteps - 1 ? accent : "#f1f5f9",
3519
+ transition: "background 0.3s"
3520
+ } }));
3521
+ })), /* @__PURE__ */ React19.createElement("div", { style: rowStyle }, /* @__PURE__ */ React19.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, "Step ", completedSteps, " of ", steps), /* @__PURE__ */ React19.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, filled >= 80 ? "Almost there!" : filled >= 50 ? "Halfway done" : "Just started"))));
3522
+ }
3523
+ return null;
3524
+ };
3062
3525
  export {
3063
3526
  AvatarCard,
3064
3527
  BackgoundImageSlider,
@@ -3075,6 +3538,8 @@ export {
3075
3538
  OTPInput,
3076
3539
  PageLoader,
3077
3540
  PricingCard,
3541
+ ProgressBar,
3078
3542
  RatingStars,
3079
- Sidebar
3543
+ Sidebar,
3544
+ StatCard
3080
3545
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "virtual-ui-lib",
3
- "version": "1.0.72",
3
+ "version": "1.0.74",
4
4
  "description": "Virtual UI React Component Library",
5
5
  "author": "Ankush",
6
6
  "license": "ISC",