@neowhale/storefront 0.2.29 → 0.2.30

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.
@@ -2454,6 +2454,68 @@ function useReferral() {
2454
2454
  referredBy: status?.referred_by ?? null
2455
2455
  };
2456
2456
  }
2457
+ var NUM_PATTERN = /(\$?[\d,]+\.?\d*[+★%]?)/g;
2458
+ function easeOutQuart(t) {
2459
+ return 1 - Math.pow(1 - t, 4);
2460
+ }
2461
+ function useCountUp(target, duration, start) {
2462
+ const [value, setValue] = react.useState(0);
2463
+ const raf = react.useRef(0);
2464
+ react.useEffect(() => {
2465
+ if (!start) return;
2466
+ const t0 = performance.now();
2467
+ function tick(now2) {
2468
+ const elapsed = now2 - t0;
2469
+ const progress = Math.min(elapsed / duration, 1);
2470
+ setValue(Math.round(easeOutQuart(progress) * target));
2471
+ if (progress < 1) raf.current = requestAnimationFrame(tick);
2472
+ }
2473
+ raf.current = requestAnimationFrame(tick);
2474
+ return () => cancelAnimationFrame(raf.current);
2475
+ }, [target, duration, start]);
2476
+ return value;
2477
+ }
2478
+ function AnimatedNumber({ raw }) {
2479
+ const ref = react.useRef(null);
2480
+ const [visible, setVisible] = react.useState(false);
2481
+ react.useEffect(() => {
2482
+ const el = ref.current;
2483
+ if (!el || typeof IntersectionObserver === "undefined") {
2484
+ setVisible(true);
2485
+ return;
2486
+ }
2487
+ const obs = new IntersectionObserver(([entry]) => {
2488
+ if (entry.isIntersecting) {
2489
+ setVisible(true);
2490
+ obs.disconnect();
2491
+ }
2492
+ }, { threshold: 0.3 });
2493
+ obs.observe(el);
2494
+ return () => obs.disconnect();
2495
+ }, []);
2496
+ const prefix = raw.startsWith("$") ? "$" : "";
2497
+ const suffix = raw.match(/[+★%]$/)?.[0] || "";
2498
+ const numeric = parseFloat(raw.replace(/[\$,+★%]/g, ""));
2499
+ const hasCommas = raw.includes(",");
2500
+ const decimals = raw.includes(".") ? raw.split(".")[1]?.replace(/[+★%]/g, "").length || 0 : 0;
2501
+ const count = useCountUp(
2502
+ decimals > 0 ? Math.round(numeric * Math.pow(10, decimals)) : numeric,
2503
+ 1400,
2504
+ visible
2505
+ );
2506
+ const display = decimals > 0 ? (count / Math.pow(10, decimals)).toFixed(decimals) : hasCommas ? count.toLocaleString() : String(count);
2507
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { ref, children: [
2508
+ prefix,
2509
+ display,
2510
+ suffix
2511
+ ] });
2512
+ }
2513
+ function AnimatedText({ text }) {
2514
+ const parts = text.split(NUM_PATTERN);
2515
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: parts.map(
2516
+ (part, i) => NUM_PATTERN.test(part) ? /* @__PURE__ */ jsxRuntime.jsx(AnimatedNumber, { raw: part }, i) : part
2517
+ ) });
2518
+ }
2457
2519
  function trackClick(tracking, label, url, position) {
2458
2520
  if (!tracking?.gatewayUrl || !tracking?.code) return;
2459
2521
  const body = JSON.stringify({ label, url, position });
@@ -2536,7 +2598,7 @@ function HeroSection({ section, theme, tracking, onEvent }) {
2536
2598
  lineHeight: 1.15,
2537
2599
  letterSpacing: "-0.02em",
2538
2600
  color: theme.fg
2539
- }, children: title }),
2601
+ }, children: /* @__PURE__ */ jsxRuntime.jsx(AnimatedText, { text: title }) }),
2540
2602
  subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { style: {
2541
2603
  fontSize: "0.85rem",
2542
2604
  color: theme.accent,
@@ -2711,7 +2773,7 @@ function StatsSection({ section, theme }) {
2711
2773
  letterSpacing: "0.15em",
2712
2774
  color: `${theme.fg}66`
2713
2775
  }, children: stat.label }),
2714
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 14, fontWeight: 300, color: `${theme.fg}CC` }, children: stat.value })
2776
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 14, fontWeight: 300, color: `${theme.fg}CC` }, children: /* @__PURE__ */ jsxRuntime.jsx(AnimatedText, { text: stat.value }) })
2715
2777
  ] }),
2716
2778
  i < stats.length - 1 && /* @__PURE__ */ jsxRuntime.jsx("hr", { style: { border: "none", borderTop: `1px solid ${theme.fg}0A`, margin: 0 } })
2717
2779
  ] }, i)) });
@@ -2732,7 +2794,7 @@ function StatsSection({ section, theme }) {
2732
2794
  fontWeight: 300,
2733
2795
  lineHeight: 1,
2734
2796
  color: theme.fg
2735
- }, children: stat.value }),
2797
+ }, children: /* @__PURE__ */ jsxRuntime.jsx(AnimatedText, { text: stat.value }) }),
2736
2798
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2737
2799
  fontSize: 11,
2738
2800
  fontWeight: 500,