@snowcone-app/ui 0.3.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -271,6 +271,7 @@ __export(src_exports, {
271
271
  RealtimeProvider: () => RealtimeProvider,
272
272
  ResponsiveZoom: () => ResponsiveZoom,
273
273
  RightToLeftProgressiveBlur: () => RightToLeftProgressiveBlur,
274
+ SafeImg: () => SafeImg,
274
275
  ScrollFade: () => ScrollFade,
275
276
  SearchBox: () => SearchBox,
276
277
  SearchProvider: () => SearchProvider,
@@ -378,7 +379,7 @@ __export(src_exports, {
378
379
  useProductSelection: () => useProductSelection,
379
380
  useProviderStatus: () => useProviderStatus,
380
381
  useRealtime: () => useRealtime,
381
- useRealtimeMockup: () => import_react69.useRealtimeMockup,
382
+ useRealtimeMockup: () => import_react70.useRealtimeMockup,
382
383
  useRealtimeOptional: () => useRealtimeOptional,
383
384
  useRenderCount: () => useRenderCount,
384
385
  useRenderGuard: () => useRenderGuard,
@@ -5979,8 +5980,8 @@ function RealtimeProvider({
5979
5980
  },
5980
5981
  onAllMockupsRendered: (results) => {
5981
5982
  },
5982
- onError: (error) => {
5983
- console.error("[RealtimeProvider] Error:", error);
5983
+ onError: (error, detail) => {
5984
+ console.error(`[RealtimeProvider] Render error [${detail.code}]:`, error);
5984
5985
  }
5985
5986
  });
5986
5987
  const subscribeRTCTiming = (0, import_react24.useCallback)((_callback) => {
@@ -5990,6 +5991,7 @@ function RealtimeProvider({
5990
5991
  const {
5991
5992
  isConnected,
5992
5993
  isConfigured,
5994
+ renderError,
5993
5995
  mockupResults: rawMockupResults,
5994
5996
  sendCanvasBlob: sendCanvasBlobRaw,
5995
5997
  sendCanvasState: sendCanvasStateRaw,
@@ -6509,6 +6511,7 @@ function RealtimeProvider({
6509
6511
  isEnabled,
6510
6512
  isConnected,
6511
6513
  isConfigured,
6514
+ renderError,
6512
6515
  // Read from ref - this is a snapshot at render time, NOT reactive
6513
6516
  // For reactive updates, use getMockupResultsImmediate() or subscribe functions
6514
6517
  get mockupResults() {
@@ -6552,6 +6555,7 @@ function RealtimeProvider({
6552
6555
  isEnabled,
6553
6556
  isConnected,
6554
6557
  isConfigured,
6558
+ renderError,
6555
6559
  // mockupResults removed from deps - it's a getter that reads from ref
6556
6560
  canvasExportSize,
6557
6561
  mockupWidth,
@@ -9338,7 +9342,7 @@ var LoadingOverlayPrismCandyInline = (0, import_react40.memo)(
9338
9342
  );
9339
9343
 
9340
9344
  // src/index.ts
9341
- var import_react69 = require("@snowcone-app/sdk/react");
9345
+ var import_react70 = require("@snowcone-app/sdk/react");
9342
9346
  var import_sdk11 = require("@snowcone-app/sdk");
9343
9347
 
9344
9348
  // src/patterns/ProductPageProvider.tsx
@@ -10412,12 +10416,18 @@ var HeroProductImage = (0, import_react45.memo)(function HeroProductImage2({
10412
10416
  const [showNew, setShowNew] = (0, import_react45.useState)(false);
10413
10417
  const [renderedUrl, setRenderedUrl] = (0, import_react45.useState)(displayUrl);
10414
10418
  const [firstImageLoaded, setFirstImageLoaded] = (0, import_react45.useState)(false);
10419
+ const [loaderMounted, setLoaderMounted] = (0, import_react45.useState)(true);
10420
+ const [imgFailed, setImgFailed] = (0, import_react45.useState)(false);
10421
+ const [retryNonce, setRetryNonce] = (0, import_react45.useState)(0);
10422
+ const retriedUrlRef = (0, import_react45.useRef)(null);
10415
10423
  const prevDisplayUrlRef = (0, import_react45.useRef)(displayUrl);
10416
10424
  const signHintShownRef = (0, import_react45.useRef)(false);
10417
10425
  (0, import_react45.useEffect)(() => {
10418
10426
  if (!displayUrl || displayUrl === prevDisplayUrlRef.current) return;
10419
10427
  const oldUrl = prevDisplayUrlRef.current;
10420
10428
  prevDisplayUrlRef.current = displayUrl;
10429
+ setImgFailed(false);
10430
+ retriedUrlRef.current = null;
10421
10431
  if (!oldUrl) {
10422
10432
  setRenderedUrl(displayUrl);
10423
10433
  return;
@@ -10443,6 +10453,7 @@ var HeroProductImage = (0, import_react45.memo)(function HeroProductImage2({
10443
10453
  setPrevUrl(null);
10444
10454
  setShowNew(false);
10445
10455
  }, []);
10456
+ const handleLoaderExited = (0, import_react45.useCallback)(() => setLoaderMounted(false), []);
10446
10457
  if (!hasArtwork) {
10447
10458
  return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
10448
10459
  "div",
@@ -10491,19 +10502,19 @@ var HeroProductImage = (0, import_react45.memo)(function HeroProductImage2({
10491
10502
  style,
10492
10503
  "data-hero-image": "true",
10493
10504
  children: [
10494
- !firstImageLoaded && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "absolute inset-0 bg-muted-foreground/20 animate-pulse" }),
10495
- renderedUrl && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
10505
+ renderedUrl && !imgFailed && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
10496
10506
  "img",
10497
10507
  {
10498
10508
  alt: `Product mockup${placement ? ` - ${placement}` : ""}`,
10499
10509
  crossOrigin: "anonymous",
10500
10510
  className: "absolute inset-0 w-full h-full object-cover",
10501
10511
  draggable,
10502
- src: renderedUrl,
10512
+ src: retriedUrlRef.current === renderedUrl ? `${renderedUrl}${renderedUrl.includes("?") ? "&" : "?"}_cb=${retryNonce}` : renderedUrl,
10503
10513
  loading: "eager",
10504
10514
  fetchPriority: "high",
10505
10515
  onClick,
10506
10516
  onLoad: () => {
10517
+ setImgFailed(false);
10507
10518
  setFirstImageLoaded(true);
10508
10519
  if (!onLoadCalledRef.current && onLoad) {
10509
10520
  onLoadCalledRef.current = true;
@@ -10512,6 +10523,12 @@ var HeroProductImage = (0, import_react45.memo)(function HeroProductImage2({
10512
10523
  onUrlGeneratedRef.current?.(renderedUrl);
10513
10524
  },
10514
10525
  onError: () => {
10526
+ if (renderedUrl && retriedUrlRef.current !== renderedUrl) {
10527
+ retriedUrlRef.current = renderedUrl;
10528
+ setRetryNonce((n) => n + 1);
10529
+ return;
10530
+ }
10531
+ setImgFailed(true);
10515
10532
  setFirstImageLoaded(true);
10516
10533
  onError?.();
10517
10534
  if (process.env.NODE_ENV !== "production" && !signHintShownRef.current && renderedUrl && /\/[A-Za-z0-9]+\?/.test(renderedUrl) && !/[?&]signature=/.test(renderedUrl)) {
@@ -10524,6 +10541,16 @@ var HeroProductImage = (0, import_react45.memo)(function HeroProductImage2({
10524
10541
  }
10525
10542
  }
10526
10543
  ),
10544
+ imgFailed && !prevUrl && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "absolute inset-0 flex items-center justify-center bg-muted", children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("p", { className: "text-muted-foreground text-xs", children: "Preview unavailable" }) }),
10545
+ realtimeContext?.renderError && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
10546
+ "div",
10547
+ {
10548
+ role: "alert",
10549
+ "data-render-error": realtimeContext.renderError.code,
10550
+ className: "absolute inset-x-0 bottom-0 z-20 bg-red-600/90 text-white text-xs font-medium px-3 py-2 pointer-events-none",
10551
+ children: `Render blocked: ${realtimeContext.renderError.code} \u2014 ${realtimeContext.renderError.message}`
10552
+ }
10553
+ ),
10527
10554
  prevUrl && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
10528
10555
  "img",
10529
10556
  {
@@ -10538,12 +10565,45 @@ var HeroProductImage = (0, import_react45.memo)(function HeroProductImage2({
10538
10565
  },
10539
10566
  onTransitionEnd: handleCrossfadeEnd
10540
10567
  }
10568
+ ),
10569
+ loaderMounted && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
10570
+ LoadingOverlayPrismCandyInline,
10571
+ {
10572
+ visible: !firstImageLoaded,
10573
+ variant: "light",
10574
+ onExited: handleLoaderExited
10575
+ }
10541
10576
  )
10542
10577
  ]
10543
10578
  }
10544
10579
  );
10545
10580
  });
10546
10581
 
10582
+ // src/composed/SafeImg.tsx
10583
+ var import_react46 = __toESM(require("react"), 1);
10584
+ var import_jsx_runtime61 = require("react/jsx-runtime");
10585
+ var SafeImg = import_react46.default.forwardRef(
10586
+ function SafeImg2({ fallback = null, onError, src, ...rest }, ref) {
10587
+ const [failed, setFailed] = (0, import_react46.useState)(false);
10588
+ (0, import_react46.useEffect)(() => {
10589
+ setFailed(false);
10590
+ }, [src]);
10591
+ if (failed) return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(import_jsx_runtime61.Fragment, { children: fallback });
10592
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
10593
+ "img",
10594
+ {
10595
+ ...rest,
10596
+ ref,
10597
+ src,
10598
+ onError: (e) => {
10599
+ setFailed(true);
10600
+ onError?.(e);
10601
+ }
10602
+ }
10603
+ );
10604
+ }
10605
+ );
10606
+
10547
10607
  // src/index.ts
10548
10608
  var import_sdk12 = require("@snowcone-app/sdk");
10549
10609
 
@@ -10553,7 +10613,7 @@ var import_react_instantsearch = require("react-instantsearch");
10553
10613
  // src/composed/search/meilisearchAdapter.ts
10554
10614
  var import_instant_meilisearch = require("@meilisearch/instant-meilisearch");
10555
10615
  var MEILISEARCH_HOST = readEnv("NEXT_PUBLIC_MEILISEARCH_HOST") || "https://ms-e5d999b2eaca-15654.sfo.meilisearch.io";
10556
- var MEILISEARCH_API_KEY = readEnv("NEXT_PUBLIC_MEILISEARCH_API_KEY") || "eee819b849798ad9091228c486ec05d0931e5292";
10616
+ var MEILISEARCH_API_KEY = readEnv("NEXT_PUBLIC_MEILISEARCH_API_KEY") || "4a11f6599e39af365f6289dab46b77a30ef78ba1ac078f7d74e152c099b3b63c";
10557
10617
  var { searchClient } = (0, import_instant_meilisearch.instantMeiliSearch)(
10558
10618
  MEILISEARCH_HOST,
10559
10619
  MEILISEARCH_API_KEY,
@@ -10564,11 +10624,11 @@ var { searchClient } = (0, import_instant_meilisearch.instantMeiliSearch)(
10564
10624
  );
10565
10625
 
10566
10626
  // src/composed/search/SearchProvider.tsx
10567
- var import_react46 = require("react");
10568
- var import_jsx_runtime61 = require("react/jsx-runtime");
10627
+ var import_react47 = require("react");
10628
+ var import_jsx_runtime62 = require("react/jsx-runtime");
10569
10629
  function InitialSearchTrigger() {
10570
10630
  const { refine } = (0, import_react_instantsearch.useSearchBox)();
10571
- (0, import_react46.useEffect)(() => {
10631
+ (0, import_react47.useEffect)(() => {
10572
10632
  refine("");
10573
10633
  }, [refine]);
10574
10634
  return null;
@@ -10592,7 +10652,7 @@ function SearchProvider({
10592
10652
  ],
10593
10653
  children
10594
10654
  }) {
10595
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(
10655
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
10596
10656
  import_react_instantsearch.InstantSearch,
10597
10657
  {
10598
10658
  searchClient,
@@ -10620,7 +10680,7 @@ function SearchProvider({
10620
10680
  }
10621
10681
  },
10622
10682
  children: [
10623
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
10683
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
10624
10684
  import_react_instantsearch.Configure,
10625
10685
  {
10626
10686
  hitsPerPage,
@@ -10629,7 +10689,7 @@ function SearchProvider({
10629
10689
  attributesToRetrieve
10630
10690
  }
10631
10691
  ),
10632
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(InitialSearchTrigger, {}),
10692
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(InitialSearchTrigger, {}),
10633
10693
  children
10634
10694
  ]
10635
10695
  }
@@ -10639,17 +10699,17 @@ function SearchProvider({
10639
10699
  // src/composed/search/SearchBox.tsx
10640
10700
  var import_react_instantsearch2 = require("react-instantsearch");
10641
10701
  var import_lucide_react3 = require("lucide-react");
10642
- var import_react47 = require("react");
10643
- var import_jsx_runtime62 = require("react/jsx-runtime");
10702
+ var import_react48 = require("react");
10703
+ var import_jsx_runtime63 = require("react/jsx-runtime");
10644
10704
  function SearchBox() {
10645
10705
  const { query, refine, clear } = (0, import_react_instantsearch2.useSearchBox)();
10646
10706
  const searchParams = useUiSearchParams();
10647
10707
  const router = useUiRouter();
10648
- const inputRef = (0, import_react47.useRef)(null);
10649
- const [showShimmer, setShowShimmer] = (0, import_react47.useState)(false);
10708
+ const inputRef = (0, import_react48.useRef)(null);
10709
+ const [showShimmer, setShowShimmer] = (0, import_react48.useState)(false);
10650
10710
  const inputId = "search-products-input";
10651
10711
  const descriptionId = "search-description";
10652
- (0, import_react47.useEffect)(() => {
10712
+ (0, import_react48.useEffect)(() => {
10653
10713
  const handleSpotlight = () => {
10654
10714
  inputRef.current?.focus();
10655
10715
  inputRef.current?.scrollIntoView({ behavior: "smooth", block: "center" });
@@ -10659,7 +10719,7 @@ function SearchBox() {
10659
10719
  window.addEventListener("search-spotlight", handleSpotlight);
10660
10720
  return () => window.removeEventListener("search-spotlight", handleSpotlight);
10661
10721
  }, []);
10662
- (0, import_react47.useEffect)(() => {
10722
+ (0, import_react48.useEffect)(() => {
10663
10723
  const shouldFocus = searchParams.get("focus") === "search";
10664
10724
  if (shouldFocus && inputRef.current) {
10665
10725
  const timer = setTimeout(() => {
@@ -10674,8 +10734,8 @@ function SearchBox() {
10674
10734
  return () => clearTimeout(timer);
10675
10735
  }
10676
10736
  }, [searchParams, router]);
10677
- return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("form", { role: "search", onSubmit: (e) => e.preventDefault(), children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "relative", children: [
10678
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
10737
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("form", { role: "search", onSubmit: (e) => e.preventDefault(), children: /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "relative", children: [
10738
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
10679
10739
  Input,
10680
10740
  {
10681
10741
  ref: inputRef,
@@ -10684,15 +10744,15 @@ function SearchBox() {
10684
10744
  value: query,
10685
10745
  onChange: (e) => refine(e.target.value),
10686
10746
  placeholder: "Search products...",
10687
- startContent: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react3.Search, { className: "w-5 h-5", strokeWidth: 1.5, "aria-hidden": "true" }),
10688
- endContent: query ? /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
10747
+ startContent: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(import_lucide_react3.Search, { className: "w-5 h-5", strokeWidth: 1.5, "aria-hidden": "true" }),
10748
+ endContent: query ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
10689
10749
  "button",
10690
10750
  {
10691
10751
  type: "button",
10692
10752
  onClick: clear,
10693
10753
  className: "hover:text-foreground transition-colors",
10694
10754
  "aria-label": "Clear search",
10695
- children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react3.X, { className: "w-4 h-4", strokeWidth: 2, "aria-hidden": "true" })
10755
+ children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(import_lucide_react3.X, { className: "w-4 h-4", strokeWidth: 2, "aria-hidden": "true" })
10696
10756
  }
10697
10757
  ) : void 0,
10698
10758
  "aria-label": "Search products",
@@ -10702,11 +10762,11 @@ function SearchBox() {
10702
10762
  className: "[&::-webkit-search-cancel-button]:hidden [&::-webkit-search-decoration]:hidden"
10703
10763
  }
10704
10764
  ),
10705
- showShimmer && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
10765
+ showShimmer && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
10706
10766
  "div",
10707
10767
  {
10708
10768
  className: "absolute inset-0 pointer-events-none rounded-input z-20 overflow-hidden",
10709
- children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
10769
+ children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
10710
10770
  "div",
10711
10771
  {
10712
10772
  className: "absolute inset-0",
@@ -10719,13 +10779,13 @@ function SearchBox() {
10719
10779
  )
10720
10780
  }
10721
10781
  ),
10722
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("style", { dangerouslySetInnerHTML: { __html: `
10782
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("style", { dangerouslySetInnerHTML: { __html: `
10723
10783
  @keyframes searchShimmer {
10724
10784
  0% { transform: translateX(-100%); }
10725
10785
  100% { transform: translateX(100%); }
10726
10786
  }
10727
10787
  ` } }),
10728
- /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { id: descriptionId, className: "sr-only", children: "Search results will update as you type" })
10788
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { id: descriptionId, className: "sr-only", children: "Search results will update as you type" })
10729
10789
  ] }) });
10730
10790
  }
10731
10791
 
@@ -10733,7 +10793,7 @@ function SearchBox() {
10733
10793
  var import_react_instantsearch3 = require("react-instantsearch");
10734
10794
 
10735
10795
  // src/composed/search/ProductHit.tsx
10736
- var import_jsx_runtime63 = require("react/jsx-runtime");
10796
+ var import_jsx_runtime64 = require("react/jsx-runtime");
10737
10797
  function ProductHitComponent({
10738
10798
  hit: product,
10739
10799
  variant = "overlay"
@@ -10750,12 +10810,12 @@ function ProductHitComponent({
10750
10810
  }
10751
10811
  return "";
10752
10812
  };
10753
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
10813
+ return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
10754
10814
  Product,
10755
10815
  {
10756
10816
  productId,
10757
10817
  productData: product,
10758
- children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
10818
+ children: /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
10759
10819
  ProductCard,
10760
10820
  {
10761
10821
  variant,
@@ -10776,10 +10836,10 @@ function ProductHitComponent({
10776
10836
  }
10777
10837
 
10778
10838
  // src/composed/search/ProductGrid.tsx
10779
- var import_react48 = require("react");
10780
- var import_jsx_runtime64 = require("react/jsx-runtime");
10839
+ var import_react49 = require("react");
10840
+ var import_jsx_runtime65 = require("react/jsx-runtime");
10781
10841
  function ProductGridSkeletonItem() {
10782
- return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: "aspect-square bg-muted animate-pulse" });
10842
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { className: "aspect-square bg-muted animate-pulse" });
10783
10843
  }
10784
10844
  function ProductGrid({
10785
10845
  className = "",
@@ -10789,26 +10849,26 @@ function ProductGrid({
10789
10849
  }) {
10790
10850
  const { nbHits } = (0, import_react_instantsearch3.useStats)();
10791
10851
  const { status, results } = (0, import_react_instantsearch3.useInstantSearch)();
10792
- const [announcement, setAnnouncement] = (0, import_react48.useState)("");
10852
+ const [announcement, setAnnouncement] = (0, import_react49.useState)("");
10793
10853
  const hitsCount = results?.hits?.length ?? 0;
10794
10854
  const showSkeleton = hitsCount === 0 && status !== "error";
10795
- (0, import_react48.useEffect)(() => {
10855
+ (0, import_react49.useEffect)(() => {
10796
10856
  const timer = setTimeout(() => {
10797
10857
  setAnnouncement(`${nbHits} ${nbHits === 1 ? "product" : "products"} found`);
10798
10858
  }, 1e3);
10799
10859
  return () => clearTimeout(timer);
10800
10860
  }, [nbHits]);
10801
- const HitComponent = (0, import_react48.useCallback)(({ hit }) => /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
10861
+ const HitComponent = (0, import_react49.useCallback)(({ hit }) => /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
10802
10862
  ProductHitComponent,
10803
10863
  {
10804
10864
  hit,
10805
10865
  variant
10806
10866
  }
10807
10867
  ), [variant]);
10808
- return /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)("div", { className, children: [
10809
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: "sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement }),
10810
- showSkeleton && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: `grid ${gridClassName}`, children: Array.from({ length: skeletonCount }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(ProductGridSkeletonItem, {}, i)) }),
10811
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("div", { className: showSkeleton ? "hidden" : "", children: /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
10868
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className, children: [
10869
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { className: "sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement }),
10870
+ showSkeleton && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { className: `grid ${gridClassName}`, children: Array.from({ length: skeletonCount }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(ProductGridSkeletonItem, {}, i)) }),
10871
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { className: showSkeleton ? "hidden" : "", children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
10812
10872
  import_react_instantsearch3.Hits,
10813
10873
  {
10814
10874
  hitComponent: HitComponent,
@@ -10823,18 +10883,18 @@ function ProductGrid({
10823
10883
  }
10824
10884
 
10825
10885
  // src/composed/search/Filters.tsx
10826
- var import_react50 = require("react");
10886
+ var import_react51 = require("react");
10827
10887
 
10828
10888
  // src/composed/search/FiltersButton.tsx
10829
10889
  var import_lucide_react4 = require("lucide-react");
10830
- var import_jsx_runtime65 = require("react/jsx-runtime");
10890
+ var import_jsx_runtime66 = require("react/jsx-runtime");
10831
10891
  var SlidersHorizontalIcon = import_lucide_react4.SlidersHorizontal;
10832
10892
  function FiltersButton({
10833
10893
  onClick,
10834
10894
  className = "",
10835
10895
  children = "Filters"
10836
10896
  }) {
10837
- return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
10897
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
10838
10898
  Button,
10839
10899
  {
10840
10900
  variant: "field",
@@ -10842,8 +10902,8 @@ function FiltersButton({
10842
10902
  className,
10843
10903
  "aria-label": "Open filters",
10844
10904
  children: [
10845
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(SlidersHorizontalIcon, { className: "w-4 h-4" }),
10846
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { children })
10905
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(SlidersHorizontalIcon, { className: "w-4 h-4" }),
10906
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { children })
10847
10907
  ]
10848
10908
  }
10849
10909
  );
@@ -10852,15 +10912,15 @@ function FiltersButton({
10852
10912
  // src/composed/search/FiltersDrawer.tsx
10853
10913
  var import_react_instantsearch4 = require("react-instantsearch");
10854
10914
  var import_lucide_react5 = require("lucide-react");
10855
- var import_react49 = require("react");
10915
+ var import_react50 = require("react");
10856
10916
  var Slider2 = __toESM(require("@radix-ui/react-slider"), 1);
10857
- var import_jsx_runtime66 = require("react/jsx-runtime");
10917
+ var import_jsx_runtime67 = require("react/jsx-runtime");
10858
10918
  var XIcon2 = import_lucide_react5.X;
10859
10919
  function FiltersDrawer({ isOpen, onClose }) {
10860
- const [showCounts, setShowCounts] = (0, import_react49.useState)(false);
10920
+ const [showCounts, setShowCounts] = (0, import_react50.useState)(false);
10861
10921
  const { nbHits } = (0, import_react_instantsearch4.useStats)();
10862
10922
  const containerRef = useFocusTrap(isOpen, onClose);
10863
- (0, import_react49.useEffect)(() => {
10923
+ (0, import_react50.useEffect)(() => {
10864
10924
  if (isOpen) {
10865
10925
  document.body.style.overflow = "hidden";
10866
10926
  } else {
@@ -10870,7 +10930,7 @@ function FiltersDrawer({ isOpen, onClose }) {
10870
10930
  document.body.style.overflow = "";
10871
10931
  };
10872
10932
  }, [isOpen]);
10873
- (0, import_react49.useEffect)(() => {
10933
+ (0, import_react50.useEffect)(() => {
10874
10934
  const handleEscape = (e) => {
10875
10935
  if (e.key === "Escape" && isOpen) {
10876
10936
  onClose();
@@ -10879,8 +10939,8 @@ function FiltersDrawer({ isOpen, onClose }) {
10879
10939
  document.addEventListener("keydown", handleEscape);
10880
10940
  return () => document.removeEventListener("keydown", handleEscape);
10881
10941
  }, [isOpen, onClose]);
10882
- return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(import_jsx_runtime66.Fragment, { children: [
10883
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
10942
+ return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(import_jsx_runtime67.Fragment, { children: [
10943
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
10884
10944
  "div",
10885
10945
  {
10886
10946
  className: `fixed inset-0 bg-black/50 z-40 transition-opacity ${isOpen ? "opacity-100" : "opacity-0 pointer-events-none"}`,
@@ -10888,7 +10948,7 @@ function FiltersDrawer({ isOpen, onClose }) {
10888
10948
  "aria-hidden": "true"
10889
10949
  }
10890
10950
  ),
10891
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
10951
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
10892
10952
  "div",
10893
10953
  {
10894
10954
  ref: containerRef,
@@ -10897,26 +10957,26 @@ function FiltersDrawer({ isOpen, onClose }) {
10897
10957
  "aria-modal": "true",
10898
10958
  "aria-labelledby": "filters-drawer-title",
10899
10959
  children: [
10900
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex items-center justify-between px-4 py-4", children: [
10901
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("h2", { id: "filters-drawer-title", className: "text-xl font-bold", children: "Filters" }),
10902
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
10960
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "flex items-center justify-between px-4 py-4", children: [
10961
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("h2", { id: "filters-drawer-title", className: "text-xl font-bold", children: "Filters" }),
10962
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
10903
10963
  "button",
10904
10964
  {
10905
10965
  onClick: onClose,
10906
10966
  className: "p-2 hover:bg-foreground/5 rounded-full transition-colors",
10907
10967
  "aria-label": "Close filters",
10908
- children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(XIcon2, { className: "w-5 h-5" })
10968
+ children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(XIcon2, { className: "w-5 h-5" })
10909
10969
  }
10910
10970
  )
10911
10971
  ] }),
10912
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { className: "px-4 pb-4", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("p", { className: "text-sm font-caption text-foreground/60", role: "status", "aria-live": "polite", children: [
10972
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("div", { className: "px-4 pb-4", children: /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("p", { className: "text-sm font-caption text-foreground/60", role: "status", "aria-live": "polite", children: [
10913
10973
  nbHits.toLocaleString(),
10914
10974
  " ",
10915
10975
  nbHits === 1 ? "result" : "results"
10916
10976
  ] }) }),
10917
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { className: "flex-1 overflow-y-auto px-4 pb-4", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex flex-col gap-8", children: [
10918
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(TagsSection, { showCounts, setShowCounts }),
10919
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(PriceSection, {})
10977
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("div", { className: "flex-1 overflow-y-auto px-4 pb-4", children: /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "flex flex-col gap-8", children: [
10978
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(TagsSection, { showCounts, setShowCounts }),
10979
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(PriceSection, {})
10920
10980
  ] }) })
10921
10981
  ]
10922
10982
  }
@@ -10932,9 +10992,9 @@ function TagsSection({
10932
10992
  sortBy: ["count:desc", "name:asc"],
10933
10993
  limit: 100
10934
10994
  });
10935
- const [isExpanded, setIsExpanded] = (0, import_react49.useState)(true);
10936
- return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "bg-foreground/5 rounded-lg p-4", children: [
10937
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
10995
+ const [isExpanded, setIsExpanded] = (0, import_react50.useState)(true);
10996
+ return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "bg-foreground/5 rounded-lg p-4", children: [
10997
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
10938
10998
  "button",
10939
10999
  {
10940
11000
  onClick: () => setIsExpanded(!isExpanded),
@@ -10942,8 +11002,8 @@ function TagsSection({
10942
11002
  "aria-expanded": isExpanded,
10943
11003
  "aria-controls": "tags-content",
10944
11004
  children: [
10945
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("h3", { className: "text-base font-semibold text-primary", children: "Tags" }),
10946
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
11005
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("h3", { className: "text-base font-semibold text-primary", children: "Tags" }),
11006
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
10947
11007
  "svg",
10948
11008
  {
10949
11009
  className: `w-5 h-5 transition-transform text-foreground/40 group-hover:text-foreground/60 ${isExpanded ? "rotate-180" : ""}`,
@@ -10952,14 +11012,14 @@ function TagsSection({
10952
11012
  stroke: "currentColor",
10953
11013
  strokeWidth: 2.5,
10954
11014
  "aria-hidden": "true",
10955
- children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" })
11015
+ children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" })
10956
11016
  }
10957
11017
  )
10958
11018
  ]
10959
11019
  }
10960
11020
  ),
10961
- isExpanded && /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-4", id: "tags-content", children: [
10962
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { className: "flex flex-wrap gap-2", role: "group", "aria-label": "Product tags filter", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
11021
+ isExpanded && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "space-y-4", id: "tags-content", children: [
11022
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("div", { className: "flex flex-wrap gap-2", role: "group", "aria-label": "Product tags filter", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
10963
11023
  "button",
10964
11024
  {
10965
11025
  onClick: () => refine(item.value),
@@ -10970,15 +11030,15 @@ function TagsSection({
10970
11030
  "aria-label": `${item.isRefined ? "Remove" : "Apply"} ${item.label} filter${showCounts ? ` (${item.count} products)` : ""}`,
10971
11031
  "aria-pressed": item.isRefined,
10972
11032
  children: [
10973
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { "aria-hidden": "true", children: item.label }),
10974
- showCounts && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: `text-xs font-caption ${item.isRefined ? "opacity-80" : "opacity-60"}`, "aria-hidden": "true", children: item.count })
11033
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { "aria-hidden": "true", children: item.label }),
11034
+ showCounts && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: `text-xs font-caption ${item.isRefined ? "opacity-80" : "opacity-60"}`, "aria-hidden": "true", children: item.count })
10975
11035
  ]
10976
11036
  },
10977
11037
  item.value
10978
11038
  )) }),
10979
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex items-center justify-between pt-2", children: [
10980
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "text-sm font-label text-foreground/60", id: "show-counts-label", children: "Show counts" }),
10981
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
11039
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "flex items-center justify-between pt-2", children: [
11040
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "text-sm font-label text-foreground/60", id: "show-counts-label", children: "Show counts" }),
11041
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
10982
11042
  "button",
10983
11043
  {
10984
11044
  onClick: () => setShowCounts(!showCounts),
@@ -10986,7 +11046,7 @@ function TagsSection({
10986
11046
  role: "switch",
10987
11047
  "aria-checked": showCounts,
10988
11048
  "aria-labelledby": "show-counts-label",
10989
- children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
11049
+ children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
10990
11050
  "span",
10991
11051
  {
10992
11052
  className: `inline-block h-4 w-4 transform rounded-full bg-background shadow-sm transition-transform ${showCounts ? "translate-x-6" : "translate-x-1"}`,
@@ -11003,11 +11063,11 @@ function PriceSection() {
11003
11063
  const { range, refine, start, canRefine } = (0, import_react_instantsearch4.useRange)({ attribute: "price" });
11004
11064
  const rangeMin = typeof range.min === "number" && isFinite(range.min) ? range.min : 0;
11005
11065
  const rangeMax = typeof range.max === "number" && isFinite(range.max) ? range.max : 15e3;
11006
- const [localRange, setLocalRange] = (0, import_react49.useState)([
11066
+ const [localRange, setLocalRange] = (0, import_react50.useState)([
11007
11067
  typeof start?.[0] === "number" && isFinite(start[0]) ? start[0] : rangeMin,
11008
11068
  typeof start?.[1] === "number" && isFinite(start[1]) ? start[1] : rangeMax
11009
11069
  ]);
11010
- (0, import_react49.useEffect)(() => {
11070
+ (0, import_react50.useEffect)(() => {
11011
11071
  if (start && Array.isArray(start)) {
11012
11072
  setLocalRange([
11013
11073
  typeof start[0] === "number" && isFinite(start[0]) ? start[0] : rangeMin,
@@ -11017,7 +11077,7 @@ function PriceSection() {
11017
11077
  setLocalRange([rangeMin, rangeMax]);
11018
11078
  }
11019
11079
  }, [start, rangeMin, rangeMax]);
11020
- const [isExpanded, setIsExpanded] = (0, import_react49.useState)(true);
11080
+ const [isExpanded, setIsExpanded] = (0, import_react50.useState)(true);
11021
11081
  if (!canRefine) {
11022
11082
  return null;
11023
11083
  }
@@ -11032,8 +11092,8 @@ function PriceSection() {
11032
11092
  return `$${priceInDollars.toFixed(2)}`;
11033
11093
  }
11034
11094
  };
11035
- return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "bg-foreground/5 rounded-lg p-4", children: [
11036
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
11095
+ return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "bg-foreground/5 rounded-lg p-4", children: [
11096
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
11037
11097
  "button",
11038
11098
  {
11039
11099
  onClick: () => setIsExpanded(!isExpanded),
@@ -11041,8 +11101,8 @@ function PriceSection() {
11041
11101
  "aria-expanded": isExpanded,
11042
11102
  "aria-controls": "price-content",
11043
11103
  children: [
11044
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("h3", { className: "text-base font-semibold text-primary", children: "Price" }),
11045
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
11104
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("h3", { className: "text-base font-semibold text-primary", children: "Price" }),
11105
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
11046
11106
  "svg",
11047
11107
  {
11048
11108
  className: `w-5 h-5 transition-transform text-foreground/40 group-hover:text-foreground/60 ${isExpanded ? "rotate-180" : ""}`,
@@ -11051,22 +11111,22 @@ function PriceSection() {
11051
11111
  stroke: "currentColor",
11052
11112
  strokeWidth: 2.5,
11053
11113
  "aria-hidden": "true",
11054
- children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" })
11114
+ children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" })
11055
11115
  }
11056
11116
  )
11057
11117
  ]
11058
11118
  }
11059
11119
  ),
11060
- isExpanded && /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "space-y-6", id: "price-content", children: [
11061
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "flex items-center justify-between text-sm font-display", children: [
11062
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { children: formatPrice2(localRange[0]) }),
11063
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "text-foreground/70", children: formatPrice2(localRange[1]) })
11120
+ isExpanded && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "space-y-6", id: "price-content", children: [
11121
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "flex items-center justify-between text-sm font-display", children: [
11122
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { children: formatPrice2(localRange[0]) }),
11123
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "text-foreground/70", children: formatPrice2(localRange[1]) })
11064
11124
  ] }),
11065
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { className: "relative h-24 flex items-end justify-between gap-0.5 px-1", "aria-hidden": "true", role: "presentation", children: [60, 40, 80, 50, 60, 30, 20, 15, 10, 5, 30, 20, 15, 10, 5, 3, 3, 60, 40].map((height, i) => {
11125
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("div", { className: "relative h-24 flex items-end justify-between gap-0.5 px-1", "aria-hidden": "true", role: "presentation", children: [60, 40, 80, 50, 60, 30, 20, 15, 10, 5, 30, 20, 15, 10, 5, 3, 3, 60, 40].map((height, i) => {
11066
11126
  const totalBars = 19;
11067
11127
  const barPrice = rangeMin + (rangeMax - rangeMin) / totalBars * i;
11068
11128
  const isInRange = barPrice >= localRange[0] && barPrice <= localRange[1];
11069
- return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
11129
+ return /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
11070
11130
  "div",
11071
11131
  {
11072
11132
  className: `flex-1 rounded-t-sm transition-opacity ${isInRange ? "bg-foreground" : "bg-foreground/20"}`,
@@ -11075,7 +11135,7 @@ function PriceSection() {
11075
11135
  i
11076
11136
  );
11077
11137
  }) }),
11078
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { style: { touchAction: "none" }, className: "my-6", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
11138
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("div", { style: { touchAction: "none" }, className: "my-6", children: /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
11079
11139
  Slider2.Root,
11080
11140
  {
11081
11141
  className: "relative flex w-full touch-none select-none items-center",
@@ -11093,8 +11153,8 @@ function PriceSection() {
11093
11153
  step: 1,
11094
11154
  minStepsBetweenThumbs: 1,
11095
11155
  children: [
11096
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Slider2.Track, { className: "relative h-3 w-full grow overflow-hidden rounded-full bg-foreground/20", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Slider2.Range, { className: "absolute h-full bg-foreground" }) }),
11097
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
11156
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(Slider2.Track, { className: "relative h-3 w-full grow overflow-hidden rounded-full bg-foreground/20", children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(Slider2.Range, { className: "absolute h-full bg-foreground" }) }),
11157
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
11098
11158
  Slider2.Thumb,
11099
11159
  {
11100
11160
  className: "block h-6 w-6 rounded-full bg-background shadow transition-all focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:pointer-events-none disabled:opacity-50 cursor-grab active:cursor-grabbing hover:scale-105 border-2 border-primary",
@@ -11108,7 +11168,7 @@ function PriceSection() {
11108
11168
  "aria-valuetext": formatPrice2(localRange[0])
11109
11169
  }
11110
11170
  ),
11111
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
11171
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
11112
11172
  Slider2.Thumb,
11113
11173
  {
11114
11174
  className: "block h-6 w-6 rounded-full bg-background shadow transition-all focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:pointer-events-none disabled:opacity-50 cursor-grab active:cursor-grabbing hover:scale-105 border-2 border-primary",
@@ -11125,10 +11185,10 @@ function PriceSection() {
11125
11185
  ]
11126
11186
  }
11127
11187
  ) }),
11128
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "grid grid-cols-2 gap-3", children: [
11129
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { children: [
11130
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("label", { htmlFor: "price-min", className: "text-xs font-label text-foreground/60 mb-1.5 block", children: "Min" }),
11131
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
11188
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "grid grid-cols-2 gap-3", children: [
11189
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { children: [
11190
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("label", { htmlFor: "price-min", className: "text-xs font-label text-foreground/60 mb-1.5 block", children: "Min" }),
11191
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
11132
11192
  "input",
11133
11193
  {
11134
11194
  id: "price-min",
@@ -11146,9 +11206,9 @@ function PriceSection() {
11146
11206
  }
11147
11207
  )
11148
11208
  ] }),
11149
- /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { children: [
11150
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("label", { htmlFor: "price-max", className: "text-xs font-label text-foreground/60 mb-1.5 block", children: "Max" }),
11151
- /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
11209
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { children: [
11210
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("label", { htmlFor: "price-max", className: "text-xs font-label text-foreground/60 mb-1.5 block", children: "Max" }),
11211
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
11152
11212
  "input",
11153
11213
  {
11154
11214
  id: "price-max",
@@ -11172,11 +11232,11 @@ function PriceSection() {
11172
11232
  }
11173
11233
 
11174
11234
  // src/composed/search/Filters.tsx
11175
- var import_jsx_runtime67 = require("react/jsx-runtime");
11235
+ var import_jsx_runtime68 = require("react/jsx-runtime");
11176
11236
  function Filters({ buttonClassName, buttonText }) {
11177
- const [isOpen, setIsOpen] = (0, import_react50.useState)(false);
11178
- return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(import_jsx_runtime67.Fragment, { children: [
11179
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
11237
+ const [isOpen, setIsOpen] = (0, import_react51.useState)(false);
11238
+ return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(import_jsx_runtime68.Fragment, { children: [
11239
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
11180
11240
  FiltersButton,
11181
11241
  {
11182
11242
  onClick: () => setIsOpen(true),
@@ -11184,14 +11244,14 @@ function Filters({ buttonClassName, buttonText }) {
11184
11244
  children: buttonText
11185
11245
  }
11186
11246
  ),
11187
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(FiltersDrawer, { isOpen, onClose: () => setIsOpen(false) })
11247
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(FiltersDrawer, { isOpen, onClose: () => setIsOpen(false) })
11188
11248
  ] });
11189
11249
  }
11190
11250
 
11191
11251
  // src/composed/search/CurrentRefinements.tsx
11192
11252
  var import_react_instantsearch5 = require("react-instantsearch");
11193
11253
  var import_lucide_react6 = require("lucide-react");
11194
- var import_jsx_runtime68 = require("react/jsx-runtime");
11254
+ var import_jsx_runtime69 = require("react/jsx-runtime");
11195
11255
  var XIcon3 = import_lucide_react6.X;
11196
11256
  function CurrentRefinements() {
11197
11257
  const { items, refine } = (0, import_react_instantsearch5.useCurrentRefinements)();
@@ -11237,15 +11297,15 @@ function CurrentRefinements() {
11237
11297
  if (allRefinements.length === 0) {
11238
11298
  return null;
11239
11299
  }
11240
- return /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "flex flex-wrap items-center gap-2 mb-4 -mt-1", role: "group", "aria-label": "Active filters", children: allRefinements.map((refinement, index) => /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
11300
+ return /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "flex flex-wrap items-center gap-2 mb-4 -mt-1", role: "group", "aria-label": "Active filters", children: allRefinements.map((refinement, index) => /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)(
11241
11301
  "button",
11242
11302
  {
11243
11303
  className: "bg-primary text-on-primary hover:bg-primary/90 inline-flex h-7 items-center gap-1.5 rounded-full px-3 text-sm transition-colors",
11244
11304
  onClick: () => refinement.refine(),
11245
11305
  "aria-label": `Remove filter: ${refinement.displayLabel}`,
11246
11306
  children: [
11247
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "truncate", children: refinement.displayLabel }),
11248
- /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(XIcon3, { className: "w-3 h-3" })
11307
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "truncate", children: refinement.displayLabel }),
11308
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(XIcon3, { className: "w-3 h-3" })
11249
11309
  ]
11250
11310
  },
11251
11311
  `${refinement.attribute}-${refinement.value}-${index}`
@@ -11269,12 +11329,12 @@ var FACET_SECTIONS = [
11269
11329
  ];
11270
11330
 
11271
11331
  // src/composed/zoom/ResponsiveZoom.tsx
11272
- var import_react53 = require("react");
11332
+ var import_react54 = require("react");
11273
11333
 
11274
11334
  // src/composed/zoom/ZoomOverlay.tsx
11275
- var import_react51 = require("react");
11335
+ var import_react52 = require("react");
11276
11336
  var import_lucide_react7 = require("lucide-react");
11277
- var import_jsx_runtime69 = require("react/jsx-runtime");
11337
+ var import_jsx_runtime70 = require("react/jsx-runtime");
11278
11338
  var PlusIcon2 = import_lucide_react7.Plus;
11279
11339
  var MinusIcon2 = import_lucide_react7.Minus;
11280
11340
  function ZoomOverlay({
@@ -11286,13 +11346,13 @@ function ZoomOverlay({
11286
11346
  className,
11287
11347
  style
11288
11348
  }) {
11289
- const [zoomedImageIndex, setZoomedImageIndex] = (0, import_react51.useState)(null);
11290
- const [zoomOrigin, setZoomOrigin] = (0, import_react51.useState)({ x: 50, y: 50 });
11291
- const [hoveredImageIndex, setHoveredImageIndex] = (0, import_react51.useState)(null);
11292
- const [cursorPos, setCursorPos] = (0, import_react51.useState)({ x: 0, y: 0 });
11293
- const [announcement, setAnnouncement] = (0, import_react51.useState)("");
11294
- const [isZooming, setIsZooming] = (0, import_react51.useState)(false);
11295
- const handleZoomClick = (0, import_react51.useCallback)(
11349
+ const [zoomedImageIndex, setZoomedImageIndex] = (0, import_react52.useState)(null);
11350
+ const [zoomOrigin, setZoomOrigin] = (0, import_react52.useState)({ x: 50, y: 50 });
11351
+ const [hoveredImageIndex, setHoveredImageIndex] = (0, import_react52.useState)(null);
11352
+ const [cursorPos, setCursorPos] = (0, import_react52.useState)({ x: 0, y: 0 });
11353
+ const [announcement, setAnnouncement] = (0, import_react52.useState)("");
11354
+ const [isZooming, setIsZooming] = (0, import_react52.useState)(false);
11355
+ const handleZoomClick = (0, import_react52.useCallback)(
11296
11356
  (e) => {
11297
11357
  e.stopPropagation();
11298
11358
  if (isLargeTouchDevice && onEnhancedViewer) {
@@ -11317,7 +11377,7 @@ function ZoomOverlay({
11317
11377
  },
11318
11378
  [zoomedImageIndex, isLargeTouchDevice, onEnhancedViewer, imageIndex]
11319
11379
  );
11320
- const handleZoomMouseMove = (0, import_react51.useCallback)(
11380
+ const handleZoomMouseMove = (0, import_react52.useCallback)(
11321
11381
  (e) => {
11322
11382
  setCursorPos({ x: e.clientX, y: e.clientY });
11323
11383
  if (zoomedImageIndex === imageIndex) {
@@ -11333,9 +11393,9 @@ function ZoomOverlay({
11333
11393
  const isZoomed = zoomedImageIndex === imageIndex;
11334
11394
  const isHovered = hoveredImageIndex === imageIndex;
11335
11395
  const cursorStyle = isLargeTouchDevice ? "pointer" : isTouchDevice ? "default" : "none";
11336
- return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)(import_jsx_runtime69.Fragment, { children: [
11337
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement }),
11338
- /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
11396
+ return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(import_jsx_runtime70.Fragment, { children: [
11397
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement }),
11398
+ /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11339
11399
  "div",
11340
11400
  {
11341
11401
  className,
@@ -11343,7 +11403,7 @@ function ZoomOverlay({
11343
11403
  ...style,
11344
11404
  position: "relative"
11345
11405
  },
11346
- children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
11406
+ children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11347
11407
  "div",
11348
11408
  {
11349
11409
  style: {
@@ -11366,7 +11426,7 @@ function ZoomOverlay({
11366
11426
  handleZoomClick(e);
11367
11427
  }
11368
11428
  },
11369
- children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
11429
+ children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11370
11430
  "div",
11371
11431
  {
11372
11432
  style: {
@@ -11382,7 +11442,7 @@ function ZoomOverlay({
11382
11442
  )
11383
11443
  }
11384
11444
  ),
11385
- isHovered && !isTouchDevice && /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
11445
+ isHovered && !isTouchDevice && /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11386
11446
  "div",
11387
11447
  {
11388
11448
  className: "fixed pointer-events-none z-50 hidden md:block",
@@ -11392,7 +11452,7 @@ function ZoomOverlay({
11392
11452
  transform: "translate(-50%, -50%)"
11393
11453
  },
11394
11454
  "aria-hidden": "true",
11395
- children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "bg-white dark:bg-gray-800 rounded-full p-2 shadow-sm dark:shadow-gray-950/50", children: isZoomed ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
11455
+ children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "bg-white dark:bg-gray-800 rounded-full p-2 shadow-sm dark:shadow-gray-950/50", children: isZoomed ? /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11396
11456
  MinusIcon2,
11397
11457
  {
11398
11458
  size: 20,
@@ -11400,7 +11460,7 @@ function ZoomOverlay({
11400
11460
  strokeWidth: 1.5,
11401
11461
  "aria-hidden": "true"
11402
11462
  }
11403
- ) : /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
11463
+ ) : /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11404
11464
  PlusIcon2,
11405
11465
  {
11406
11466
  size: 20,
@@ -11415,11 +11475,11 @@ function ZoomOverlay({
11415
11475
  }
11416
11476
 
11417
11477
  // src/composed/zoom/EnhancedImageViewer.tsx
11418
- var import_react52 = require("react");
11478
+ var import_react53 = require("react");
11419
11479
  var import_react_dom3 = require("react-dom");
11420
11480
  var import_react_zoom_pan_pinch = require("react-zoom-pan-pinch");
11421
11481
  var import_lucide_react8 = require("lucide-react");
11422
- var import_jsx_runtime70 = require("react/jsx-runtime");
11482
+ var import_jsx_runtime71 = require("react/jsx-runtime");
11423
11483
  var TransformWrapper = import_react_zoom_pan_pinch.TransformWrapper;
11424
11484
  var TransformComponent = import_react_zoom_pan_pinch.TransformComponent;
11425
11485
  var EnhancedImageViewer = ({
@@ -11430,17 +11490,17 @@ var EnhancedImageViewer = ({
11430
11490
  onIndexChange,
11431
11491
  currentIndex: propCurrentIndex
11432
11492
  }) => {
11433
- const [isMounted, setIsMounted] = (0, import_react52.useState)(false);
11434
- const [isClient, setIsClient] = (0, import_react52.useState)(false);
11435
- const [scale, setScale] = (0, import_react52.useState)({ initial: 1, min: 1, max: 8 });
11436
- const [cropDimensions, setCropDimensions] = (0, import_react52.useState)({ width: 0, height: 0 });
11437
- const [currentZoomScale, setCurrentZoomScale] = (0, import_react52.useState)(1);
11438
- const imgRef = (0, import_react52.useRef)(null);
11439
- const touchStartRef = (0, import_react52.useRef)(
11493
+ const [isMounted, setIsMounted] = (0, import_react53.useState)(false);
11494
+ const [isClient, setIsClient] = (0, import_react53.useState)(false);
11495
+ const [scale, setScale] = (0, import_react53.useState)({ initial: 1, min: 1, max: 8 });
11496
+ const [cropDimensions, setCropDimensions] = (0, import_react53.useState)({ width: 0, height: 0 });
11497
+ const [currentZoomScale, setCurrentZoomScale] = (0, import_react53.useState)(1);
11498
+ const imgRef = (0, import_react53.useRef)(null);
11499
+ const touchStartRef = (0, import_react53.useRef)(
11440
11500
  null
11441
11501
  );
11442
- const isSwipingRef = (0, import_react52.useRef)(false);
11443
- const calculateScale = (0, import_react52.useCallback)(() => {
11502
+ const isSwipingRef = (0, import_react53.useRef)(false);
11503
+ const calculateScale = (0, import_react53.useCallback)(() => {
11444
11504
  const viewport = {
11445
11505
  width: window.innerWidth,
11446
11506
  height: window.innerHeight
@@ -11452,10 +11512,10 @@ var EnhancedImageViewer = ({
11452
11512
  max: 8
11453
11513
  });
11454
11514
  }, []);
11455
- const handleImageLoad = (0, import_react52.useCallback)(() => {
11515
+ const handleImageLoad = (0, import_react53.useCallback)(() => {
11456
11516
  calculateScale();
11457
11517
  }, [calculateScale]);
11458
- (0, import_react52.useLayoutEffect)(() => {
11518
+ (0, import_react53.useLayoutEffect)(() => {
11459
11519
  setIsClient(true);
11460
11520
  setIsMounted(true);
11461
11521
  document.body.style.overflow = "hidden";
@@ -11464,17 +11524,17 @@ var EnhancedImageViewer = ({
11464
11524
  document.body.style.overflow = "";
11465
11525
  };
11466
11526
  }, [calculateScale]);
11467
- (0, import_react52.useEffect)(() => {
11527
+ (0, import_react53.useEffect)(() => {
11468
11528
  calculateScale();
11469
11529
  }, [calculateScale]);
11470
- (0, import_react52.useEffect)(() => {
11530
+ (0, import_react53.useEffect)(() => {
11471
11531
  const handleResize = () => {
11472
11532
  calculateScale();
11473
11533
  };
11474
11534
  window.addEventListener("resize", handleResize);
11475
11535
  return () => window.removeEventListener("resize", handleResize);
11476
11536
  }, [calculateScale]);
11477
- (0, import_react52.useEffect)(() => {
11537
+ (0, import_react53.useEffect)(() => {
11478
11538
  const handleKeyDown = (e) => {
11479
11539
  if (e.key === "Escape") {
11480
11540
  onClose();
@@ -11500,7 +11560,7 @@ var EnhancedImageViewer = ({
11500
11560
  document.addEventListener("keydown", handleKeyDown);
11501
11561
  return () => document.removeEventListener("keydown", handleKeyDown);
11502
11562
  }, [onClose, imageUrl, images, onIndexChange, propCurrentIndex]);
11503
- const handleSwipeNavigation = (0, import_react52.useCallback)(
11563
+ const handleSwipeNavigation = (0, import_react53.useCallback)(
11504
11564
  (direction) => {
11505
11565
  let currentIndex = propCurrentIndex !== void 0 ? propCurrentIndex : -1;
11506
11566
  if (currentIndex === -1) {
@@ -11521,7 +11581,7 @@ var EnhancedImageViewer = ({
11521
11581
  },
11522
11582
  [propCurrentIndex, images, imageUrl, onIndexChange]
11523
11583
  );
11524
- const handleTouchStart = (0, import_react52.useCallback)(
11584
+ const handleTouchStart = (0, import_react53.useCallback)(
11525
11585
  (e) => {
11526
11586
  const isAtInitialZoom = Math.abs(currentZoomScale - scale.initial) < 0.1;
11527
11587
  if (!isAtInitialZoom) return;
@@ -11535,7 +11595,7 @@ var EnhancedImageViewer = ({
11535
11595
  },
11536
11596
  [currentZoomScale, scale.initial]
11537
11597
  );
11538
- const handleTouchEnd = (0, import_react52.useCallback)(
11598
+ const handleTouchEnd = (0, import_react53.useCallback)(
11539
11599
  (e) => {
11540
11600
  if (!touchStartRef.current) return;
11541
11601
  const touch = e.changedTouches[0];
@@ -11559,12 +11619,12 @@ var EnhancedImageViewer = ({
11559
11619
  );
11560
11620
  if (!isMounted || !isClient) {
11561
11621
  return (0, import_react_dom3.createPortal)(
11562
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11622
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11563
11623
  "div",
11564
11624
  {
11565
11625
  className: "fixed inset-0 bg-black flex items-center justify-center",
11566
11626
  style: { zIndex: 999999 },
11567
- children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11627
+ children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11568
11628
  "div",
11569
11629
  {
11570
11630
  style: {
@@ -11580,7 +11640,7 @@ var EnhancedImageViewer = ({
11580
11640
  );
11581
11641
  }
11582
11642
  return (0, import_react_dom3.createPortal)(
11583
- /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(
11643
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(
11584
11644
  "div",
11585
11645
  {
11586
11646
  className: "fixed inset-0 bg-black flex items-center justify-center",
@@ -11589,7 +11649,7 @@ var EnhancedImageViewer = ({
11589
11649
  "aria-modal": "true",
11590
11650
  "aria-label": "Image viewer",
11591
11651
  children: [
11592
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11652
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11593
11653
  "button",
11594
11654
  {
11595
11655
  onClick: (e) => {
@@ -11615,10 +11675,10 @@ var EnhancedImageViewer = ({
11615
11675
  touchAction: "manipulation",
11616
11676
  marginBottom: "env(safe-area-inset-bottom, 0px)"
11617
11677
  },
11618
- children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(import_lucide_react8.X, { className: "w-7 h-7", strokeWidth: 2.5 })
11678
+ children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(import_lucide_react8.X, { className: "w-7 h-7", strokeWidth: 2.5 })
11619
11679
  }
11620
11680
  ),
11621
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11681
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11622
11682
  TransformWrapper,
11623
11683
  {
11624
11684
  initialScale: scale.initial,
@@ -11652,7 +11712,7 @@ var EnhancedImageViewer = ({
11652
11712
  onTransformed: (ref) => {
11653
11713
  setCurrentZoomScale(ref.state.scale);
11654
11714
  },
11655
- children: ({ zoomIn, zoomOut, resetTransform }) => /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(
11715
+ children: ({ zoomIn, zoomOut, resetTransform }) => /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(
11656
11716
  "div",
11657
11717
  {
11658
11718
  style: {
@@ -11665,14 +11725,14 @@ var EnhancedImageViewer = ({
11665
11725
  onTouchStart: handleTouchStart,
11666
11726
  onTouchEnd: handleTouchEnd,
11667
11727
  children: [
11668
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11728
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11669
11729
  TransformComponent,
11670
11730
  {
11671
11731
  wrapperStyle: {
11672
11732
  width: "100%",
11673
11733
  height: "100%"
11674
11734
  },
11675
- children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11735
+ children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11676
11736
  "div",
11677
11737
  {
11678
11738
  style: {
@@ -11683,8 +11743,8 @@ var EnhancedImageViewer = ({
11683
11743
  alignItems: "center",
11684
11744
  justifyContent: "center"
11685
11745
  },
11686
- children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11687
- "img",
11746
+ children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11747
+ SafeImg,
11688
11748
  {
11689
11749
  ref: imgRef,
11690
11750
  src: imageUrl,
@@ -11704,8 +11764,8 @@ var EnhancedImageViewer = ({
11704
11764
  )
11705
11765
  }
11706
11766
  ),
11707
- /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: "fixed bottom-5 left-0 right-0 z-50", children: [
11708
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "flex justify-center gap-2", children: (() => {
11767
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("div", { className: "fixed bottom-5 left-0 right-0 z-50", children: [
11768
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("div", { className: "flex justify-center gap-2", children: (() => {
11709
11769
  let currentIndex = propCurrentIndex !== void 0 ? propCurrentIndex : -1;
11710
11770
  if (currentIndex === -1) {
11711
11771
  currentIndex = images.findIndex(
@@ -11738,8 +11798,8 @@ var EnhancedImageViewer = ({
11738
11798
  };
11739
11799
  const nextIndex = findNextAvailableIndex(currentIndex, 1);
11740
11800
  const prevIndex = findNextAvailableIndex(currentIndex, -1);
11741
- return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(import_jsx_runtime70.Fragment, { children: [
11742
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11801
+ return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(import_jsx_runtime71.Fragment, { children: [
11802
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11743
11803
  "button",
11744
11804
  {
11745
11805
  onClick: () => {
@@ -11752,7 +11812,7 @@ var EnhancedImageViewer = ({
11752
11812
  className: `w-10 h-10 rounded-full shadow-lg flex items-center justify-center transition-all duration-200 ${prevIndex === -1 ? "bg-white/40 text-black opacity-50 cursor-not-allowed" : "bg-white/90 hover:bg-white text-black"}`,
11753
11813
  style: { touchAction: "manipulation" },
11754
11814
  "aria-label": "Previous image",
11755
- children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11815
+ children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11756
11816
  "svg",
11757
11817
  {
11758
11818
  className: "w-4 h-4",
@@ -11760,7 +11820,7 @@ var EnhancedImageViewer = ({
11760
11820
  stroke: "currentColor",
11761
11821
  viewBox: "0 0 24 24",
11762
11822
  "aria-hidden": "true",
11763
- children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11823
+ children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11764
11824
  "path",
11765
11825
  {
11766
11826
  strokeLinecap: "round",
@@ -11773,7 +11833,7 @@ var EnhancedImageViewer = ({
11773
11833
  )
11774
11834
  }
11775
11835
  ),
11776
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11836
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11777
11837
  "button",
11778
11838
  {
11779
11839
  onClick: () => {
@@ -11786,7 +11846,7 @@ var EnhancedImageViewer = ({
11786
11846
  className: `w-10 h-10 rounded-full shadow-lg flex items-center justify-center transition-all duration-200 ${nextIndex === -1 ? "bg-white/40 text-black opacity-50 cursor-not-allowed" : "bg-white/90 hover:bg-white text-black"}`,
11787
11847
  style: { touchAction: "manipulation" },
11788
11848
  "aria-label": "Next image",
11789
- children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11849
+ children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11790
11850
  "svg",
11791
11851
  {
11792
11852
  className: "w-4 h-4",
@@ -11794,7 +11854,7 @@ var EnhancedImageViewer = ({
11794
11854
  stroke: "currentColor",
11795
11855
  viewBox: "0 0 24 24",
11796
11856
  "aria-hidden": "true",
11797
- children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11857
+ children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11798
11858
  "path",
11799
11859
  {
11800
11860
  strokeLinecap: "round",
@@ -11809,7 +11869,7 @@ var EnhancedImageViewer = ({
11809
11869
  )
11810
11870
  ] });
11811
11871
  })() }),
11812
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { style: { position: "fixed", bottom: 20, left: 24, zIndex: 10, marginBottom: "env(safe-area-inset-bottom, 0px)" }, className: "h-10 px-3 rounded-full bg-white/90 text-black text-sm font-medium flex items-center justify-center shadow-lg", children: (() => {
11872
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("div", { style: { position: "fixed", bottom: 20, left: 24, zIndex: 10, marginBottom: "env(safe-area-inset-bottom, 0px)" }, className: "h-10 px-3 rounded-full bg-white/90 text-black text-sm font-medium flex items-center justify-center shadow-lg", children: (() => {
11813
11873
  const total = Math.max(images.length, 1);
11814
11874
  const current = propCurrentIndex !== void 0 ? Math.min(propCurrentIndex + 1, total) : 1;
11815
11875
  return `${current} / ${total}`;
@@ -11821,7 +11881,7 @@ var EnhancedImageViewer = ({
11821
11881
  },
11822
11882
  `${scale.initial}-${scale.min}-${scale.max}`
11823
11883
  ),
11824
- /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
11884
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11825
11885
  "div",
11826
11886
  {
11827
11887
  className: "absolute inset-0 bg-black",
@@ -11840,7 +11900,7 @@ var EnhancedImageViewer = ({
11840
11900
  };
11841
11901
 
11842
11902
  // src/composed/zoom/ResponsiveZoom.tsx
11843
- var import_jsx_runtime71 = require("react/jsx-runtime");
11903
+ var import_jsx_runtime72 = require("react/jsx-runtime");
11844
11904
  function ResponsiveZoom({
11845
11905
  imageIndex,
11846
11906
  children,
@@ -11850,11 +11910,11 @@ function ResponsiveZoom({
11850
11910
  imageUrl,
11851
11911
  alt = "Product image"
11852
11912
  }) {
11853
- const [isTouchDevice, setIsTouchDevice] = (0, import_react53.useState)(false);
11854
- const [showEnhancedViewer, setShowEnhancedViewer] = (0, import_react53.useState)(false);
11855
- const [viewerIndex, setViewerIndex] = (0, import_react53.useState)(0);
11856
- const [currentImageUrl, setCurrentImageUrl] = (0, import_react53.useState)(imageUrl || "");
11857
- (0, import_react53.useEffect)(() => {
11913
+ const [isTouchDevice, setIsTouchDevice] = (0, import_react54.useState)(false);
11914
+ const [showEnhancedViewer, setShowEnhancedViewer] = (0, import_react54.useState)(false);
11915
+ const [viewerIndex, setViewerIndex] = (0, import_react54.useState)(0);
11916
+ const [currentImageUrl, setCurrentImageUrl] = (0, import_react54.useState)(imageUrl || "");
11917
+ (0, import_react54.useEffect)(() => {
11858
11918
  const checkDeviceType = () => {
11859
11919
  const hasTouch = "ontouchstart" in window || navigator.maxTouchPoints > 0;
11860
11920
  setIsTouchDevice(hasTouch);
@@ -11881,8 +11941,8 @@ function ResponsiveZoom({
11881
11941
  }
11882
11942
  }
11883
11943
  };
11884
- return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(import_jsx_runtime71.Fragment, { children: [
11885
- isTouchDevice ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11944
+ return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(import_jsx_runtime72.Fragment, { children: [
11945
+ isTouchDevice ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
11886
11946
  "div",
11887
11947
  {
11888
11948
  className,
@@ -11899,7 +11959,7 @@ function ResponsiveZoom({
11899
11959
  },
11900
11960
  children
11901
11961
  }
11902
- ) : /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11962
+ ) : /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
11903
11963
  ZoomOverlay,
11904
11964
  {
11905
11965
  imageIndex,
@@ -11910,7 +11970,7 @@ function ResponsiveZoom({
11910
11970
  children
11911
11971
  }
11912
11972
  ),
11913
- showEnhancedViewer && isTouchDevice && currentImageUrl && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
11973
+ showEnhancedViewer && isTouchDevice && currentImageUrl && /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
11914
11974
  EnhancedImageViewer,
11915
11975
  {
11916
11976
  imageUrl: currentImageUrl,
@@ -11933,9 +11993,32 @@ function ResponsiveZoom({
11933
11993
  }
11934
11994
 
11935
11995
  // src/composed/carousels/MobileProductCarousel.tsx
11936
- var import_react54 = require("react");
11937
- var import_jsx_runtime72 = require("react/jsx-runtime");
11938
- var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarousel2({
11996
+ var import_react55 = require("react");
11997
+ var import_jsx_runtime73 = require("react/jsx-runtime");
11998
+ function StaticCarouselImage({
11999
+ src,
12000
+ alt,
12001
+ className
12002
+ }) {
12003
+ const [failed, setFailed] = (0, import_react55.useState)(false);
12004
+ if (failed || !src) {
12005
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: `bg-muted ${className ?? ""}`, role: "img", "aria-label": alt });
12006
+ }
12007
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12008
+ "img",
12009
+ {
12010
+ src,
12011
+ alt,
12012
+ crossOrigin: "anonymous",
12013
+ className,
12014
+ loading: "lazy",
12015
+ decoding: "async",
12016
+ draggable: false,
12017
+ onError: () => setFailed(true)
12018
+ }
12019
+ );
12020
+ }
12021
+ var MobileProductCarousel = (0, import_react55.memo)(function MobileProductCarousel2({
11939
12022
  images,
11940
12023
  currentIndex = 0,
11941
12024
  onIndexChange,
@@ -11950,42 +12033,42 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
11950
12033
  mockupWidth,
11951
12034
  onMockupUrlGenerated
11952
12035
  }) {
11953
- const [activeIndex, setActiveIndex] = (0, import_react54.useState)(currentIndex);
11954
- const [touchStart, setTouchStart] = (0, import_react54.useState)(
12036
+ const [activeIndex, setActiveIndex] = (0, import_react55.useState)(currentIndex);
12037
+ const [touchStart, setTouchStart] = (0, import_react55.useState)(
11955
12038
  null
11956
12039
  );
11957
- const [touchEnd, setTouchEnd] = (0, import_react54.useState)(
12040
+ const [touchEnd, setTouchEnd] = (0, import_react55.useState)(
11958
12041
  null
11959
12042
  );
11960
- const [showImageViewer, setShowImageViewer] = (0, import_react54.useState)(false);
11961
- const [viewerKey, setViewerKey] = (0, import_react54.useState)(0);
11962
- const [isDragging, setIsDragging] = (0, import_react54.useState)(false);
11963
- const [dragOffset, setDragOffset] = (0, import_react54.useState)(0);
11964
- const [isTransitioning, setIsTransitioning] = (0, import_react54.useState)(false);
11965
- const [isHorizontalSwipe, setIsHorizontalSwipe] = (0, import_react54.useState)(
12043
+ const [showImageViewer, setShowImageViewer] = (0, import_react55.useState)(false);
12044
+ const [viewerKey, setViewerKey] = (0, import_react55.useState)(0);
12045
+ const [isDragging, setIsDragging] = (0, import_react55.useState)(false);
12046
+ const [dragOffset, setDragOffset] = (0, import_react55.useState)(0);
12047
+ const [isTransitioning, setIsTransitioning] = (0, import_react55.useState)(false);
12048
+ const [isHorizontalSwipe, setIsHorizontalSwipe] = (0, import_react55.useState)(
11966
12049
  null
11967
12050
  );
11968
- const [isPeeking, setIsPeeking] = (0, import_react54.useState)(false);
11969
- const [isPeekReturning, setIsPeekReturning] = (0, import_react54.useState)(false);
11970
- const carouselRef = (0, import_react54.useRef)(null);
11971
- const indicatorRef = (0, import_react54.useRef)(null);
11972
- const touchStartRef = (0, import_react54.useRef)(
12051
+ const [isPeeking, setIsPeeking] = (0, import_react55.useState)(false);
12052
+ const [isPeekReturning, setIsPeekReturning] = (0, import_react55.useState)(false);
12053
+ const carouselRef = (0, import_react55.useRef)(null);
12054
+ const indicatorRef = (0, import_react55.useRef)(null);
12055
+ const touchStartRef = (0, import_react55.useRef)(
11973
12056
  null
11974
12057
  );
11975
- const horizontalGestureRef = (0, import_react54.useRef)(false);
11976
- const hasShownPeekRef = (0, import_react54.useRef)(false);
11977
- const hasSwipedThisSessionRef = (0, import_react54.useRef)(false);
11978
- const generatedUrlsRef = (0, import_react54.useRef)(/* @__PURE__ */ new Map());
11979
- const prevArtworkSrcRef = (0, import_react54.useRef)(currentArtwork?.src);
11980
- (0, import_react54.useEffect)(() => {
12058
+ const horizontalGestureRef = (0, import_react55.useRef)(false);
12059
+ const hasShownPeekRef = (0, import_react55.useRef)(false);
12060
+ const hasSwipedThisSessionRef = (0, import_react55.useRef)(false);
12061
+ const generatedUrlsRef = (0, import_react55.useRef)(/* @__PURE__ */ new Map());
12062
+ const prevArtworkSrcRef = (0, import_react55.useRef)(currentArtwork?.src);
12063
+ (0, import_react55.useEffect)(() => {
11981
12064
  if (currentArtwork?.src !== prevArtworkSrcRef.current) {
11982
12065
  generatedUrlsRef.current.clear();
11983
12066
  prevArtworkSrcRef.current = currentArtwork?.src;
11984
12067
  }
11985
12068
  }, [currentArtwork?.src]);
11986
- const onMockupUrlGeneratedRef = (0, import_react54.useRef)(onMockupUrlGenerated);
12069
+ const onMockupUrlGeneratedRef = (0, import_react55.useRef)(onMockupUrlGenerated);
11987
12070
  onMockupUrlGeneratedRef.current = onMockupUrlGenerated;
11988
- const handleUrlGenerated = (0, import_react54.useCallback)((mockupId, url) => {
12071
+ const handleUrlGenerated = (0, import_react55.useCallback)((mockupId, url) => {
11989
12072
  generatedUrlsRef.current.set(mockupId, url);
11990
12073
  onMockupUrlGeneratedRef.current?.(mockupId, url);
11991
12074
  }, []);
@@ -11993,24 +12076,24 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
11993
12076
  const shouldHideDots = stickyHeroContext?.shouldHideDots ?? false;
11994
12077
  const priorityContext = useMockupPriorityOptional();
11995
12078
  const realtimeContext = useRealtimeOptional();
11996
- const [urlUpdateCounter, setUrlUpdateCounter] = (0, import_react54.useState)(0);
11997
- (0, import_react54.useEffect)(() => {
12079
+ const [urlUpdateCounter, setUrlUpdateCounter] = (0, import_react55.useState)(0);
12080
+ (0, import_react55.useEffect)(() => {
11998
12081
  if (!realtimeContext?.subscribeMockupResults) return;
11999
12082
  const unsubscribe = realtimeContext.subscribeMockupResults(() => {
12000
12083
  setUrlUpdateCounter((c) => c + 1);
12001
12084
  });
12002
12085
  return unsubscribe;
12003
12086
  }, [realtimeContext?.subscribeMockupResults]);
12004
- const mockupIds = (0, import_react54.useMemo)(() => {
12087
+ const mockupIds = (0, import_react55.useMemo)(() => {
12005
12088
  return images.filter((img) => img.isRealMockup && img.mockupId).map((img) => img.mockupId);
12006
12089
  }, [images]);
12007
- const realtimeMockupUrls = (0, import_react54.useMemo)(() => {
12090
+ const realtimeMockupUrls = (0, import_react55.useMemo)(() => {
12008
12091
  if (!realtimeContext?.getMockupUrls || mockupIds.length === 0) {
12009
12092
  return {};
12010
12093
  }
12011
12094
  return realtimeContext.getMockupUrls(mockupIds);
12012
12095
  }, [realtimeContext?.getMockupUrls, mockupIds, urlUpdateCounter]);
12013
- const imagesWithRealtimeUrls = (0, import_react54.useMemo)(() => {
12096
+ const imagesWithRealtimeUrls = (0, import_react55.useMemo)(() => {
12014
12097
  return images.map((img) => {
12015
12098
  if (img.isRealMockup && img.mockupId && realtimeMockupUrls[img.mockupId]) {
12016
12099
  return {
@@ -12022,10 +12105,10 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12022
12105
  });
12023
12106
  }, [images, realtimeMockupUrls]);
12024
12107
  const minSwipeDistance = 50;
12025
- (0, import_react54.useEffect)(() => {
12108
+ (0, import_react55.useEffect)(() => {
12026
12109
  setActiveIndex(currentIndex);
12027
12110
  }, [currentIndex]);
12028
- (0, import_react54.useEffect)(() => {
12111
+ (0, import_react55.useEffect)(() => {
12029
12112
  if (!priorityContext) return;
12030
12113
  const realMockups = images.map((img, idx) => ({ img, originalIdx: idx })).filter(({ img }) => img.isRealMockup && img.mockupId);
12031
12114
  const mockupIdsList = realMockups.map(({ img }) => img.mockupId);
@@ -12053,7 +12136,7 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12053
12136
  priorityContext.clearMobileCarouselMode?.();
12054
12137
  };
12055
12138
  }, [priorityContext, activeIndex, images]);
12056
- (0, import_react54.useEffect)(() => {
12139
+ (0, import_react55.useEffect)(() => {
12057
12140
  const indicator = indicatorRef.current;
12058
12141
  if (!indicator) return;
12059
12142
  let ticking = false;
@@ -12094,7 +12177,7 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12094
12177
  }, []);
12095
12178
  const SWIPE_TRACKING_KEY = "carousel-swipe-tracking";
12096
12179
  const PDP_VIEWS_BEFORE_PEEK = 10;
12097
- const getSwipeTracking = (0, import_react54.useCallback)(() => {
12180
+ const getSwipeTracking = (0, import_react55.useCallback)(() => {
12098
12181
  try {
12099
12182
  const stored = localStorage.getItem(SWIPE_TRACKING_KEY);
12100
12183
  if (stored) {
@@ -12104,7 +12187,7 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12104
12187
  }
12105
12188
  return { viewsWithoutSwipe: 0, hasEverSwiped: false };
12106
12189
  }, []);
12107
- const recordSwipe = (0, import_react54.useCallback)(() => {
12190
+ const recordSwipe = (0, import_react55.useCallback)(() => {
12108
12191
  if (hasSwipedThisSessionRef.current) return;
12109
12192
  hasSwipedThisSessionRef.current = true;
12110
12193
  try {
@@ -12118,7 +12201,7 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12118
12201
  } catch {
12119
12202
  }
12120
12203
  }, []);
12121
- (0, import_react54.useEffect)(() => {
12204
+ (0, import_react55.useEffect)(() => {
12122
12205
  if (!enablePeekAnimation || images.length <= 1) return;
12123
12206
  const tracking = getSwipeTracking();
12124
12207
  const newViewCount = tracking.viewsWithoutSwipe + 1;
@@ -12159,14 +12242,14 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12159
12242
  clearTimeout(clearTimeout_);
12160
12243
  };
12161
12244
  }, [images.length, getSwipeTracking, enablePeekAnimation]);
12162
- const wasTapRef = (0, import_react54.useRef)(false);
12163
- const handleImageTap = (0, import_react54.useCallback)(() => {
12245
+ const wasTapRef = (0, import_react55.useRef)(false);
12246
+ const handleImageTap = (0, import_react55.useCallback)(() => {
12164
12247
  if (!enableZoom) return;
12165
12248
  setViewerKey((prev) => prev + 1);
12166
12249
  setShowImageViewer(true);
12167
12250
  onZoomChange?.(true);
12168
12251
  }, [enableZoom, onZoomChange]);
12169
- const calculateDragOffset = (0, import_react54.useCallback)(
12252
+ const calculateDragOffset = (0, import_react55.useCallback)(
12170
12253
  (startX, currentX, containerWidth) => {
12171
12254
  const distance = startX - currentX;
12172
12255
  const offsetPercent = distance / containerWidth * 100;
@@ -12191,7 +12274,7 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12191
12274
  },
12192
12275
  [activeIndex, images.length]
12193
12276
  );
12194
- const handleSwipeEnd = (0, import_react54.useCallback)(
12277
+ const handleSwipeEnd = (0, import_react55.useCallback)(
12195
12278
  (startX, endX, containerWidth) => {
12196
12279
  const distance = startX - endX;
12197
12280
  const distancePercent = Math.abs(distance) / containerWidth * 100;
@@ -12222,7 +12305,7 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12222
12305
  },
12223
12306
  [activeIndex, images.length, onIndexChange, recordSwipe]
12224
12307
  );
12225
- (0, import_react54.useEffect)(() => {
12308
+ (0, import_react55.useEffect)(() => {
12226
12309
  const container = carouselRef.current;
12227
12310
  if (!container) return;
12228
12311
  const handleTouchStart = (e) => {
@@ -12311,11 +12394,11 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12311
12394
  handleSwipeEnd,
12312
12395
  handleImageTap
12313
12396
  ]);
12314
- const mouseStartRef = (0, import_react54.useRef)(
12397
+ const mouseStartRef = (0, import_react55.useRef)(
12315
12398
  null
12316
12399
  );
12317
- const isMouseDraggingRef = (0, import_react54.useRef)(false);
12318
- (0, import_react54.useEffect)(() => {
12400
+ const isMouseDraggingRef = (0, import_react55.useRef)(false);
12401
+ (0, import_react55.useEffect)(() => {
12319
12402
  const container = carouselRef.current;
12320
12403
  if (!container) return;
12321
12404
  const handleMouseDown = (e) => {
@@ -12391,7 +12474,7 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12391
12474
  container.removeEventListener("mouseleave", handleMouseLeave);
12392
12475
  };
12393
12476
  }, [calculateDragOffset, handleSwipeEnd, handleImageTap]);
12394
- const goToSlide = (0, import_react54.useCallback)(
12477
+ const goToSlide = (0, import_react55.useCallback)(
12395
12478
  (index, withTransition = true) => {
12396
12479
  if (withTransition) {
12397
12480
  setIsTransitioning(true);
@@ -12409,16 +12492,16 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12409
12492
  },
12410
12493
  [onIndexChange]
12411
12494
  );
12412
- (0, import_react54.useEffect)(() => {
12495
+ (0, import_react55.useEffect)(() => {
12413
12496
  if (stickyHeroContext?.setCarouselIndicator && images.length > 1) {
12414
- const indicator = /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
12497
+ const indicator = /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12415
12498
  "div",
12416
12499
  {
12417
12500
  className: "w-full",
12418
12501
  role: "group",
12419
12502
  "aria-label": "Product image navigation",
12420
- children: /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "relative h-1", children: [
12421
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("div", { className: "flex h-full", children: images.map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
12503
+ children: /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "relative h-1", children: [
12504
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "flex h-full", children: images.map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12422
12505
  "button",
12423
12506
  {
12424
12507
  onClick: () => goToSlide(index),
@@ -12428,7 +12511,7 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12428
12511
  },
12429
12512
  index
12430
12513
  )) }),
12431
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
12514
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12432
12515
  "div",
12433
12516
  {
12434
12517
  className: "absolute top-0 h-full bg-primary transition-all duration-300 ease-out",
@@ -12451,10 +12534,10 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12451
12534
  };
12452
12535
  }, [activeIndex, images.length, goToSlide, stickyHeroContext]);
12453
12536
  if (!images || images.length === 0) {
12454
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("div", { className: "w-full aspect-video bg-muted rounded-lg" });
12537
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "w-full aspect-video bg-muted rounded-lg" });
12455
12538
  }
12456
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: `relative w-full h-full ${className}`, children: [
12457
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
12539
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: `relative w-full h-full ${className}`, children: [
12540
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12458
12541
  "div",
12459
12542
  {
12460
12543
  ref: carouselRef,
@@ -12472,7 +12555,7 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12472
12555
  role: "region",
12473
12556
  "aria-roledescription": "carousel",
12474
12557
  "aria-label": "Product images",
12475
- children: /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
12558
+ children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12476
12559
  "div",
12477
12560
  {
12478
12561
  className: `flex h-full ${isPeekReturning ? "transition-transform duration-300 ease-[cubic-bezier(0,0,0.2,1)]" : isPeeking ? "transition-transform duration-500 ease-[cubic-bezier(0.4,0,0.2,1)]" : isTransitioning || !isDragging ? "transition-transform duration-300 ease-[cubic-bezier(0.25,0.46,0.45,0.94)]" : ""}`,
@@ -12482,11 +12565,15 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12482
12565
  children: images.map((image, index) => {
12483
12566
  const DECODE_WINDOW = 1;
12484
12567
  const isWithinDecodeWindow = Math.abs(index - activeIndex) <= DECODE_WINDOW;
12485
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
12568
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12486
12569
  "div",
12487
12570
  {
12488
12571
  className: "w-full h-full flex-shrink-0 relative select-none",
12489
- children: !isWithinDecodeWindow ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("div", { className: "w-full h-full bg-muted" }) : image.isPlaceholder ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("div", { className: "w-full h-full bg-muted-foreground/20 animate-pulse" }) : image.isRealMockup && currentArtwork ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
12572
+ children: !isWithinDecodeWindow ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "w-full h-full bg-muted" }) : image.isPlaceholder ? (
12573
+ // Rainbow prism loader (same as the /create route) instead of
12574
+ // a flat pulse; fills this relative slide via inset:0.
12575
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(LoadingOverlayPrismCandyInline, { visible: true, variant: "light" })
12576
+ ) : image.isRealMockup && currentArtwork ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12490
12577
  HeroProductImage,
12491
12578
  {
12492
12579
  productId,
@@ -12498,16 +12585,12 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12498
12585
  onUrlGenerated: image.mockupId ? (url) => handleUrlGenerated(image.mockupId, url) : void 0,
12499
12586
  className: "w-full h-full object-cover cursor-pointer pointer-events-none"
12500
12587
  }
12501
- ) : image.isRealMockup && !currentArtwork ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("div", { className: "w-full h-full bg-muted animate-pulse" }) : /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
12502
- "img",
12588
+ ) : image.isRealMockup && !currentArtwork ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(LoadingOverlayPrismCandyInline, { visible: true, variant: "light" }) : /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12589
+ StaticCarouselImage,
12503
12590
  {
12504
12591
  src: image.src,
12505
- alt: image.label,
12506
- crossOrigin: "anonymous",
12507
- className: "w-full h-full object-cover cursor-pointer pointer-events-none",
12508
- loading: "lazy",
12509
- decoding: "async",
12510
- draggable: false
12592
+ alt: image.label ?? "",
12593
+ className: "w-full h-full object-cover cursor-pointer pointer-events-none"
12511
12594
  }
12512
12595
  )
12513
12596
  },
@@ -12518,7 +12601,7 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12518
12601
  )
12519
12602
  }
12520
12603
  ),
12521
- showIndicators && images.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
12604
+ showIndicators && images.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12522
12605
  "div",
12523
12606
  {
12524
12607
  ref: indicatorRef,
@@ -12526,8 +12609,8 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12526
12609
  className: "relative z-20 w-full",
12527
12610
  role: "group",
12528
12611
  "aria-label": "Product image navigation",
12529
- children: /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "relative h-1", children: [
12530
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("div", { className: "flex h-full absolute inset-0", children: images.map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
12612
+ children: /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "relative h-1", children: [
12613
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "flex h-full absolute inset-0", children: images.map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12531
12614
  "button",
12532
12615
  {
12533
12616
  onClick: () => goToSlide(index),
@@ -12537,7 +12620,7 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12537
12620
  },
12538
12621
  index
12539
12622
  )) }),
12540
- /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
12623
+ /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12541
12624
  "div",
12542
12625
  {
12543
12626
  className: `absolute top-0 h-full bg-foreground ${isPeekReturning ? "transition-all duration-300 ease-[cubic-bezier(0,0,0.2,1)]" : isPeeking ? "transition-all duration-500 ease-[cubic-bezier(0.4,0,0.2,1)]" : isDragging ? "" : "transition-all duration-300 ease-out"}`,
@@ -12572,7 +12655,7 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12572
12655
  naturalHeight: img.naturalHeight
12573
12656
  } : null;
12574
12657
  }).filter((img) => img !== null);
12575
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
12658
+ return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12576
12659
  EnhancedImageViewer,
12577
12660
  {
12578
12661
  imageUrl,
@@ -12611,8 +12694,8 @@ var MobileProductCarousel = (0, import_react54.memo)(function MobileProductCarou
12611
12694
  });
12612
12695
 
12613
12696
  // src/composed/carousels/HeroCarousel.tsx
12614
- var import_react55 = require("react");
12615
- var import_jsx_runtime73 = require("react/jsx-runtime");
12697
+ var import_react56 = require("react");
12698
+ var import_jsx_runtime74 = require("react/jsx-runtime");
12616
12699
  function HeroCarousel({
12617
12700
  images,
12618
12701
  currentIndex = 0,
@@ -12622,16 +12705,16 @@ function HeroCarousel({
12622
12705
  productId,
12623
12706
  onImageTap
12624
12707
  }) {
12625
- const [activeIndex, setActiveIndex] = (0, import_react55.useState)(currentIndex);
12626
- const containerRef = (0, import_react55.useRef)(null);
12627
- const touchStartRef = (0, import_react55.useRef)(
12708
+ const [activeIndex, setActiveIndex] = (0, import_react56.useState)(currentIndex);
12709
+ const containerRef = (0, import_react56.useRef)(null);
12710
+ const touchStartRef = (0, import_react56.useRef)(
12628
12711
  null
12629
12712
  );
12630
- const isSwipingRef = (0, import_react55.useRef)(false);
12631
- (0, import_react55.useEffect)(() => {
12713
+ const isSwipingRef = (0, import_react56.useRef)(false);
12714
+ (0, import_react56.useEffect)(() => {
12632
12715
  setActiveIndex(currentIndex);
12633
12716
  }, [currentIndex]);
12634
- const goToSlide = (0, import_react55.useCallback)(
12717
+ const goToSlide = (0, import_react56.useCallback)(
12635
12718
  (index) => {
12636
12719
  const clampedIndex = Math.max(0, Math.min(images.length - 1, index));
12637
12720
  setActiveIndex(clampedIndex);
@@ -12639,7 +12722,7 @@ function HeroCarousel({
12639
12722
  },
12640
12723
  [images.length, onIndexChange]
12641
12724
  );
12642
- (0, import_react55.useEffect)(() => {
12725
+ (0, import_react56.useEffect)(() => {
12643
12726
  const container = containerRef.current;
12644
12727
  if (!container) return;
12645
12728
  const handleTouchStart = (e) => {
@@ -12691,9 +12774,9 @@ function HeroCarousel({
12691
12774
  };
12692
12775
  }, [activeIndex, images.length, goToSlide, onImageTap]);
12693
12776
  if (!images || images.length === 0) {
12694
- return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("div", { className: "w-full h-full bg-muted" });
12777
+ return /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "w-full h-full bg-muted" });
12695
12778
  }
12696
- return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)(
12779
+ return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(
12697
12780
  "div",
12698
12781
  {
12699
12782
  ref: containerRef,
@@ -12704,7 +12787,7 @@ function HeroCarousel({
12704
12787
  overflow: "hidden"
12705
12788
  },
12706
12789
  children: [
12707
- /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12790
+ /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
12708
12791
  "div",
12709
12792
  {
12710
12793
  className: "flex h-full transition-transform duration-300 ease-out",
@@ -12715,14 +12798,14 @@ function HeroCarousel({
12715
12798
  backfaceVisibility: "hidden",
12716
12799
  WebkitBackfaceVisibility: "hidden"
12717
12800
  },
12718
- children: images.map((image, index) => /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12801
+ children: images.map((image, index) => /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
12719
12802
  "div",
12720
12803
  {
12721
12804
  className: "w-full h-full flex-shrink-0",
12722
12805
  style: {
12723
12806
  contain: "layout paint"
12724
12807
  },
12725
- children: image.isRealMockup && currentArtwork ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12808
+ children: image.isRealMockup && currentArtwork ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
12726
12809
  HeroProductImage,
12727
12810
  {
12728
12811
  productId,
@@ -12731,7 +12814,7 @@ function HeroCarousel({
12731
12814
  mockupId: image.mockupId,
12732
12815
  className: "w-full h-full object-cover"
12733
12816
  }
12734
- ) : /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12817
+ ) : /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
12735
12818
  "img",
12736
12819
  {
12737
12820
  src: image.src,
@@ -12748,12 +12831,12 @@ function HeroCarousel({
12748
12831
  ))
12749
12832
  }
12750
12833
  ),
12751
- images.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12834
+ images.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
12752
12835
  "div",
12753
12836
  {
12754
12837
  className: "absolute bottom-4 left-0 right-0 flex justify-center gap-2 z-10",
12755
12838
  style: { contain: "layout style" },
12756
- children: images.map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime73.jsx)(
12839
+ children: images.map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
12757
12840
  "button",
12758
12841
  {
12759
12842
  onClick: () => goToSlide(index),
@@ -12770,8 +12853,8 @@ function HeroCarousel({
12770
12853
  }
12771
12854
 
12772
12855
  // src/composed/grids/MasonryGrid.tsx
12773
- var import_react56 = require("react");
12774
- var import_jsx_runtime74 = require("react/jsx-runtime");
12856
+ var import_react57 = require("react");
12857
+ var import_jsx_runtime75 = require("react/jsx-runtime");
12775
12858
  var BREAKPOINTS = {
12776
12859
  sm: 640,
12777
12860
  md: 768,
@@ -12823,13 +12906,13 @@ function MasonryGrid({
12823
12906
  className = "",
12824
12907
  emptyContent
12825
12908
  }) {
12826
- const [columnCount, setColumnCount] = (0, import_react56.useState)(
12909
+ const [columnCount, setColumnCount] = (0, import_react57.useState)(
12827
12910
  () => typeof columns === "number" ? columns : getColumnCount(
12828
12911
  typeof window !== "undefined" ? window.innerWidth : 1024,
12829
12912
  columns
12830
12913
  )
12831
12914
  );
12832
- (0, import_react56.useEffect)(() => {
12915
+ (0, import_react57.useEffect)(() => {
12833
12916
  const updateColumnCount = () => {
12834
12917
  setColumnCount(getColumnCount(window.innerWidth, columns));
12835
12918
  };
@@ -12837,30 +12920,30 @@ function MasonryGrid({
12837
12920
  window.addEventListener("resize", updateColumnCount);
12838
12921
  return () => window.removeEventListener("resize", updateColumnCount);
12839
12922
  }, [columns]);
12840
- const distributedColumns = (0, import_react56.useMemo)(
12923
+ const distributedColumns = (0, import_react57.useMemo)(
12841
12924
  () => distributeItems(items, columnCount),
12842
12925
  [items, columnCount]
12843
12926
  );
12844
12927
  if (items.length === 0) {
12845
12928
  if (emptyContent) {
12846
- return /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(import_jsx_runtime74.Fragment, { children: emptyContent });
12929
+ return /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(import_jsx_runtime75.Fragment, { children: emptyContent });
12847
12930
  }
12848
12931
  return null;
12849
12932
  }
12850
- return /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
12933
+ return /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
12851
12934
  "div",
12852
12935
  {
12853
12936
  className: `flex ${className}`,
12854
12937
  style: { gap: `${gap}px` },
12855
12938
  role: "list",
12856
- children: distributedColumns.map((columnItems, columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
12939
+ children: distributedColumns.map((columnItems, columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
12857
12940
  "div",
12858
12941
  {
12859
12942
  className: "flex-1 flex flex-col",
12860
12943
  style: { gap: `${gap}px` },
12861
12944
  children: columnItems.map((item, itemIndex) => {
12862
12945
  const originalIndex = itemIndex * columnCount + columnIndex;
12863
- return /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { role: "listitem", children: renderItem(item, originalIndex) }, originalIndex);
12946
+ return /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("div", { role: "listitem", children: renderItem(item, originalIndex) }, originalIndex);
12864
12947
  })
12865
12948
  },
12866
12949
  columnIndex
@@ -12873,7 +12956,7 @@ function MasonryGrid({
12873
12956
  init_dev_warnings();
12874
12957
 
12875
12958
  // src/layouts/hero-zoom/HeroZoomLayout.tsx
12876
- var import_react58 = require("react");
12959
+ var import_react59 = require("react");
12877
12960
 
12878
12961
  // src/layouts/hero-zoom/types.ts
12879
12962
  var DEFAULT_HERO_ZOOM_CONFIG = {
@@ -12885,19 +12968,19 @@ var DEFAULT_HERO_ZOOM_CONFIG = {
12885
12968
  };
12886
12969
 
12887
12970
  // src/layouts/hero-zoom/useHeroZoomScales.ts
12888
- var import_react57 = require("react");
12971
+ var import_react58 = require("react");
12889
12972
  function useHeroZoomScales(config = {}) {
12890
12973
  const { initialScale, accountForRetina, maxRetinaMultiplier } = {
12891
12974
  ...DEFAULT_HERO_ZOOM_CONFIG,
12892
12975
  ...config
12893
12976
  };
12894
- const [isHydrated, setIsHydrated] = (0, import_react57.useState)(false);
12977
+ const [isHydrated, setIsHydrated] = (0, import_react58.useState)(false);
12895
12978
  const ssrMultiplier = accountForRetina ? maxRetinaMultiplier : 2;
12896
- const [scales, setScales] = (0, import_react57.useState)(() => ({
12979
+ const [scales, setScales] = (0, import_react58.useState)(() => ({
12897
12980
  visual: initialScale,
12898
12981
  render: initialScale * ssrMultiplier
12899
12982
  }));
12900
- const calculateScales = (0, import_react57.useCallback)(() => {
12983
+ const calculateScales = (0, import_react58.useCallback)(() => {
12901
12984
  const visualScale = Math.max(1, Math.min(4, initialScale));
12902
12985
  let renderScale;
12903
12986
  if (accountForRetina) {
@@ -12912,7 +12995,7 @@ function useHeroZoomScales(config = {}) {
12912
12995
  renderScale = Math.max(1, Math.min(8, renderScale));
12913
12996
  return { visual: visualScale, render: renderScale };
12914
12997
  }, [initialScale, accountForRetina, maxRetinaMultiplier]);
12915
- (0, import_react57.useEffect)(() => {
12998
+ (0, import_react58.useEffect)(() => {
12916
12999
  const supportsScrollTimeline = CSS.supports(
12917
13000
  "animation-timeline",
12918
13001
  "scroll()"
@@ -12962,7 +13045,7 @@ function useHeroZoomScales(config = {}) {
12962
13045
  }
12963
13046
 
12964
13047
  // src/layouts/hero-zoom/HeroZoomLayout.tsx
12965
- var import_jsx_runtime75 = require("react/jsx-runtime");
13048
+ var import_jsx_runtime76 = require("react/jsx-runtime");
12966
13049
  function HeroZoomLayout({
12967
13050
  config = {},
12968
13051
  header,
@@ -12977,9 +13060,9 @@ function HeroZoomLayout({
12977
13060
  };
12978
13061
  const { aspectRatio, initialScale, headerHeight } = mergedConfig;
12979
13062
  const { visual, render, isHydrated } = useHeroZoomScales(mergedConfig);
12980
- const imageContainerRef = (0, import_react58.useRef)(null);
12981
- const headerRef = (0, import_react58.useRef)(null);
12982
- (0, import_react58.useEffect)(() => {
13063
+ const imageContainerRef = (0, import_react59.useRef)(null);
13064
+ const headerRef = (0, import_react59.useRef)(null);
13065
+ (0, import_react59.useEffect)(() => {
12983
13066
  if (typeof window === "undefined") return;
12984
13067
  const originalRestoration = "scrollRestoration" in history ? history.scrollRestoration : "auto";
12985
13068
  if ("scrollRestoration" in history) {
@@ -12992,7 +13075,7 @@ function HeroZoomLayout({
12992
13075
  }
12993
13076
  };
12994
13077
  }, []);
12995
- (0, import_react58.useEffect)(() => {
13078
+ (0, import_react59.useEffect)(() => {
12996
13079
  const supportsScrollTimeline = CSS.supports(
12997
13080
  "animation-timeline",
12998
13081
  "scroll()"
@@ -13121,7 +13204,7 @@ function HeroZoomLayout({
13121
13204
  The drawer covers the hero completely, so let animation run continuously. */
13122
13205
  }
13123
13206
  `;
13124
- return /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)(
13207
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(
13125
13208
  "div",
13126
13209
  {
13127
13210
  className: `relative min-h-screen ${className}`,
@@ -13135,8 +13218,8 @@ function HeroZoomLayout({
13135
13218
  "--hero-zoom-final-transform": 1 / activeRender
13136
13219
  },
13137
13220
  children: [
13138
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("style", { dangerouslySetInnerHTML: { __html: scopedStyles } }),
13139
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
13221
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("style", { dangerouslySetInnerHTML: { __html: scopedStyles } }),
13222
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
13140
13223
  "div",
13141
13224
  {
13142
13225
  style: {
@@ -13144,7 +13227,7 @@ function HeroZoomLayout({
13144
13227
  }
13145
13228
  }
13146
13229
  ),
13147
- header && /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
13230
+ header && /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
13148
13231
  "div",
13149
13232
  {
13150
13233
  ref: headerRef,
@@ -13157,7 +13240,7 @@ function HeroZoomLayout({
13157
13240
  children: header
13158
13241
  }
13159
13242
  ),
13160
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(
13243
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
13161
13244
  "div",
13162
13245
  {
13163
13246
  ref: imageContainerRef,
@@ -13177,15 +13260,15 @@ function HeroZoomLayout({
13177
13260
  children: hero
13178
13261
  }
13179
13262
  ),
13180
- /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("div", { className: "relative z-10", children })
13263
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("div", { className: "relative z-10", children })
13181
13264
  ]
13182
13265
  }
13183
13266
  );
13184
13267
  }
13185
13268
 
13186
13269
  // src/layouts/hero-zoom/HeroShrinkLayout.tsx
13187
- var import_react59 = require("react");
13188
- var import_jsx_runtime76 = require("react/jsx-runtime");
13270
+ var import_react60 = require("react");
13271
+ var import_jsx_runtime77 = require("react/jsx-runtime");
13189
13272
  var DEFAULT_CONFIG = {
13190
13273
  aspectRatio: 16 / 9,
13191
13274
  initialHeightPercent: 70,
@@ -13205,13 +13288,13 @@ function HeroShrinkLayout({
13205
13288
  ...config
13206
13289
  };
13207
13290
  const { aspectRatio, initialHeightPercent, minHeightPercent, headerHeight } = mergedConfig;
13208
- const heroRef = (0, import_react59.useRef)(null);
13209
- const headerRef = (0, import_react59.useRef)(null);
13210
- const [isClient, setIsClient] = (0, import_react59.useState)(false);
13211
- (0, import_react59.useEffect)(() => {
13291
+ const heroRef = (0, import_react60.useRef)(null);
13292
+ const headerRef = (0, import_react60.useRef)(null);
13293
+ const [isClient, setIsClient] = (0, import_react60.useState)(false);
13294
+ (0, import_react60.useEffect)(() => {
13212
13295
  setIsClient(true);
13213
13296
  }, []);
13214
- (0, import_react59.useEffect)(() => {
13297
+ (0, import_react60.useEffect)(() => {
13215
13298
  if (!isClient) return;
13216
13299
  const supportsScrollTimeline = CSS.supports("animation-timeline", "scroll()");
13217
13300
  if (supportsScrollTimeline) return;
@@ -13298,15 +13381,15 @@ function HeroShrinkLayout({
13298
13381
  }
13299
13382
  `;
13300
13383
  const spacerHeight = `calc(${initialHeightPercent}svh + ${headerHeight}px)`;
13301
- return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(
13384
+ return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(
13302
13385
  "div",
13303
13386
  {
13304
13387
  className: `relative min-h-screen ${className}`,
13305
13388
  style: { ...style, ...cssVars },
13306
13389
  children: [
13307
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("style", { dangerouslySetInnerHTML: { __html: scopedStyles } }),
13308
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("div", { style: { height: spacerHeight } }),
13309
- header && /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
13390
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("style", { dangerouslySetInnerHTML: { __html: scopedStyles } }),
13391
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("div", { style: { height: spacerHeight } }),
13392
+ header && /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
13310
13393
  "div",
13311
13394
  {
13312
13395
  ref: headerRef,
@@ -13315,7 +13398,7 @@ function HeroShrinkLayout({
13315
13398
  children: header
13316
13399
  }
13317
13400
  ),
13318
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
13401
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
13319
13402
  "div",
13320
13403
  {
13321
13404
  ref: heroRef,
@@ -13323,15 +13406,15 @@ function HeroShrinkLayout({
13323
13406
  children: hero
13324
13407
  }
13325
13408
  ),
13326
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("div", { className: "relative z-10 bg-background", children })
13409
+ /* @__PURE__ */ (0, import_jsx_runtime77.jsx)("div", { className: "relative z-10 bg-background", children })
13327
13410
  ]
13328
13411
  }
13329
13412
  );
13330
13413
  }
13331
13414
 
13332
13415
  // src/layouts/pdp/ImageEdgeBlur.tsx
13333
- var import_react60 = __toESM(require("react"), 1);
13334
- var import_jsx_runtime77 = require("react/jsx-runtime");
13416
+ var import_react61 = __toESM(require("react"), 1);
13417
+ var import_jsx_runtime78 = require("react/jsx-runtime");
13335
13418
  var BLUR_CONFIG = {
13336
13419
  blur: 24,
13337
13420
  crossfade: 68
@@ -13355,7 +13438,7 @@ var BLUR_LAYERS = [
13355
13438
  { blur: Math.round(BLUR_CONFIG.blur * 0.5), zone: 0.6 },
13356
13439
  { blur: BLUR_CONFIG.blur, zone: 1 }
13357
13440
  ];
13358
- var ImageEdgeBlur = import_react60.default.memo(
13441
+ var ImageEdgeBlur = import_react61.default.memo(
13359
13442
  function ImageEdgeBlur2({
13360
13443
  imageSrc,
13361
13444
  imageCapInfo,
@@ -13386,7 +13469,7 @@ var ImageEdgeBlur = import_react60.default.memo(
13386
13469
  viewportWidth / LAYOUT_CONFIG2.IMAGE.ASPECT_RATIO,
13387
13470
  maxWidthPx / LAYOUT_CONFIG2.IMAGE.ASPECT_RATIO
13388
13471
  );
13389
- return /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
13472
+ return /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(
13390
13473
  "div",
13391
13474
  {
13392
13475
  className: `absolute inset-0 pointer-events-none overflow-hidden ${className}`,
@@ -13394,7 +13477,7 @@ var ImageEdgeBlur = import_react60.default.memo(
13394
13477
  children: BLUR_LAYERS.map((layer, index) => {
13395
13478
  const layerMask = index === BLUR_LAYERS.length - 1 ? void 0 : `linear-gradient(to right, black 0%, black ${layer.zone * 100}%, transparent ${layer.zone * 100 + 10}%)`;
13396
13479
  const blurScale = 1 + layer.blur * 3 / containerHeightPx;
13397
- return /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
13480
+ return /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(
13398
13481
  "img",
13399
13482
  {
13400
13483
  src: imageSrc,
@@ -13441,7 +13524,7 @@ var ImageEdgeBlur = import_react60.default.memo(
13441
13524
  );
13442
13525
 
13443
13526
  // src/layouts/pdp/PDPLayout.tsx
13444
- var import_jsx_runtime78 = require("react/jsx-runtime");
13527
+ var import_jsx_runtime79 = require("react/jsx-runtime");
13445
13528
  function PDPLayout({
13446
13529
  renderHeroImage,
13447
13530
  renderContent,
@@ -13469,15 +13552,15 @@ function PDPLayout({
13469
13552
  isDesktop,
13470
13553
  isWideMonitor: isWideMonitor2
13471
13554
  };
13472
- return /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: `pdp-layout ${className}`, children: [
13473
- (isDesktop === false || isDesktop === null) && /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "md:hidden", children: [
13474
- renderMobileCarousel && /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("div", { className: "mobile-carousel-container", children: renderMobileCarousel({ images: carouselImages }) }),
13475
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("div", { className: "mobile-content p-4", children: renderContent(contentProps) })
13555
+ return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: `pdp-layout ${className}`, children: [
13556
+ (isDesktop === false || isDesktop === null) && /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "md:hidden", children: [
13557
+ renderMobileCarousel && /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "mobile-carousel-container", children: renderMobileCarousel({ images: carouselImages }) }),
13558
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "mobile-content p-4", children: renderContent(contentProps) })
13476
13559
  ] }),
13477
- (isDesktop === true || isDesktop === null) && /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "hidden md:block relative", children: [
13478
- /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "desktop-hero relative", children: [
13560
+ (isDesktop === true || isDesktop === null) && /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "hidden md:block relative", children: [
13561
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "desktop-hero relative", children: [
13479
13562
  renderHeroImage(heroProps),
13480
- showEdgeBlur && blurImageSrc && isWideMonitor2 && /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(
13563
+ showEdgeBlur && blurImageSrc && isWideMonitor2 && /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
13481
13564
  ImageEdgeBlur,
13482
13565
  {
13483
13566
  imageSrc: blurImageSrc,
@@ -13488,7 +13571,7 @@ function PDPLayout({
13488
13571
  }
13489
13572
  )
13490
13573
  ] }),
13491
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(
13574
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
13492
13575
  "div",
13493
13576
  {
13494
13577
  className: "desktop-sidebar",
@@ -13505,8 +13588,8 @@ function PDPLayout({
13505
13588
  }
13506
13589
 
13507
13590
  // src/layouts/pdp/SimpleImageBlur.tsx
13508
- var import_react61 = __toESM(require("react"), 1);
13509
- var import_jsx_runtime79 = require("react/jsx-runtime");
13591
+ var import_react62 = __toESM(require("react"), 1);
13592
+ var import_jsx_runtime80 = require("react/jsx-runtime");
13510
13593
  var BLUR_CONFIG2 = {
13511
13594
  blur: 24,
13512
13595
  crossfade: 60
@@ -13529,7 +13612,7 @@ function getFadeInMask(crossfadeWidth) {
13529
13612
  black ${crossfadeWidth + 10}px
13530
13613
  )`;
13531
13614
  }
13532
- var SimpleImageBlur = import_react61.default.memo(function SimpleImageBlur2({
13615
+ var SimpleImageBlur = import_react62.default.memo(function SimpleImageBlur2({
13533
13616
  imageSrc,
13534
13617
  width,
13535
13618
  height = "100%",
@@ -13539,7 +13622,7 @@ var SimpleImageBlur = import_react61.default.memo(function SimpleImageBlur2({
13539
13622
  if (!imageSrc || width <= 0) return null;
13540
13623
  const fadeInMask = getFadeInMask(BLUR_CONFIG2.crossfade);
13541
13624
  const extendedWidth = width + BLUR_CONFIG2.blur * 2;
13542
- return /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
13625
+ return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
13543
13626
  "div",
13544
13627
  {
13545
13628
  className: `relative overflow-hidden ${className}`,
@@ -13552,7 +13635,7 @@ var SimpleImageBlur = import_react61.default.memo(function SimpleImageBlur2({
13552
13635
  black 0%,
13553
13636
  black ${layer.zone * 100}%,
13554
13637
  transparent ${layer.zone * 100 + 10}%)`;
13555
- return /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
13638
+ return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
13556
13639
  "img",
13557
13640
  {
13558
13641
  src: imageSrc,
@@ -13582,8 +13665,8 @@ var SimpleImageBlur = import_react61.default.memo(function SimpleImageBlur2({
13582
13665
  });
13583
13666
 
13584
13667
  // src/layouts/pdp/EdgeBlurBox.tsx
13585
- var import_react62 = __toESM(require("react"), 1);
13586
- var import_jsx_runtime80 = require("react/jsx-runtime");
13668
+ var import_react63 = __toESM(require("react"), 1);
13669
+ var import_jsx_runtime81 = require("react/jsx-runtime");
13587
13670
  var BLUR_CONFIG3 = {
13588
13671
  blur: 24,
13589
13672
  crossfade: 60
@@ -13607,7 +13690,7 @@ function getFadeOutMask(crossfadeWidth) {
13607
13690
  transparent 100%
13608
13691
  )`;
13609
13692
  }
13610
- var EdgeBlurBox = import_react62.default.memo(function EdgeBlurBox2({
13693
+ var EdgeBlurBox = import_react63.default.memo(function EdgeBlurBox2({
13611
13694
  imageSrc,
13612
13695
  width,
13613
13696
  height = "100%",
@@ -13622,7 +13705,7 @@ var EdgeBlurBox = import_react62.default.memo(function EdgeBlurBox2({
13622
13705
  const blurExtend = BLUR_CONFIG3.blur * 2;
13623
13706
  const actualSharpWidth = sharpImageWidth ?? width + overlapLeft;
13624
13707
  const hasOverlap = overlapLeft > 0;
13625
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(
13708
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(
13626
13709
  "div",
13627
13710
  {
13628
13711
  className: `relative ${className}`,
@@ -13633,7 +13716,7 @@ var EdgeBlurBox = import_react62.default.memo(function EdgeBlurBox2({
13633
13716
  overflow: hasOverlap ? "visible" : "hidden"
13634
13717
  },
13635
13718
  children: [
13636
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
13719
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
13637
13720
  "div",
13638
13721
  {
13639
13722
  style: {
@@ -13647,7 +13730,7 @@ var EdgeBlurBox = import_react62.default.memo(function EdgeBlurBox2({
13647
13730
  transparent ${100 - (layer.zone * 100 + 10)}%,
13648
13731
  black ${100 - layer.zone * 100}%,
13649
13732
  black 100%)`;
13650
- return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
13733
+ return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
13651
13734
  "img",
13652
13735
  {
13653
13736
  src: imageSrc,
@@ -13675,7 +13758,7 @@ var EdgeBlurBox = import_react62.default.memo(function EdgeBlurBox2({
13675
13758
  })
13676
13759
  }
13677
13760
  ),
13678
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
13761
+ /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
13679
13762
  "img",
13680
13763
  {
13681
13764
  src: imageSrc,
@@ -13703,8 +13786,8 @@ var EdgeBlurBox = import_react62.default.memo(function EdgeBlurBox2({
13703
13786
  });
13704
13787
 
13705
13788
  // src/layouts/pdp/ImageBlurExtension.tsx
13706
- var import_react63 = __toESM(require("react"), 1);
13707
- var import_jsx_runtime81 = require("react/jsx-runtime");
13789
+ var import_react64 = __toESM(require("react"), 1);
13790
+ var import_jsx_runtime82 = require("react/jsx-runtime");
13708
13791
  var BLUR_CONFIG4 = {
13709
13792
  blur: 24,
13710
13793
  crossfadeWidth: 80
@@ -13727,7 +13810,7 @@ function getFadeOutMask2(crossfadeWidth) {
13727
13810
  transparent 100%
13728
13811
  )`;
13729
13812
  }
13730
- var ImageBlurExtension = import_react63.default.memo(function ImageBlurExtension2({
13813
+ var ImageBlurExtension = import_react64.default.memo(function ImageBlurExtension2({
13731
13814
  imageSrc,
13732
13815
  width,
13733
13816
  height,
@@ -13741,7 +13824,7 @@ var ImageBlurExtension = import_react63.default.memo(function ImageBlurExtension
13741
13824
  const internalImageLeft = `calc(${heroImageLeft} - 100vw + ${width}px)`;
13742
13825
  const fadeOutMask = getFadeOutMask2(crossfadeWidth);
13743
13826
  const heightValue = typeof height === "number" ? `${height}px` : height;
13744
- return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(
13827
+ return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(
13745
13828
  "div",
13746
13829
  {
13747
13830
  className: `relative overflow-hidden ${className}`,
@@ -13750,7 +13833,7 @@ var ImageBlurExtension = import_react63.default.memo(function ImageBlurExtension
13750
13833
  height: heightValue
13751
13834
  },
13752
13835
  children: [
13753
- BLUR_LAYERS4.map((layer, index) => /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
13836
+ BLUR_LAYERS4.map((layer, index) => /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
13754
13837
  "img",
13755
13838
  {
13756
13839
  src: imageSrc,
@@ -13774,7 +13857,7 @@ var ImageBlurExtension = import_react63.default.memo(function ImageBlurExtension
13774
13857
  },
13775
13858
  `blur-${index}`
13776
13859
  )),
13777
- /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
13860
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
13778
13861
  "img",
13779
13862
  {
13780
13863
  src: imageSrc,
@@ -13802,39 +13885,39 @@ var ImageBlurExtension = import_react63.default.memo(function ImageBlurExtension
13802
13885
  });
13803
13886
 
13804
13887
  // src/design-system/ColorSwatch.tsx
13805
- var import_jsx_runtime82 = require("react/jsx-runtime");
13888
+ var import_jsx_runtime83 = require("react/jsx-runtime");
13806
13889
  function ColorTokenSwatch({ name, cssVar, className = "" }) {
13807
- return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: `flex flex-col gap-1 ${className}`, children: [
13808
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
13890
+ return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: `flex flex-col gap-1 ${className}`, children: [
13891
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
13809
13892
  "div",
13810
13893
  {
13811
13894
  className: "h-16 w-full rounded-lg border border-border shadow-sm",
13812
13895
  style: { backgroundColor: `var(${cssVar})` }
13813
13896
  }
13814
13897
  ),
13815
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "text-sm font-medium text-foreground", children: name }),
13816
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("code", { className: "text-xs text-muted-foreground font-mono", children: cssVar })
13898
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "text-sm font-medium text-foreground", children: name }),
13899
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("code", { className: "text-xs text-muted-foreground font-mono", children: cssVar })
13817
13900
  ] });
13818
13901
  }
13819
13902
  function ColorRow({ name, cssVar, description }) {
13820
- return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "flex items-center gap-4 py-2", children: [
13821
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
13903
+ return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "flex items-center gap-4 py-2", children: [
13904
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
13822
13905
  "div",
13823
13906
  {
13824
13907
  className: "h-10 w-10 rounded-lg border border-border shadow-sm flex-shrink-0",
13825
13908
  style: { backgroundColor: `var(${cssVar})` }
13826
13909
  }
13827
13910
  ),
13828
- /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "flex-1 min-w-0", children: [
13829
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "text-sm font-medium text-foreground", children: name }),
13830
- description && /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "text-xs text-muted-foreground", children: description })
13911
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "flex-1 min-w-0", children: [
13912
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "text-sm font-medium text-foreground", children: name }),
13913
+ description && /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "text-xs text-muted-foreground", children: description })
13831
13914
  ] }),
13832
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("code", { className: "text-xs text-muted-foreground font-mono bg-muted px-2 py-1 rounded", children: cssVar })
13915
+ /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("code", { className: "text-xs text-muted-foreground font-mono bg-muted px-2 py-1 rounded", children: cssVar })
13833
13916
  ] });
13834
13917
  }
13835
13918
 
13836
13919
  // src/design-system/ColorPalette.tsx
13837
- var import_jsx_runtime83 = require("react/jsx-runtime");
13920
+ var import_jsx_runtime84 = require("react/jsx-runtime");
13838
13921
  var COLOR_GROUPS = [
13839
13922
  {
13840
13923
  name: "Base",
@@ -13915,17 +13998,17 @@ var COLOR_GROUPS = [
13915
13998
  }
13916
13999
  ];
13917
14000
  function ColorPalette({ layout = "list", className = "" }) {
13918
- return /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: `space-y-8 ${className}`, children: COLOR_GROUPS.map((group) => /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("section", { children: [
13919
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("h3", { className: "text-lg font-semibold text-foreground mb-1", children: group.name }),
13920
- /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("p", { className: "text-sm text-muted-foreground mb-4", children: group.description }),
13921
- layout === "grid" ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "grid grid-cols-2 sm:grid-cols-4 gap-4", children: group.colors.map((color) => /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
14001
+ return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: `space-y-8 ${className}`, children: COLOR_GROUPS.map((group) => /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("section", { children: [
14002
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("h3", { className: "text-lg font-semibold text-foreground mb-1", children: group.name }),
14003
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("p", { className: "text-sm text-muted-foreground mb-4", children: group.description }),
14004
+ layout === "grid" ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "grid grid-cols-2 sm:grid-cols-4 gap-4", children: group.colors.map((color) => /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
13922
14005
  ColorTokenSwatch,
13923
14006
  {
13924
14007
  name: color.name,
13925
14008
  cssVar: color.cssVar
13926
14009
  },
13927
14010
  color.cssVar
13928
- )) }) : /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "bg-card rounded-lg border border-border p-4 divide-y divide-border", children: group.colors.map((color) => /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
14011
+ )) }) : /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "bg-card rounded-lg border border-border p-4 divide-y divide-border", children: group.colors.map((color) => /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
13929
14012
  ColorRow,
13930
14013
  {
13931
14014
  name: color.name,
@@ -13938,7 +14021,7 @@ function ColorPalette({ layout = "list", className = "" }) {
13938
14021
  }
13939
14022
 
13940
14023
  // src/design-system/TypographyScale.tsx
13941
- var import_jsx_runtime84 = require("react/jsx-runtime");
14024
+ var import_jsx_runtime85 = require("react/jsx-runtime");
13942
14025
  var FONT_SAMPLES = [
13943
14026
  {
13944
14027
  name: "Heading",
@@ -13972,14 +14055,14 @@ var FONT_SAMPLES = [
13972
14055
  }
13973
14056
  ];
13974
14057
  function TypographyScale({ className = "" }) {
13975
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: `space-y-8 ${className}`, children: FONT_SAMPLES.map((font) => /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("section", { className: "bg-card rounded-lg border border-border p-6", children: [
13976
- /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
13977
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("h3", { className: "text-lg font-semibold text-foreground", children: font.name }),
13978
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("code", { className: "text-xs text-muted-foreground font-mono bg-muted px-2 py-1 rounded", children: font.cssVar })
14058
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: `space-y-8 ${className}`, children: FONT_SAMPLES.map((font) => /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("section", { className: "bg-card rounded-lg border border-border p-6", children: [
14059
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
14060
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("h3", { className: "text-lg font-semibold text-foreground", children: font.name }),
14061
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("code", { className: "text-xs text-muted-foreground font-mono bg-muted px-2 py-1 rounded", children: font.cssVar })
13979
14062
  ] }),
13980
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "space-y-4", children: font.sizes.map((size) => /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "flex items-baseline gap-4", children: [
13981
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "text-xs text-muted-foreground w-20 flex-shrink-0", children: size }),
13982
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
14063
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: "space-y-4", children: font.sizes.map((size) => /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "flex items-baseline gap-4", children: [
14064
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "text-xs text-muted-foreground w-20 flex-shrink-0", children: size }),
14065
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
13983
14066
  "p",
13984
14067
  {
13985
14068
  className: `${size} text-foreground`,
@@ -13998,8 +14081,8 @@ var RADIUS_SAMPLES = [
13998
14081
  { name: "Full", value: "9999px" }
13999
14082
  ];
14000
14083
  function RadiusScale({ className = "" }) {
14001
- return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: `space-y-4 ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "grid grid-cols-5 gap-4", children: RADIUS_SAMPLES.map((radius) => /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "flex flex-col items-center gap-2", children: [
14002
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
14084
+ return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: `space-y-4 ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: "grid grid-cols-5 gap-4", children: RADIUS_SAMPLES.map((radius) => /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "flex flex-col items-center gap-2", children: [
14085
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
14003
14086
  "div",
14004
14087
  {
14005
14088
  className: "h-16 w-16 bg-primary",
@@ -14008,13 +14091,13 @@ function RadiusScale({ className = "" }) {
14008
14091
  }
14009
14092
  }
14010
14093
  ),
14011
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "text-sm font-medium text-foreground", children: radius.name }),
14012
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("code", { className: "text-xs text-muted-foreground font-mono", children: radius.cssVar || radius.value })
14094
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "text-sm font-medium text-foreground", children: radius.name }),
14095
+ /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("code", { className: "text-xs text-muted-foreground font-mono", children: radius.cssVar || radius.value })
14013
14096
  ] }, radius.name)) }) });
14014
14097
  }
14015
14098
 
14016
14099
  // src/design-system/ThemeSwitcher.tsx
14017
- var import_react64 = require("react");
14100
+ var import_react65 = require("react");
14018
14101
 
14019
14102
  // src/themes/types.ts
14020
14103
  var RADIUS_PRESETS = {
@@ -15182,7 +15265,7 @@ function applyTheme(config) {
15182
15265
  }
15183
15266
 
15184
15267
  // src/design-system/ThemeSwitcher.tsx
15185
- var import_jsx_runtime85 = require("react/jsx-runtime");
15268
+ var import_jsx_runtime86 = require("react/jsx-runtime");
15186
15269
  function readThemeFromDOM() {
15187
15270
  if (typeof document === "undefined") {
15188
15271
  return { themeName: "Linear", isDark: false };
@@ -15200,10 +15283,10 @@ function readThemeFromDOM() {
15200
15283
  return { themeName: "Linear", isDark: dark };
15201
15284
  }
15202
15285
  function ThemeSwitcher({ className = "", showBaseThemesOnly = true }) {
15203
- const [currentTheme, setCurrentTheme] = (0, import_react64.useState)("Linear");
15204
- const [isDark, setIsDark] = (0, import_react64.useState)(false);
15205
- const [isOpen, setIsOpen] = (0, import_react64.useState)(false);
15206
- (0, import_react64.useEffect)(() => {
15286
+ const [currentTheme, setCurrentTheme] = (0, import_react65.useState)("Linear");
15287
+ const [isDark, setIsDark] = (0, import_react65.useState)(false);
15288
+ const [isOpen, setIsOpen] = (0, import_react65.useState)(false);
15289
+ (0, import_react65.useEffect)(() => {
15207
15290
  const { themeName, isDark: dark } = readThemeFromDOM();
15208
15291
  setCurrentTheme(themeName);
15209
15292
  setIsDark(dark);
@@ -15242,61 +15325,61 @@ function ThemeSwitcher({ className = "", showBaseThemesOnly = true }) {
15242
15325
  applyTheme(config);
15243
15326
  };
15244
15327
  const themes = showBaseThemesOnly ? baseThemes : baseThemes;
15245
- return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: `flex items-center gap-3 ${className}`, children: [
15246
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("div", { className: "relative", children: [
15247
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
15328
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: `flex items-center gap-3 ${className}`, children: [
15329
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "relative", children: [
15330
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
15248
15331
  "button",
15249
15332
  {
15250
15333
  onClick: () => setIsOpen(!isOpen),
15251
15334
  className: "flex items-center gap-2 px-4 py-2 bg-card border border-border rounded-lg hover:bg-muted transition-colors text-foreground",
15252
15335
  children: [
15253
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01" }) }),
15254
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "font-medium", children: currentTheme }),
15255
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("svg", { className: `w-4 h-4 transition-transform ${isOpen ? "rotate-180" : ""}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) })
15336
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01" }) }),
15337
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "font-medium", children: currentTheme }),
15338
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("svg", { className: `w-4 h-4 transition-transform ${isOpen ? "rotate-180" : ""}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) })
15256
15339
  ]
15257
15340
  }
15258
15341
  ),
15259
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(import_jsx_runtime85.Fragment, { children: [
15260
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
15342
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(import_jsx_runtime86.Fragment, { children: [
15343
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
15261
15344
  "div",
15262
15345
  {
15263
15346
  className: "fixed inset-0 z-40",
15264
15347
  onClick: () => setIsOpen(false)
15265
15348
  }
15266
15349
  ),
15267
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("div", { className: "absolute top-full left-0 mt-2 w-56 max-h-80 overflow-auto bg-card border border-border rounded-lg shadow-lg z-50", children: themes.map((theme) => /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
15350
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "absolute top-full left-0 mt-2 w-56 max-h-80 overflow-auto bg-card border border-border rounded-lg shadow-lg z-50", children: themes.map((theme) => /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
15268
15351
  "button",
15269
15352
  {
15270
15353
  onClick: () => handleThemeSelect(theme.name),
15271
15354
  className: `w-full px-4 py-2 text-left hover:bg-muted transition-colors flex items-center gap-3 ${currentTheme === theme.name ? "bg-muted" : ""}`,
15272
15355
  children: [
15273
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
15356
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
15274
15357
  "div",
15275
15358
  {
15276
15359
  className: "w-4 h-4 rounded-full border border-border",
15277
15360
  style: { backgroundColor: theme.primaryColor || "#888" }
15278
15361
  }
15279
15362
  ),
15280
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "text-foreground", children: theme.name }),
15281
- currentTheme === theme.name && /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("svg", { className: "w-4 h-4 ml-auto text-primary", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) })
15363
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "text-foreground", children: theme.name }),
15364
+ currentTheme === theme.name && /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("svg", { className: "w-4 h-4 ml-auto text-primary", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) })
15282
15365
  ]
15283
15366
  },
15284
15367
  theme.name
15285
15368
  )) })
15286
15369
  ] })
15287
15370
  ] }),
15288
- /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
15371
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
15289
15372
  "button",
15290
15373
  {
15291
15374
  onClick: handleDarkModeToggle,
15292
15375
  className: "flex items-center gap-2 px-4 py-2 bg-card border border-border rounded-lg hover:bg-muted transition-colors text-foreground",
15293
15376
  title: `Switch to ${isDark ? "light" : "dark"} mode`,
15294
15377
  children: [
15295
- isDark ? /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: [
15296
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("circle", { cx: "12", cy: "12", r: "5" }),
15297
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("path", { d: "M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" })
15298
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" }) }),
15299
- /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "text-sm", children: isDark ? "Light" : "Dark" })
15378
+ isDark ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: [
15379
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("circle", { cx: "12", cy: "12", r: "5" }),
15380
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("path", { d: "M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" })
15381
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" }) }),
15382
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "text-sm", children: isDark ? "Light" : "Dark" })
15300
15383
  ]
15301
15384
  }
15302
15385
  )
@@ -15304,7 +15387,7 @@ function ThemeSwitcher({ className = "", showBaseThemesOnly = true }) {
15304
15387
  }
15305
15388
 
15306
15389
  // src/design-system/DesignSystemPage.tsx
15307
- var import_jsx_runtime86 = require("react/jsx-runtime");
15390
+ var import_jsx_runtime87 = require("react/jsx-runtime");
15308
15391
  function DesignSystemPage({
15309
15392
  showThemeSwitcher = true,
15310
15393
  showColors = true,
@@ -15314,29 +15397,29 @@ function DesignSystemPage({
15314
15397
  colorLayout = "list",
15315
15398
  className = ""
15316
15399
  }) {
15317
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: `max-w-4xl mx-auto px-4 py-8 ${className}`, children: [
15318
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("header", { className: "mb-12", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-4", children: [
15319
- /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { children: [
15320
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("h1", { className: "text-4xl font-bold text-foreground mb-2", children: "Design System" }),
15321
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("p", { className: "text-lg text-muted-foreground", children: "Visual reference for theme tokens and styles" })
15400
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: `max-w-4xl mx-auto px-4 py-8 ${className}`, children: [
15401
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("header", { className: "mb-12", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-4", children: [
15402
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { children: [
15403
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("h1", { className: "text-4xl font-bold text-foreground mb-2", children: "Design System" }),
15404
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("p", { className: "text-lg text-muted-foreground", children: "Visual reference for theme tokens and styles" })
15322
15405
  ] }),
15323
- showThemeSwitcher && /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(ThemeSwitcher, {})
15406
+ showThemeSwitcher && /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(ThemeSwitcher, {})
15324
15407
  ] }) }),
15325
- showColors && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("section", { className: "mb-16", children: [
15326
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("h2", { className: "text-2xl font-semibold text-foreground mb-6 pb-2 border-b border-border", children: "Color Palette" }),
15327
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(ColorPalette, { layout: colorLayout })
15408
+ showColors && /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("section", { className: "mb-16", children: [
15409
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("h2", { className: "text-2xl font-semibold text-foreground mb-6 pb-2 border-b border-border", children: "Color Palette" }),
15410
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(ColorPalette, { layout: colorLayout })
15328
15411
  ] }),
15329
- showTypography && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("section", { className: "mb-16", children: [
15330
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("h2", { className: "text-2xl font-semibold text-foreground mb-6 pb-2 border-b border-border", children: "Typography" }),
15331
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(TypographyScale, {})
15412
+ showTypography && /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("section", { className: "mb-16", children: [
15413
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("h2", { className: "text-2xl font-semibold text-foreground mb-6 pb-2 border-b border-border", children: "Typography" }),
15414
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(TypographyScale, {})
15332
15415
  ] }),
15333
- showRadius && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("section", { className: "mb-16", children: [
15334
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("h2", { className: "text-2xl font-semibold text-foreground mb-6 pb-2 border-b border-border", children: "Border Radius" }),
15335
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(RadiusScale, {})
15416
+ showRadius && /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("section", { className: "mb-16", children: [
15417
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("h2", { className: "text-2xl font-semibold text-foreground mb-6 pb-2 border-b border-border", children: "Border Radius" }),
15418
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(RadiusScale, {})
15336
15419
  ] }),
15337
- showSpacing && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("section", { className: "mb-16", children: [
15338
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("h2", { className: "text-2xl font-semibold text-foreground mb-6 pb-2 border-b border-border", children: "Spacing Scale" }),
15339
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(SpacingScale, {})
15420
+ showSpacing && /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("section", { className: "mb-16", children: [
15421
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("h2", { className: "text-2xl font-semibold text-foreground mb-6 pb-2 border-b border-border", children: "Spacing Scale" }),
15422
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(SpacingScale, {})
15340
15423
  ] })
15341
15424
  ] });
15342
15425
  }
@@ -15351,31 +15434,31 @@ function SpacingScale() {
15351
15434
  { name: "12", value: "3rem" },
15352
15435
  { name: "16", value: "4rem" }
15353
15436
  ];
15354
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "space-y-2", children: spaces.map((space) => /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex items-center gap-4", children: [
15355
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("code", { className: "text-xs text-muted-foreground font-mono w-8", children: space.name }),
15356
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
15437
+ return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "space-y-2", children: spaces.map((space) => /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "flex items-center gap-4", children: [
15438
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("code", { className: "text-xs text-muted-foreground font-mono w-8", children: space.name }),
15439
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
15357
15440
  "div",
15358
15441
  {
15359
15442
  className: "h-4 bg-primary rounded",
15360
15443
  style: { width: space.value }
15361
15444
  }
15362
15445
  ),
15363
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "text-sm text-muted-foreground", children: space.value })
15446
+ /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "text-sm text-muted-foreground", children: space.value })
15364
15447
  ] }, space.name)) });
15365
15448
  }
15366
15449
 
15367
15450
  // src/personalization/PersonalizationProvider.tsx
15368
- var import_react67 = __toESM(require("react"), 1);
15451
+ var import_react68 = __toESM(require("react"), 1);
15369
15452
 
15370
15453
  // src/personalization/PersonalizationContext.ts
15371
- var import_react65 = require("react");
15372
- var PersonalizationContext = (0, import_react65.createContext)(null);
15454
+ var import_react66 = require("react");
15455
+ var PersonalizationContext = (0, import_react66.createContext)(null);
15373
15456
  function usePersonalizationContext() {
15374
- return (0, import_react65.useContext)(PersonalizationContext);
15457
+ return (0, import_react66.useContext)(PersonalizationContext);
15375
15458
  }
15376
15459
 
15377
15460
  // src/personalization/utils.ts
15378
- var import_react66 = require("react");
15461
+ var import_react67 = require("react");
15379
15462
  function normalizeHex(color) {
15380
15463
  let hex = color.trim().toUpperCase();
15381
15464
  if (hex.length === 4 && hex.startsWith("#")) {
@@ -15396,8 +15479,8 @@ function isValidImageUrl(url) {
15396
15479
  }
15397
15480
  }
15398
15481
  function useDebouncedValue(value, delay) {
15399
- const [debounced, setDebounced] = (0, import_react66.useState)(value);
15400
- (0, import_react66.useEffect)(() => {
15482
+ const [debounced, setDebounced] = (0, import_react67.useState)(value);
15483
+ (0, import_react67.useEffect)(() => {
15401
15484
  const timer = setTimeout(() => setDebounced(value), delay);
15402
15485
  return () => clearTimeout(timer);
15403
15486
  }, [value, delay]);
@@ -15418,18 +15501,18 @@ function scrollInputAboveKeyboard(input) {
15418
15501
  }
15419
15502
 
15420
15503
  // src/personalization/PersonalizationProvider.tsx
15421
- var import_jsx_runtime87 = require("react/jsx-runtime");
15504
+ var import_jsx_runtime88 = require("react/jsx-runtime");
15422
15505
  function createBridgeFromCanvas(canvasModule) {
15423
15506
  const { useEditor, useCommands, useImageBinding } = canvasModule;
15424
15507
  function TextBinder({ name, value }) {
15425
15508
  const { elements } = useEditor();
15426
15509
  const { executeElementUpdate } = useCommands();
15427
- const elementsRef = import_react67.default.useRef(elements);
15510
+ const elementsRef = import_react68.default.useRef(elements);
15428
15511
  elementsRef.current = elements;
15429
- const executeRef = import_react67.default.useRef(executeElementUpdate);
15512
+ const executeRef = import_react68.default.useRef(executeElementUpdate);
15430
15513
  executeRef.current = executeElementUpdate;
15431
- const hasUserInput = import_react67.default.useRef(false);
15432
- import_react67.default.useEffect(() => {
15514
+ const hasUserInput = import_react68.default.useRef(false);
15515
+ import_react68.default.useEffect(() => {
15433
15516
  if (value == null) return;
15434
15517
  if (value === "" && !hasUserInput.current) return;
15435
15518
  hasUserInput.current = true;
@@ -15447,12 +15530,12 @@ function createBridgeFromCanvas(canvasModule) {
15447
15530
  function ColorBinder({ originalColor, newColor }) {
15448
15531
  const { elements } = useEditor();
15449
15532
  const { executeElementUpdate } = useCommands();
15450
- const elementsRef = import_react67.default.useRef(elements);
15533
+ const elementsRef = import_react68.default.useRef(elements);
15451
15534
  elementsRef.current = elements;
15452
- const executeRef = import_react67.default.useRef(executeElementUpdate);
15535
+ const executeRef = import_react68.default.useRef(executeElementUpdate);
15453
15536
  executeRef.current = executeElementUpdate;
15454
- const appliedColorRef = import_react67.default.useRef(normalizeHex(originalColor));
15455
- import_react67.default.useEffect(() => {
15537
+ const appliedColorRef = import_react68.default.useRef(normalizeHex(originalColor));
15538
+ import_react68.default.useEffect(() => {
15456
15539
  const normalizedNew = normalizeHex(newColor);
15457
15540
  if (normalizedNew === appliedColorRef.current) return;
15458
15541
  const matchColor = appliedColorRef.current;
@@ -15492,11 +15575,11 @@ function createBridgeFromCanvas(canvasModule) {
15492
15575
  }
15493
15576
  function ImageBinder({ name, value, fit = "cover" }) {
15494
15577
  const { setImageUrl } = useImageBinding(name, { fit });
15495
- const hasUserInput = import_react67.default.useRef(false);
15578
+ const hasUserInput = import_react68.default.useRef(false);
15496
15579
  const debouncedValue = useDebouncedValue(value, 500);
15497
- const setImageUrlRef = import_react67.default.useRef(setImageUrl);
15580
+ const setImageUrlRef = import_react68.default.useRef(setImageUrl);
15498
15581
  setImageUrlRef.current = setImageUrl;
15499
- import_react67.default.useEffect(() => {
15582
+ import_react68.default.useEffect(() => {
15500
15583
  if (debouncedValue == null) return;
15501
15584
  if (debouncedValue === "" && !hasUserInput.current) return;
15502
15585
  hasUserInput.current = true;
@@ -15506,15 +15589,15 @@ function createBridgeFromCanvas(canvasModule) {
15506
15589
  return null;
15507
15590
  }
15508
15591
  return function PersonalizationBridge({ fields = [], values = {} } = {}) {
15509
- return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_jsx_runtime87.Fragment, { children: fields.map((field) => {
15592
+ return /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(import_jsx_runtime88.Fragment, { children: fields.map((field) => {
15510
15593
  if (field.type === "text") {
15511
- return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(TextBinder, { name: field.name, value: values[field.name] ?? "" }, `text-${field.name}`);
15594
+ return /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(TextBinder, { name: field.name, value: values[field.name] ?? "" }, `text-${field.name}`);
15512
15595
  }
15513
15596
  if (field.type === "color") {
15514
- return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(ColorBinder, { originalColor: field.color, newColor: values[field.color] ?? field.color }, `color-${field.color}`);
15597
+ return /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(ColorBinder, { originalColor: field.color, newColor: values[field.color] ?? field.color }, `color-${field.color}`);
15515
15598
  }
15516
15599
  if (field.type === "image") {
15517
- return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(ImageBinder, { name: field.name, value: values[field.name] ?? "", fit: field.fit ?? "cover" }, `image-${field.name}`);
15600
+ return /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(ImageBinder, { name: field.name, value: values[field.name] ?? "", fit: field.fit ?? "cover" }, `image-${field.name}`);
15518
15601
  }
15519
15602
  return null;
15520
15603
  }) });
@@ -15536,19 +15619,19 @@ function PersonalizationProvider({
15536
15619
  children
15537
15620
  }) {
15538
15621
  const realtime = useRealtimeOptional();
15539
- const [personValues, setPersonValues] = (0, import_react67.useState)(initialValues ?? {});
15540
- const [isActive, setIsActive] = (0, import_react67.useState)(!!(initialValues && Object.keys(initialValues).length > 0));
15541
- const [isExporting, setIsExporting] = (0, import_react67.useState)(false);
15542
- const [exportedBlobUrls, setExportedBlobUrls] = (0, import_react67.useState)({});
15543
- const [exportCount, setExportCount] = (0, import_react67.useState)(0);
15544
- const blobUrlsRef = (0, import_react67.useRef)({});
15545
- const [CanvasComponent, setCanvasComponent] = (0, import_react67.useState)(
15622
+ const [personValues, setPersonValues] = (0, import_react68.useState)(initialValues ?? {});
15623
+ const [isActive, setIsActive] = (0, import_react68.useState)(!!(initialValues && Object.keys(initialValues).length > 0));
15624
+ const [isExporting, setIsExporting] = (0, import_react68.useState)(false);
15625
+ const [exportedBlobUrls, setExportedBlobUrls] = (0, import_react68.useState)({});
15626
+ const [exportCount, setExportCount] = (0, import_react68.useState)(0);
15627
+ const blobUrlsRef = (0, import_react68.useRef)({});
15628
+ const [CanvasComponent, setCanvasComponent] = (0, import_react68.useState)(
15546
15629
  cachedCanvasComponent
15547
15630
  );
15548
- const [BridgeComponent, setBridgeComponent] = (0, import_react67.useState)(
15631
+ const [BridgeComponent, setBridgeComponent] = (0, import_react68.useState)(
15549
15632
  cachedBridgeComponent
15550
15633
  );
15551
- (0, import_react67.useEffect)(() => {
15634
+ (0, import_react68.useEffect)(() => {
15552
15635
  if (CanvasComponent && BridgeComponent) return;
15553
15636
  if (!canvasImport) return;
15554
15637
  if (!canvasLoadPromise) {
@@ -15566,8 +15649,8 @@ function PersonalizationProvider({
15566
15649
  }
15567
15650
  });
15568
15651
  }, [CanvasComponent, BridgeComponent, canvasImport]);
15569
- const realtimeEnabledRef = (0, import_react67.useRef)(false);
15570
- (0, import_react67.useEffect)(() => {
15652
+ const realtimeEnabledRef = (0, import_react68.useRef)(false);
15653
+ (0, import_react68.useEffect)(() => {
15571
15654
  return () => {
15572
15655
  for (const url of Object.values(blobUrlsRef.current)) {
15573
15656
  try {
@@ -15577,16 +15660,16 @@ function PersonalizationProvider({
15577
15660
  }
15578
15661
  };
15579
15662
  }, []);
15580
- const updateField = (0, import_react67.useCallback)((key, value) => {
15663
+ const updateField = (0, import_react68.useCallback)((key, value) => {
15581
15664
  setIsActive(true);
15582
15665
  setPersonValues((prev) => ({ ...prev, [key]: value }));
15583
15666
  }, []);
15584
- const reset = (0, import_react67.useCallback)(() => {
15667
+ const reset = (0, import_react68.useCallback)(() => {
15585
15668
  setPersonValues({});
15586
15669
  setIsActive(false);
15587
15670
  setIsExporting(false);
15588
15671
  }, []);
15589
- const handleExport = (0, import_react67.useCallback)(
15672
+ const handleExport = (0, import_react68.useCallback)(
15590
15673
  (exports2) => {
15591
15674
  const newUrls = {};
15592
15675
  for (const [name, data] of Object.entries(exports2)) {
@@ -15620,11 +15703,11 @@ function PersonalizationProvider({
15620
15703
  },
15621
15704
  [realtime, placementOverride]
15622
15705
  );
15623
- const handleExportScheduled = (0, import_react67.useCallback)(() => {
15706
+ const handleExportScheduled = (0, import_react68.useCallback)(() => {
15624
15707
  setIsExporting(true);
15625
15708
  }, []);
15626
15709
  const shouldMountCanvas = CanvasComponent && BridgeComponent && canvasState?.elements && canvasState.elements.length > 0 && (!lazy || isActive);
15627
- const contextValue = import_react67.default.useMemo(
15710
+ const contextValue = import_react68.default.useMemo(
15628
15711
  () => ({
15629
15712
  fields,
15630
15713
  personValues,
@@ -15637,8 +15720,8 @@ function PersonalizationProvider({
15637
15720
  }),
15638
15721
  [fields, personValues, updateField, isActive, isExporting, exportedBlobUrls, exportCount, reset]
15639
15722
  );
15640
- return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(PersonalizationContext.Provider, { value: contextValue, children: [
15641
- shouldMountCanvas && CanvasComponent && BridgeComponent && /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
15723
+ return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(PersonalizationContext.Provider, { value: contextValue, children: [
15724
+ shouldMountCanvas && CanvasComponent && BridgeComponent && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
15642
15725
  "div",
15643
15726
  {
15644
15727
  style: {
@@ -15651,7 +15734,7 @@ function PersonalizationProvider({
15651
15734
  pointerEvents: "none"
15652
15735
  },
15653
15736
  "aria-hidden": true,
15654
- children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
15737
+ children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
15655
15738
  CanvasComponent,
15656
15739
  {
15657
15740
  initialElements: canvasState?.elements,
@@ -15671,7 +15754,7 @@ function PersonalizationProvider({
15671
15754
  exportImageQuality: exportConfig?.imageQuality ?? 0.85,
15672
15755
  onExport: handleExport,
15673
15756
  onExportScheduled: handleExportScheduled,
15674
- overlay: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(BridgeComponent, { fields, values: personValues })
15757
+ overlay: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(BridgeComponent, { fields, values: personValues })
15675
15758
  }
15676
15759
  )
15677
15760
  },
@@ -15696,7 +15779,7 @@ function usePersonalizationOptional() {
15696
15779
  }
15697
15780
 
15698
15781
  // src/personalization/PersonalizationInputs.tsx
15699
- var import_jsx_runtime88 = require("react/jsx-runtime");
15782
+ var import_jsx_runtime89 = require("react/jsx-runtime");
15700
15783
  function PersonalizationInputs({
15701
15784
  className,
15702
15785
  inputClassName = "w-full px-4 py-3 rounded-lg border text-base text-foreground placeholder:text-muted-foreground bg-white/50 outline-none focus:ring-2 focus:ring-foreground/20",
@@ -15720,8 +15803,8 @@ function PersonalizationInputs({
15720
15803
  scrollInputAboveKeyboard(e.target);
15721
15804
  }
15722
15805
  };
15723
- return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: className || "flex flex-col gap-3", children: [
15724
- textFields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
15806
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: className || "flex flex-col gap-3", children: [
15807
+ textFields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
15725
15808
  "input",
15726
15809
  {
15727
15810
  type: "text",
@@ -15735,8 +15818,8 @@ function PersonalizationInputs({
15735
15818
  },
15736
15819
  `text-${field.name}`
15737
15820
  )),
15738
- colorFields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "flex items-center gap-3", children: [
15739
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
15821
+ colorFields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "flex items-center gap-3", children: [
15822
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
15740
15823
  "input",
15741
15824
  {
15742
15825
  type: "color",
@@ -15745,9 +15828,9 @@ function PersonalizationInputs({
15745
15828
  onChange: (e) => updateField(field.color, e.target.value)
15746
15829
  }
15747
15830
  ),
15748
- /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "text-base text-muted-foreground", children: field.label })
15831
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "text-base text-muted-foreground", children: field.label })
15749
15832
  ] }, `color-${field.color}`)),
15750
- imageFields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
15833
+ imageFields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
15751
15834
  "input",
15752
15835
  {
15753
15836
  type: "text",
@@ -15765,15 +15848,15 @@ function PersonalizationInputs({
15765
15848
  }
15766
15849
 
15767
15850
  // src/personalization/usePersonalizationShimmer.ts
15768
- var import_react68 = require("react");
15851
+ var import_react69 = require("react");
15769
15852
  function usePersonalizationShimmer(containerRef, safetyTimeoutMs = 1e4) {
15770
15853
  const personCtx = usePersonalizationContext();
15771
15854
  const realtime = useRealtimeOptional();
15772
- const [shimmerActive, setShimmerActive] = (0, import_react68.useState)(false);
15773
- const sdkSettledRef = (0, import_react68.useRef)(false);
15774
- const manualTriggerRef = (0, import_react68.useRef)(false);
15775
- const safetyTimeoutRef = (0, import_react68.useRef)(void 0);
15776
- const startShimmer = (0, import_react68.useCallback)(() => {
15855
+ const [shimmerActive, setShimmerActive] = (0, import_react69.useState)(false);
15856
+ const sdkSettledRef = (0, import_react69.useRef)(false);
15857
+ const manualTriggerRef = (0, import_react69.useRef)(false);
15858
+ const safetyTimeoutRef = (0, import_react69.useRef)(void 0);
15859
+ const startShimmer = (0, import_react69.useCallback)(() => {
15777
15860
  setShimmerActive(true);
15778
15861
  if (safetyTimeoutRef.current) clearTimeout(safetyTimeoutRef.current);
15779
15862
  safetyTimeoutRef.current = setTimeout(
@@ -15785,25 +15868,25 @@ function usePersonalizationShimmer(containerRef, safetyTimeoutMs = 1e4) {
15785
15868
  safetyTimeoutMs
15786
15869
  );
15787
15870
  }, [safetyTimeoutMs]);
15788
- (0, import_react68.useEffect)(() => {
15871
+ (0, import_react69.useEffect)(() => {
15789
15872
  if (!personCtx?.isActive) return;
15790
15873
  sdkSettledRef.current = false;
15791
15874
  manualTriggerRef.current = false;
15792
15875
  realtime?.resetPipelineSettled();
15793
15876
  startShimmer();
15794
15877
  }, [personCtx?.personValues, personCtx?.isActive, startShimmer]);
15795
- const triggerShimmer = (0, import_react68.useCallback)(() => {
15878
+ const triggerShimmer = (0, import_react69.useCallback)(() => {
15796
15879
  sdkSettledRef.current = false;
15797
15880
  manualTriggerRef.current = true;
15798
15881
  startShimmer();
15799
15882
  }, [startShimmer]);
15800
- (0, import_react68.useEffect)(() => {
15883
+ (0, import_react69.useEffect)(() => {
15801
15884
  if (!realtime?.subscribePipelineSettled) return;
15802
15885
  return realtime.subscribePipelineSettled(() => {
15803
15886
  sdkSettledRef.current = true;
15804
15887
  });
15805
15888
  }, [realtime]);
15806
- (0, import_react68.useEffect)(() => {
15889
+ (0, import_react69.useEffect)(() => {
15807
15890
  const container = containerRef.current;
15808
15891
  if (!container) return;
15809
15892
  const observer = new MutationObserver((mutations) => {
@@ -15846,7 +15929,7 @@ function usePersonalizationShimmer(containerRef, safetyTimeoutMs = 1e4) {
15846
15929
  });
15847
15930
  return () => observer.disconnect();
15848
15931
  }, [containerRef]);
15849
- (0, import_react68.useEffect)(() => {
15932
+ (0, import_react69.useEffect)(() => {
15850
15933
  return () => {
15851
15934
  if (safetyTimeoutRef.current) clearTimeout(safetyTimeoutRef.current);
15852
15935
  };
@@ -15988,6 +16071,7 @@ function usePersonalizationShimmer(containerRef, safetyTimeoutMs = 1e4) {
15988
16071
  RealtimeProvider,
15989
16072
  ResponsiveZoom,
15990
16073
  RightToLeftProgressiveBlur,
16074
+ SafeImg,
15991
16075
  ScrollFade,
15992
16076
  SearchBox,
15993
16077
  SearchProvider,