virtual-ui-lib 1.0.73 → 1.0.75

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.js CHANGED
@@ -33,6 +33,7 @@ __export(index_exports, {
33
33
  BackgoundImageSlider: () => BackgoundImageSlider,
34
34
  Charts: () => Charts,
35
35
  ColorPicker: () => ColorPicker,
36
+ EcommerceCard: () => EcommerceCard,
36
37
  FileUpload: () => FileUpload,
37
38
  Footer: () => Footer,
38
39
  ImageCard: () => ImageCard,
@@ -44,6 +45,7 @@ __export(index_exports, {
44
45
  OTPInput: () => OTPInput,
45
46
  PageLoader: () => PageLoader,
46
47
  PricingCard: () => PricingCard,
48
+ ProgressBar: () => ProgressBar,
47
49
  RatingStars: () => RatingStars,
48
50
  Sidebar: () => Sidebar,
49
51
  StatCard: () => StatCard
@@ -3327,12 +3329,316 @@ var StatCard = ({
3327
3329
  ))
3328
3330
  ));
3329
3331
  };
3332
+
3333
+ // src/components/ProgressBar/ProgressBar.jsx
3334
+ var import_react19 = __toESM(require("react"));
3335
+ var ProgressBar = ({
3336
+ label = "Progress",
3337
+ percentage = 75,
3338
+ accent = "#6366f1",
3339
+ bg = "#ffffff",
3340
+ height = 12,
3341
+ showLabel = true,
3342
+ showPercent = true,
3343
+ type = "default",
3344
+ // "default" | "striped" | "circular" | "gradient" | "steps"
3345
+ steps = 5
3346
+ // only for type="steps"
3347
+ }) => {
3348
+ const [filled, setFilled] = (0, import_react19.useState)(0);
3349
+ const [visible, setVisible] = (0, import_react19.useState)(false);
3350
+ const ref = (0, import_react19.useRef)(null);
3351
+ (0, import_react19.useEffect)(() => {
3352
+ const obs = new IntersectionObserver(
3353
+ ([e]) => {
3354
+ if (e.isIntersecting) {
3355
+ setVisible(true);
3356
+ obs.disconnect();
3357
+ }
3358
+ },
3359
+ { threshold: 0.3 }
3360
+ );
3361
+ if (ref.current) obs.observe(ref.current);
3362
+ return () => obs.disconnect();
3363
+ }, []);
3364
+ (0, import_react19.useEffect)(() => {
3365
+ if (!visible) return;
3366
+ const duration = 1200;
3367
+ const start = performance.now();
3368
+ const target = Math.min(100, Math.max(0, percentage));
3369
+ const tick = (now) => {
3370
+ const p = Math.min((now - start) / duration, 1);
3371
+ const eased = 1 - Math.pow(1 - p, 4);
3372
+ setFilled(Math.round(eased * target));
3373
+ if (p < 1) requestAnimationFrame(tick);
3374
+ };
3375
+ requestAnimationFrame(tick);
3376
+ }, [visible, percentage]);
3377
+ const alpha = (hex, op) => {
3378
+ const r = parseInt(hex.slice(1, 3), 16);
3379
+ const g = parseInt(hex.slice(3, 5), 16);
3380
+ const b = parseInt(hex.slice(5, 7), 16);
3381
+ return `rgba(${r},${g},${b},${op})`;
3382
+ };
3383
+ const uid = (accent + label + type).replace(/[^a-z0-9]/gi, "x");
3384
+ const badgeColor = filled >= 80 ? "#16a34a" : filled >= 50 ? "#d97706" : "#dc2626";
3385
+ const badgeBg = filled >= 80 ? "#dcfce7" : filled >= 50 ? "#fef3c7" : "#fee2e2";
3386
+ const wrapStyle = {
3387
+ fontFamily: "'Sora', sans-serif",
3388
+ background: bg,
3389
+ borderRadius: "14px",
3390
+ padding: "20px 22px",
3391
+ display: "flex",
3392
+ flexDirection: "column",
3393
+ gap: "10px",
3394
+ border: "1px solid rgba(0,0,0,0.07)",
3395
+ boxShadow: "0 2px 12px rgba(0,0,0,0.05)",
3396
+ opacity: visible ? 1 : 0,
3397
+ transform: visible ? "translateY(0)" : "translateY(16px)",
3398
+ transition: "opacity 0.45s ease, transform 0.45s ease"
3399
+ };
3400
+ const rowStyle = { display: "flex", justifyContent: "space-between", alignItems: "center" };
3401
+ const labelEl = showLabel && /* @__PURE__ */ import_react19.default.createElement("span", { style: { fontSize: "0.85rem", fontWeight: 600, color: "#334155" } }, label);
3402
+ const badgeEl = showPercent && /* @__PURE__ */ import_react19.default.createElement("span", { style: {
3403
+ fontSize: "0.72rem",
3404
+ fontWeight: 700,
3405
+ color: badgeColor,
3406
+ background: badgeBg,
3407
+ padding: "3px 10px",
3408
+ borderRadius: "999px",
3409
+ transition: "color 0.4s,background 0.4s",
3410
+ fontVariantNumeric: "tabular-nums"
3411
+ } }, filled, "%");
3412
+ if (type === "default") return /* @__PURE__ */ import_react19.default.createElement(import_react19.default.Fragment, null, /* @__PURE__ */ import_react19.default.createElement("style", null, `
3413
+ @import url('https://fonts.googleapis.com/css2?family=Sora:wght@400;600;700&display=swap');
3414
+ @keyframes pb-pulse-${uid} {
3415
+ 0%,100%{opacity:.9;transform:translateY(-50%) scale(1)}
3416
+ 50%{opacity:.4;transform:translateY(-50%) scale(1.5)}
3417
+ }
3418
+ `), /* @__PURE__ */ import_react19.default.createElement("div", { ref, style: wrapStyle }, /* @__PURE__ */ import_react19.default.createElement("div", { style: rowStyle }, labelEl, badgeEl), /* @__PURE__ */ import_react19.default.createElement("div", { style: { width: "100%", height, borderRadius: "999px", background: "#f1f5f9", overflow: "hidden", position: "relative" } }, /* @__PURE__ */ import_react19.default.createElement("div", { style: {
3419
+ height: "100%",
3420
+ width: `${filled}%`,
3421
+ borderRadius: "999px",
3422
+ background: `linear-gradient(90deg,${alpha(accent, 0.7)},${accent})`,
3423
+ boxShadow: `0 0 10px ${alpha(accent, 0.35)}`,
3424
+ position: "relative",
3425
+ transition: "width 0.05s linear"
3426
+ } }, /* @__PURE__ */ import_react19.default.createElement("div", { style: {
3427
+ position: "absolute",
3428
+ right: 0,
3429
+ top: "50%",
3430
+ width: height + 4,
3431
+ height: height + 4,
3432
+ borderRadius: "50%",
3433
+ background: accent,
3434
+ boxShadow: `0 0 8px 2px ${alpha(accent, 0.5)}`,
3435
+ animation: `pb-pulse-${uid} 1.5s ease-in-out infinite`
3436
+ } }))), /* @__PURE__ */ import_react19.default.createElement("div", { style: rowStyle }, /* @__PURE__ */ import_react19.default.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, filled < 100 ? `${filled} of 100 completed` : "Completed \u2713"), /* @__PURE__ */ import_react19.default.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, filled >= 80 ? "Almost there!" : filled >= 50 ? "Halfway done" : "Just started"))));
3437
+ if (type === "striped") return /* @__PURE__ */ import_react19.default.createElement(import_react19.default.Fragment, null, /* @__PURE__ */ import_react19.default.createElement("style", null, `
3438
+ @import url('https://fonts.googleapis.com/css2?family=Sora:wght@400;600;700&display=swap');
3439
+ @keyframes pb-stripe-${uid} { from{background-position:0 0} to{background-position:32px 0} }
3440
+ @keyframes pb-pulse-${uid} {
3441
+ 0%,100%{opacity:.9;transform:translateY(-50%) scale(1)}
3442
+ 50%{opacity:.4;transform:translateY(-50%) scale(1.5)}
3443
+ }
3444
+ `), /* @__PURE__ */ import_react19.default.createElement("div", { ref, style: wrapStyle }, /* @__PURE__ */ import_react19.default.createElement("div", { style: rowStyle }, labelEl, badgeEl), /* @__PURE__ */ import_react19.default.createElement("div", { style: { width: "100%", height, borderRadius: "999px", background: "#f1f5f9", overflow: "hidden", position: "relative" } }, /* @__PURE__ */ import_react19.default.createElement("div", { style: {
3445
+ height: "100%",
3446
+ width: `${filled}%`,
3447
+ borderRadius: "999px",
3448
+ background: `linear-gradient(90deg,${alpha(accent, 0.7)},${accent})`,
3449
+ boxShadow: `0 0 10px ${alpha(accent, 0.35)}`,
3450
+ position: "relative",
3451
+ transition: "width 0.05s linear"
3452
+ } }, /* @__PURE__ */ import_react19.default.createElement("div", { style: {
3453
+ position: "absolute",
3454
+ inset: 0,
3455
+ borderRadius: "999px",
3456
+ background: "repeating-linear-gradient(45deg,transparent,transparent 8px,rgba(255,255,255,0.18) 8px,rgba(255,255,255,0.18) 16px)",
3457
+ animation: `pb-stripe-${uid} 0.7s linear infinite`
3458
+ } }), /* @__PURE__ */ import_react19.default.createElement("div", { style: {
3459
+ position: "absolute",
3460
+ right: 0,
3461
+ top: "50%",
3462
+ width: height + 4,
3463
+ height: height + 4,
3464
+ borderRadius: "50%",
3465
+ background: accent,
3466
+ boxShadow: `0 0 8px 2px ${alpha(accent, 0.5)}`,
3467
+ animation: `pb-pulse-${uid} 1.5s ease-in-out infinite`
3468
+ } }))), /* @__PURE__ */ import_react19.default.createElement("div", { style: rowStyle }, /* @__PURE__ */ import_react19.default.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, filled < 100 ? `${filled} of 100 completed` : "Completed \u2713"), /* @__PURE__ */ import_react19.default.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, filled >= 80 ? "Almost there!" : filled >= 50 ? "Halfway done" : "Just started"))));
3469
+ if (type === "circular") {
3470
+ const r = 54;
3471
+ const cx = 70;
3472
+ const cy = 70;
3473
+ const circ = 2 * Math.PI * r;
3474
+ const offset = circ - filled / 100 * circ;
3475
+ return /* @__PURE__ */ import_react19.default.createElement(import_react19.default.Fragment, null, /* @__PURE__ */ import_react19.default.createElement("style", null, `
3476
+ @import url('https://fonts.googleapis.com/css2?family=Sora:wght@400;600;700;800&display=swap');
3477
+ @keyframes pb-spin-${uid} { from{stroke-dashoffset:${circ}} to{stroke-dashoffset:${offset}} }
3478
+ `), /* @__PURE__ */ import_react19.default.createElement("div", { ref, style: { ...wrapStyle, alignItems: "center", gap: 16 } }, /* @__PURE__ */ import_react19.default.createElement("svg", { width: "140", height: "140", viewBox: "0 0 140 140" }, /* @__PURE__ */ import_react19.default.createElement("circle", { cx, cy, r, fill: "none", stroke: "#f1f5f9", strokeWidth: "10" }), /* @__PURE__ */ import_react19.default.createElement(
3479
+ "circle",
3480
+ {
3481
+ cx,
3482
+ cy,
3483
+ r,
3484
+ fill: "none",
3485
+ stroke: accent,
3486
+ strokeWidth: "10",
3487
+ strokeLinecap: "round",
3488
+ strokeDasharray: circ,
3489
+ strokeDashoffset: offset,
3490
+ transform: `rotate(-90 ${cx} ${cy})`,
3491
+ style: { transition: "stroke-dashoffset 0.05s linear", filter: `drop-shadow(0 0 6px ${alpha(accent, 0.5)})` }
3492
+ }
3493
+ ), /* @__PURE__ */ import_react19.default.createElement(
3494
+ "text",
3495
+ {
3496
+ x: cx,
3497
+ y: cy - 8,
3498
+ textAnchor: "middle",
3499
+ dominantBaseline: "middle",
3500
+ style: { fontFamily: "'Sora',sans-serif", fontSize: "1.5rem", fontWeight: 800, fill: "#0f172a" }
3501
+ },
3502
+ filled,
3503
+ "%"
3504
+ ), /* @__PURE__ */ import_react19.default.createElement(
3505
+ "text",
3506
+ {
3507
+ x: cx,
3508
+ y: cy + 14,
3509
+ textAnchor: "middle",
3510
+ dominantBaseline: "middle",
3511
+ style: { fontFamily: "'Sora',sans-serif", fontSize: "0.68rem", fontWeight: 600, fill: "#94a3b8", letterSpacing: "0.05em" }
3512
+ },
3513
+ filled >= 80 ? "GREAT" : filled >= 50 ? "GOOD" : "LOW"
3514
+ )), showLabel && /* @__PURE__ */ import_react19.default.createElement("span", { style: { fontSize: "0.85rem", fontWeight: 600, color: "#334155" } }, label)));
3515
+ }
3516
+ if (type === "gradient") {
3517
+ const colors = ["#ef4444", "#f97316", "#eab308", "#22c55e", "#6366f1"];
3518
+ const gradStr = colors.map((c, i) => `${c} ${i * 25}%`).join(",");
3519
+ return /* @__PURE__ */ import_react19.default.createElement(import_react19.default.Fragment, null, /* @__PURE__ */ import_react19.default.createElement("style", null, `
3520
+ @import url('https://fonts.googleapis.com/css2?family=Sora:wght@400;600;700&display=swap');
3521
+ @keyframes pb-pulse-${uid} {
3522
+ 0%,100%{opacity:.9;transform:translateY(-50%) scale(1)}
3523
+ 50%{opacity:.4;transform:translateY(-50%) scale(1.5)}
3524
+ }
3525
+ `), /* @__PURE__ */ import_react19.default.createElement("div", { ref, style: wrapStyle }, /* @__PURE__ */ import_react19.default.createElement("div", { style: rowStyle }, labelEl, badgeEl), /* @__PURE__ */ import_react19.default.createElement("div", { style: { width: "100%", height, borderRadius: "999px", background: "#f1f5f9", overflow: "hidden", position: "relative" } }, /* @__PURE__ */ import_react19.default.createElement("div", { style: { position: "absolute", inset: 0, background: `linear-gradient(90deg,${gradStr})`, opacity: 0.15 } }), /* @__PURE__ */ import_react19.default.createElement("div", { style: {
3526
+ height: "100%",
3527
+ width: `${filled}%`,
3528
+ borderRadius: "999px",
3529
+ background: `linear-gradient(90deg,${gradStr})`,
3530
+ transition: "width 0.05s linear",
3531
+ position: "relative"
3532
+ } }, /* @__PURE__ */ import_react19.default.createElement("div", { style: {
3533
+ position: "absolute",
3534
+ right: 0,
3535
+ top: "50%",
3536
+ width: height + 4,
3537
+ height: height + 4,
3538
+ borderRadius: "50%",
3539
+ background: "#fff",
3540
+ border: `2px solid ${accent}`,
3541
+ animation: `pb-pulse-${uid} 1.5s ease-in-out infinite`
3542
+ } }))), /* @__PURE__ */ import_react19.default.createElement("div", { style: rowStyle }, /* @__PURE__ */ import_react19.default.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, filled < 100 ? `${filled} of 100` : "Completed \u2713"), /* @__PURE__ */ import_react19.default.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, filled >= 80 ? "Almost there!" : filled >= 50 ? "Halfway done" : "Just started"))));
3543
+ }
3544
+ if (type === "steps") {
3545
+ const completedSteps = Math.round(filled / 100 * steps);
3546
+ return /* @__PURE__ */ import_react19.default.createElement(import_react19.default.Fragment, null, /* @__PURE__ */ import_react19.default.createElement("style", null, `
3547
+ @import url('https://fonts.googleapis.com/css2?family=Sora:wght@400;600;700&display=swap');
3548
+ @keyframes pb-popin-${uid} {
3549
+ from{transform:scale(0.5);opacity:0}
3550
+ to{transform:scale(1);opacity:1}
3551
+ }
3552
+ `), /* @__PURE__ */ import_react19.default.createElement("div", { ref, style: wrapStyle }, /* @__PURE__ */ import_react19.default.createElement("div", { style: rowStyle }, labelEl, badgeEl), /* @__PURE__ */ import_react19.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 0 } }, Array.from({ length: steps }, (_, i) => {
3553
+ const done = i < completedSteps;
3554
+ const active = i === completedSteps - 1;
3555
+ return /* @__PURE__ */ import_react19.default.createElement(import_react19.default.Fragment, { key: i }, /* @__PURE__ */ import_react19.default.createElement("div", { style: {
3556
+ width: 32,
3557
+ height: 32,
3558
+ borderRadius: "50%",
3559
+ background: done ? accent : "#f1f5f9",
3560
+ border: active ? `2px solid ${accent}` : done ? "none" : "2px solid #e2e8f0",
3561
+ display: "flex",
3562
+ alignItems: "center",
3563
+ justifyContent: "center",
3564
+ flexShrink: 0,
3565
+ boxShadow: active ? `0 0 12px ${alpha(accent, 0.4)}` : "none",
3566
+ transition: "background 0.3s,box-shadow 0.3s",
3567
+ animation: done ? `pb-popin-${uid} 0.3s ease ${i * 0.08}s both` : "none"
3568
+ } }, done ? /* @__PURE__ */ import_react19.default.createElement("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none" }, /* @__PURE__ */ import_react19.default.createElement("path", { d: "M2.5 7l3.5 3.5 5.5-6", stroke: "#fff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })) : /* @__PURE__ */ import_react19.default.createElement("span", { style: { fontSize: "0.7rem", fontWeight: 700, color: "#cbd5e1" } }, i + 1)), i < steps - 1 && /* @__PURE__ */ import_react19.default.createElement("div", { style: {
3569
+ flex: 1,
3570
+ height: 3,
3571
+ borderRadius: "999px",
3572
+ background: i < completedSteps - 1 ? accent : "#f1f5f9",
3573
+ transition: "background 0.3s"
3574
+ } }));
3575
+ })), /* @__PURE__ */ import_react19.default.createElement("div", { style: rowStyle }, /* @__PURE__ */ import_react19.default.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, "Step ", completedSteps, " of ", steps), /* @__PURE__ */ import_react19.default.createElement("span", { style: { fontSize: "0.7rem", color: "#94a3b8" } }, filled >= 80 ? "Almost there!" : filled >= 50 ? "Halfway done" : "Just started"))));
3576
+ }
3577
+ return null;
3578
+ };
3579
+
3580
+ // src/components/EcommerceCard/EcommerceCard.jsx
3581
+ var import_react20 = __toESM(require("react"));
3582
+ var EcommerceCard = ({
3583
+ image = "https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=600&q=80",
3584
+ title = "Wireless Headphones",
3585
+ description = "Premium noise-cancelling headphones with 40 hours battery life.",
3586
+ price = 199,
3587
+ currency = "$",
3588
+ accent = "#6366f1",
3589
+ bg = "#0f172a",
3590
+ onAddToCart = () => {
3591
+ },
3592
+ onViewDetails = () => {
3593
+ }
3594
+ }) => {
3595
+ const [hovered, setHovered] = (0, import_react20.useState)(false);
3596
+ const alpha = (hex, op) => {
3597
+ const r = parseInt(hex.slice(1, 3), 16), g = parseInt(hex.slice(3, 5), 16), b = parseInt(hex.slice(5, 7), 16);
3598
+ return "rgba(" + r + "," + g + "," + b + "," + op + ")";
3599
+ };
3600
+ return /* @__PURE__ */ import_react20.default.createElement(
3601
+ "div",
3602
+ {
3603
+ onMouseEnter: () => setHovered(true),
3604
+ onMouseLeave: () => setHovered(false),
3605
+ style: {
3606
+ background: bg,
3607
+ borderRadius: "20px",
3608
+ overflow: "hidden",
3609
+ width: "300px",
3610
+ border: "1px solid " + (hovered ? alpha(accent, 0.3) : "rgba(255,255,255,0.07)"),
3611
+ fontFamily: "system-ui,sans-serif",
3612
+ transition: "transform 0.25s, box-shadow 0.25s",
3613
+ transform: hovered ? "translateY(-4px)" : "translateY(0px)",
3614
+ boxShadow: hovered ? "0 16px 40px rgba(0,0,0,0.5)" : "0 4px 20px rgba(0,0,0,0.3)"
3615
+ }
3616
+ },
3617
+ /* @__PURE__ */ import_react20.default.createElement("div", { style: { position: "relative", width: "100%", height: "200px", overflow: "hidden" } }, /* @__PURE__ */ import_react20.default.createElement("img", { src: image, alt: title, style: { width: "100%", height: "100%", objectFit: "cover", transform: hovered ? "scale(1.05)" : "scale(1)", transition: "transform 0.4s ease" } }), /* @__PURE__ */ import_react20.default.createElement("div", { style: { position: "absolute", inset: 0, background: "linear-gradient(to top, rgba(0,0,0,0.5) 0%, transparent 60%)" } })),
3618
+ /* @__PURE__ */ import_react20.default.createElement("div", { style: { padding: "18px" } }, /* @__PURE__ */ import_react20.default.createElement("h3", { style: { fontSize: "15px", fontWeight: "700", color: "#fff", margin: "0 0 8px", lineHeight: 1.4 } }, title), /* @__PURE__ */ import_react20.default.createElement("p", { style: { fontSize: "13px", color: "rgba(255,255,255,0.45)", lineHeight: 1.65, margin: "0 0 18px" } }, description), /* @__PURE__ */ import_react20.default.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: "18px" } }, /* @__PURE__ */ import_react20.default.createElement("span", { style: { fontSize: "24px", fontWeight: "800", color: "#fff" } }, currency, price), /* @__PURE__ */ import_react20.default.createElement(
3619
+ "button",
3620
+ {
3621
+ onClick: onAddToCart,
3622
+ style: { padding: "8px 16px", borderRadius: "12px", border: "none", background: accent, color: "#fff", fontSize: "13px", fontWeight: "700", cursor: "pointer", fontFamily: "inherit" }
3623
+ },
3624
+ "Add to Cart"
3625
+ )), /* @__PURE__ */ import_react20.default.createElement(
3626
+ "button",
3627
+ {
3628
+ onClick: onViewDetails,
3629
+ style: { width: "100%", padding: "11px", borderRadius: "12px", border: "1px solid " + alpha(accent, 0.3), background: "transparent", color: accent, fontSize: "13px", fontWeight: "700", cursor: "pointer", fontFamily: "inherit" }
3630
+ },
3631
+ "View Details"
3632
+ ))
3633
+ );
3634
+ };
3330
3635
  // Annotate the CommonJS export names for ESM import in node:
3331
3636
  0 && (module.exports = {
3332
3637
  AvatarCard,
3333
3638
  BackgoundImageSlider,
3334
3639
  Charts,
3335
3640
  ColorPicker,
3641
+ EcommerceCard,
3336
3642
  FileUpload,
3337
3643
  Footer,
3338
3644
  ImageCard,
@@ -3344,6 +3650,7 @@ var StatCard = ({
3344
3650
  OTPInput,
3345
3651
  PageLoader,
3346
3652
  PricingCard,
3653
+ ProgressBar,
3347
3654
  RatingStars,
3348
3655
  Sidebar,
3349
3656
  StatCard
package/dist/index.mjs CHANGED
@@ -3275,11 +3275,315 @@ var StatCard = ({
3275
3275
  ))
3276
3276
  ));
3277
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
+ };
3525
+
3526
+ // src/components/EcommerceCard/EcommerceCard.jsx
3527
+ import React20, { useState as useState18 } from "react";
3528
+ var EcommerceCard = ({
3529
+ image = "https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=600&q=80",
3530
+ title = "Wireless Headphones",
3531
+ description = "Premium noise-cancelling headphones with 40 hours battery life.",
3532
+ price = 199,
3533
+ currency = "$",
3534
+ accent = "#6366f1",
3535
+ bg = "#0f172a",
3536
+ onAddToCart = () => {
3537
+ },
3538
+ onViewDetails = () => {
3539
+ }
3540
+ }) => {
3541
+ const [hovered, setHovered] = useState18(false);
3542
+ const alpha = (hex, op) => {
3543
+ const r = parseInt(hex.slice(1, 3), 16), g = parseInt(hex.slice(3, 5), 16), b = parseInt(hex.slice(5, 7), 16);
3544
+ return "rgba(" + r + "," + g + "," + b + "," + op + ")";
3545
+ };
3546
+ return /* @__PURE__ */ React20.createElement(
3547
+ "div",
3548
+ {
3549
+ onMouseEnter: () => setHovered(true),
3550
+ onMouseLeave: () => setHovered(false),
3551
+ style: {
3552
+ background: bg,
3553
+ borderRadius: "20px",
3554
+ overflow: "hidden",
3555
+ width: "300px",
3556
+ border: "1px solid " + (hovered ? alpha(accent, 0.3) : "rgba(255,255,255,0.07)"),
3557
+ fontFamily: "system-ui,sans-serif",
3558
+ transition: "transform 0.25s, box-shadow 0.25s",
3559
+ transform: hovered ? "translateY(-4px)" : "translateY(0px)",
3560
+ boxShadow: hovered ? "0 16px 40px rgba(0,0,0,0.5)" : "0 4px 20px rgba(0,0,0,0.3)"
3561
+ }
3562
+ },
3563
+ /* @__PURE__ */ React20.createElement("div", { style: { position: "relative", width: "100%", height: "200px", overflow: "hidden" } }, /* @__PURE__ */ React20.createElement("img", { src: image, alt: title, style: { width: "100%", height: "100%", objectFit: "cover", transform: hovered ? "scale(1.05)" : "scale(1)", transition: "transform 0.4s ease" } }), /* @__PURE__ */ React20.createElement("div", { style: { position: "absolute", inset: 0, background: "linear-gradient(to top, rgba(0,0,0,0.5) 0%, transparent 60%)" } })),
3564
+ /* @__PURE__ */ React20.createElement("div", { style: { padding: "18px" } }, /* @__PURE__ */ React20.createElement("h3", { style: { fontSize: "15px", fontWeight: "700", color: "#fff", margin: "0 0 8px", lineHeight: 1.4 } }, title), /* @__PURE__ */ React20.createElement("p", { style: { fontSize: "13px", color: "rgba(255,255,255,0.45)", lineHeight: 1.65, margin: "0 0 18px" } }, description), /* @__PURE__ */ React20.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: "18px" } }, /* @__PURE__ */ React20.createElement("span", { style: { fontSize: "24px", fontWeight: "800", color: "#fff" } }, currency, price), /* @__PURE__ */ React20.createElement(
3565
+ "button",
3566
+ {
3567
+ onClick: onAddToCart,
3568
+ style: { padding: "8px 16px", borderRadius: "12px", border: "none", background: accent, color: "#fff", fontSize: "13px", fontWeight: "700", cursor: "pointer", fontFamily: "inherit" }
3569
+ },
3570
+ "Add to Cart"
3571
+ )), /* @__PURE__ */ React20.createElement(
3572
+ "button",
3573
+ {
3574
+ onClick: onViewDetails,
3575
+ style: { width: "100%", padding: "11px", borderRadius: "12px", border: "1px solid " + alpha(accent, 0.3), background: "transparent", color: accent, fontSize: "13px", fontWeight: "700", cursor: "pointer", fontFamily: "inherit" }
3576
+ },
3577
+ "View Details"
3578
+ ))
3579
+ );
3580
+ };
3278
3581
  export {
3279
3582
  AvatarCard,
3280
3583
  BackgoundImageSlider,
3281
3584
  Charts,
3282
3585
  ColorPicker,
3586
+ EcommerceCard,
3283
3587
  FileUpload,
3284
3588
  Footer,
3285
3589
  ImageCard,
@@ -3291,6 +3595,7 @@ export {
3291
3595
  OTPInput,
3292
3596
  PageLoader,
3293
3597
  PricingCard,
3598
+ ProgressBar,
3294
3599
  RatingStars,
3295
3600
  Sidebar,
3296
3601
  StatCard
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "virtual-ui-lib",
3
- "version": "1.0.73",
3
+ "version": "1.0.75",
4
4
  "description": "Virtual UI React Component Library",
5
5
  "author": "Ankush",
6
6
  "license": "ISC",