@snowcone-app/ui 0.4.7 → 0.4.9

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
@@ -5911,16 +5911,29 @@ function useFocusTrap(isActive, onClose) {
5911
5911
  }
5912
5912
 
5913
5913
  // src/hooks/useCanvasContext.ts
5914
- var import_react26 = require("react");
5914
+ var import_react27 = require("react");
5915
5915
 
5916
5916
  // src/patterns/RealtimeProvider.tsx
5917
- var import_react24 = require("react");
5918
- var import_react25 = require("@snowcone-app/sdk/react");
5917
+ var import_react25 = require("react");
5918
+ var import_react26 = require("@snowcone-app/sdk/react");
5919
5919
  var import_sdk8 = require("@snowcone-app/sdk");
5920
+
5921
+ // src/patterns/MockupBackground.tsx
5922
+ var import_react24 = require("react");
5920
5923
  var import_jsx_runtime51 = require("react/jsx-runtime");
5924
+ var MockupBackgroundContext = (0, import_react24.createContext)(void 0);
5925
+ function MockupBackground({ bg, children }) {
5926
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(MockupBackgroundContext.Provider, { value: bg, children });
5927
+ }
5928
+ function useMockupBackgroundOptional() {
5929
+ return (0, import_react24.useContext)(MockupBackgroundContext);
5930
+ }
5931
+
5932
+ // src/patterns/RealtimeProvider.tsx
5933
+ var import_jsx_runtime52 = require("react/jsx-runtime");
5921
5934
  var DEFAULT_ARTBOARD_SIZE = 2e3;
5922
5935
  var MAX_CONCURRENT_BLOBS = 5;
5923
- var RealtimeContext = (0, import_react24.createContext)(
5936
+ var RealtimeContext = (0, import_react25.createContext)(
5924
5937
  void 0
5925
5938
  );
5926
5939
  function RealtimeProvider({
@@ -5934,9 +5947,10 @@ function RealtimeProvider({
5934
5947
  grantUrl
5935
5948
  }) {
5936
5949
  const productContext = useProductOptional();
5937
- const [isEnabled, setIsEnabled] = (0, import_react24.useState)(autoEnable);
5950
+ const mockupBg = useMockupBackgroundOptional();
5951
+ const [isEnabled, setIsEnabled] = (0, import_react25.useState)(autoEnable);
5938
5952
  const useSessionGrant = Boolean(shop && grantUrl);
5939
- const getToken = (0, import_react24.useCallback)(async () => {
5953
+ const getToken = (0, import_react25.useCallback)(async () => {
5940
5954
  const res = await fetch(grantUrl, {
5941
5955
  method: "POST",
5942
5956
  headers: { "Content-Type": "application/json" },
@@ -5947,15 +5961,19 @@ function RealtimeProvider({
5947
5961
  }
5948
5962
  return await res.json();
5949
5963
  }, [shop, grantUrl]);
5950
- const canvasBlobsSentRef = (0, import_react24.useRef)(0);
5951
- const colorBlobsSentRef = (0, import_react24.useRef)(0);
5952
- const lastBlobSentTimeRef = (0, import_react24.useRef)(null);
5953
- const isPendingMockupsRef = (0, import_react24.useRef)(false);
5954
- const configSentRef = (0, import_react24.useRef)(false);
5955
- const placementSettingsOverridesRef = (0, import_react24.useRef)({});
5956
- const lastSentVariantIdRef = (0, import_react24.useRef)(null);
5957
- const lastSentColorsRef = (0, import_react24.useRef)({});
5958
- const realtimeMockup = (0, import_react25.useRealtimeMockup)({
5964
+ const canvasBlobsSentRef = (0, import_react25.useRef)(0);
5965
+ const colorBlobsSentRef = (0, import_react25.useRef)(0);
5966
+ const lastBlobSentTimeRef = (0, import_react25.useRef)(null);
5967
+ const isPendingMockupsRef = (0, import_react25.useRef)(false);
5968
+ const configSentRef = (0, import_react25.useRef)(false);
5969
+ const placementSettingsOverridesRef = (0, import_react25.useRef)({});
5970
+ const lastSentVariantIdRef = (0, import_react25.useRef)(null);
5971
+ const lastSentBgRef = (0, import_react25.useRef)(void 0);
5972
+ const spreadCropsRef = (0, import_react25.useRef)(void 0);
5973
+ const [spreadCropsVersion, setSpreadCropsVersion] = (0, import_react25.useState)(0);
5974
+ const lastSentSpreadCropsRef = (0, import_react25.useRef)("null");
5975
+ const lastSentColorsRef = (0, import_react25.useRef)({});
5976
+ const realtimeMockup = (0, import_react26.useRealtimeMockup)({
5959
5977
  wsUrl,
5960
5978
  getToken: useSessionGrant ? getToken : void 0,
5961
5979
  onConnected: (sessionId) => {
@@ -5986,7 +6004,7 @@ function RealtimeProvider({
5986
6004
  console.error(`[RealtimeProvider] Render error [${detail.code}]:`, error);
5987
6005
  }
5988
6006
  });
5989
- const subscribeRTCTiming = (0, import_react24.useCallback)((_callback) => {
6007
+ const subscribeRTCTiming = (0, import_react25.useCallback)((_callback) => {
5990
6008
  return () => {
5991
6009
  };
5992
6010
  }, []);
@@ -6006,31 +6024,31 @@ function RealtimeProvider({
6006
6024
  flushPendingBlobs,
6007
6025
  hasPendingBlobs
6008
6026
  } = realtimeMockup;
6009
- const mockupResultsRef = (0, import_react24.useRef)([]);
6010
- const mockupSubscribersRef = (0, import_react24.useRef)(
6027
+ const mockupResultsRef = (0, import_react25.useRef)([]);
6028
+ const mockupSubscribersRef = (0, import_react25.useRef)(
6011
6029
  /* @__PURE__ */ new Set()
6012
6030
  );
6013
- const mockupSubscribersByIdRef = (0, import_react24.useRef)(/* @__PURE__ */ new Map());
6014
- const pendingExportCancelledSubscribersRef = (0, import_react24.useRef)(/* @__PURE__ */ new Set());
6015
- const pendingBlobSubscribersRef = (0, import_react24.useRef)(
6031
+ const mockupSubscribersByIdRef = (0, import_react25.useRef)(/* @__PURE__ */ new Map());
6032
+ const pendingExportCancelledSubscribersRef = (0, import_react25.useRef)(/* @__PURE__ */ new Set());
6033
+ const pendingBlobSubscribersRef = (0, import_react25.useRef)(
6016
6034
  /* @__PURE__ */ new Set()
6017
6035
  );
6018
- const blobReceivedSubscribersRef = (0, import_react24.useRef)(
6036
+ const blobReceivedSubscribersRef = (0, import_react25.useRef)(
6019
6037
  /* @__PURE__ */ new Set()
6020
6038
  );
6021
- const blobSentSubscribersRef = (0, import_react24.useRef)(
6039
+ const blobSentSubscribersRef = (0, import_react25.useRef)(
6022
6040
  /* @__PURE__ */ new Set()
6023
6041
  );
6024
- const pipelineSettledSubscribersRef = (0, import_react24.useRef)(/* @__PURE__ */ new Set());
6025
- const pipelineGenRef = (0, import_react24.useRef)(0);
6026
- const blobQueuedGenRef = (0, import_react24.useRef)(0);
6027
- const hasBlobInFlightRef = (0, import_react24.useRef)(false);
6028
- const pipelineResetCooldownRef = (0, import_react24.useRef)(false);
6029
- const mockupUrlCacheRef = (0, import_react24.useRef)(/* @__PURE__ */ new Map());
6030
- const registeredBlobUrlsRef = (0, import_react24.useRef)(/* @__PURE__ */ new Set());
6031
- const pendingPlacementsRef = (0, import_react24.useRef)(/* @__PURE__ */ new Set());
6032
- const pendingMockupIdsRef = (0, import_react24.useRef)(/* @__PURE__ */ new Set());
6033
- (0, import_react24.useEffect)(() => {
6042
+ const pipelineSettledSubscribersRef = (0, import_react25.useRef)(/* @__PURE__ */ new Set());
6043
+ const pipelineGenRef = (0, import_react25.useRef)(0);
6044
+ const blobQueuedGenRef = (0, import_react25.useRef)(0);
6045
+ const hasBlobInFlightRef = (0, import_react25.useRef)(false);
6046
+ const pipelineResetCooldownRef = (0, import_react25.useRef)(false);
6047
+ const mockupUrlCacheRef = (0, import_react25.useRef)(/* @__PURE__ */ new Map());
6048
+ const registeredBlobUrlsRef = (0, import_react25.useRef)(/* @__PURE__ */ new Set());
6049
+ const pendingPlacementsRef = (0, import_react25.useRef)(/* @__PURE__ */ new Set());
6050
+ const pendingMockupIdsRef = (0, import_react25.useRef)(/* @__PURE__ */ new Set());
6051
+ (0, import_react25.useEffect)(() => {
6034
6052
  if (rawMockupResults.length === 0) {
6035
6053
  if (mockupResultsRef.current.length > 0) {
6036
6054
  mockupResultsRef.current = [];
@@ -6082,7 +6100,7 @@ function RealtimeProvider({
6082
6100
  pipelineSettledSubscribersRef.current.forEach((cb) => cb());
6083
6101
  }
6084
6102
  }, [rawMockupResults]);
6085
- const sendCanvasBlob = (0, import_react24.useCallback)(
6103
+ const sendCanvasBlob = (0, import_react25.useCallback)(
6086
6104
  (placement, blob, mockupCount, baseThrottleMs) => {
6087
6105
  blobQueuedGenRef.current = pipelineGenRef.current;
6088
6106
  const result = sendCanvasBlobRaw(
@@ -6101,7 +6119,7 @@ function RealtimeProvider({
6101
6119
  },
6102
6120
  [sendCanvasBlobRaw]
6103
6121
  );
6104
- const sendCanvasState = (0, import_react24.useCallback)(
6122
+ const sendCanvasState = (0, import_react25.useCallback)(
6105
6123
  (placement, state, mockupCount, baseThrottleMs) => {
6106
6124
  blobQueuedGenRef.current = pipelineGenRef.current;
6107
6125
  const result = sendCanvasStateRaw(
@@ -6120,7 +6138,7 @@ function RealtimeProvider({
6120
6138
  },
6121
6139
  [sendCanvasStateRaw]
6122
6140
  );
6123
- const sendColorBlobTracked = (0, import_react24.useCallback)(
6141
+ const sendColorBlobTracked = (0, import_react25.useCallback)(
6124
6142
  (placement, color) => {
6125
6143
  const result = sendColorBlob(placement, color);
6126
6144
  if (result) {
@@ -6132,23 +6150,25 @@ function RealtimeProvider({
6132
6150
  },
6133
6151
  [sendColorBlob]
6134
6152
  );
6135
- (0, import_react24.useEffect)(() => {
6153
+ (0, import_react25.useEffect)(() => {
6136
6154
  if (isEnabled) {
6137
6155
  connect();
6138
6156
  return () => {
6139
6157
  disconnect();
6140
6158
  configSentRef.current = false;
6141
6159
  lastSentVariantIdRef.current = null;
6160
+ lastSentBgRef.current = void 0;
6161
+ lastSentSpreadCropsRef.current = "null";
6142
6162
  lastSentColorsRef.current = {};
6143
6163
  };
6144
6164
  }
6145
6165
  }, [isEnabled, connect, disconnect, wsUrl]);
6146
- (0, import_react24.useEffect)(() => {
6166
+ (0, import_react25.useEffect)(() => {
6147
6167
  if (rawMockupResults.length > 0 && isPendingMockupsRef.current) {
6148
6168
  isPendingMockupsRef.current = false;
6149
6169
  }
6150
6170
  }, [rawMockupResults.length]);
6151
- (0, import_react24.useEffect)(() => {
6171
+ (0, import_react25.useEffect)(() => {
6152
6172
  if (!isEnabled || !isConnected || !productContext?.product) return;
6153
6173
  const product = productContext.product;
6154
6174
  const productId = product.id;
@@ -6160,7 +6180,10 @@ function RealtimeProvider({
6160
6180
  );
6161
6181
  const isFirstSend = !configSentRef.current;
6162
6182
  const variantChanged = lastSentVariantIdRef.current !== null && lastSentVariantIdRef.current !== variantId;
6163
- if (!isFirstSend && !variantChanged) {
6183
+ const bgChanged = configSentRef.current && lastSentBgRef.current !== mockupBg;
6184
+ const spreadCropsJson = JSON.stringify(spreadCropsRef.current ?? null);
6185
+ const spreadCropsChanged = configSentRef.current && lastSentSpreadCropsRef.current !== spreadCropsJson;
6186
+ if (!isFirstSend && !variantChanged && !bgChanged && !spreadCropsChanged) {
6164
6187
  return;
6165
6188
  }
6166
6189
  const mockupIds = [];
@@ -6177,6 +6200,8 @@ function RealtimeProvider({
6177
6200
  variantId,
6178
6201
  shop,
6179
6202
  width: mockupWidth,
6203
+ ...mockupBg ? { bg: mockupBg } : {},
6204
+ ...spreadCropsRef.current ? { spreadCrops: spreadCropsRef.current } : {},
6180
6205
  placementSettings: { ...placementSettingsOverridesRef.current }
6181
6206
  } : {
6182
6207
  productId,
@@ -6185,6 +6210,8 @@ function RealtimeProvider({
6185
6210
  shop: "hTidnpNnNa",
6186
6211
  seal: "bypass-sig-for-k6-load-test",
6187
6212
  width: mockupWidth,
6213
+ ...mockupBg ? { bg: mockupBg } : {},
6214
+ ...spreadCropsRef.current ? { spreadCrops: spreadCropsRef.current } : {},
6188
6215
  placementSettings: { ...placementSettingsOverridesRef.current }
6189
6216
  };
6190
6217
  if (variantChanged) {
@@ -6196,6 +6223,8 @@ function RealtimeProvider({
6196
6223
  sendConfigRaw(configPayload);
6197
6224
  configSentRef.current = true;
6198
6225
  lastSentVariantIdRef.current = variantId;
6226
+ lastSentBgRef.current = mockupBg;
6227
+ lastSentSpreadCropsRef.current = spreadCropsJson;
6199
6228
  setTimeout(() => {
6200
6229
  const colorPlacements = placements.filter((p) => p.type === "color");
6201
6230
  colorPlacements.forEach((p) => {
@@ -6213,9 +6242,11 @@ function RealtimeProvider({
6213
6242
  productContext?.selection,
6214
6243
  sendConfigRaw,
6215
6244
  sendColorBlobTracked,
6216
- mockupWidth
6245
+ mockupWidth,
6246
+ mockupBg,
6247
+ spreadCropsVersion
6217
6248
  ]);
6218
- (0, import_react24.useEffect)(() => {
6249
+ (0, import_react25.useEffect)(() => {
6219
6250
  if (!isEnabled || !isConnected || !isConfigured || !productContext?.product)
6220
6251
  return;
6221
6252
  const placements = productContext.product.placements || [];
@@ -6240,20 +6271,31 @@ function RealtimeProvider({
6240
6271
  productContext?.selection,
6241
6272
  sendColorBlobTracked
6242
6273
  ]);
6243
- const updatePlacementSettingsWrapped = (0, import_react24.useCallback)(
6274
+ const updatePlacementSettingsWrapped = (0, import_react25.useCallback)(
6244
6275
  (settings) => {
6245
6276
  placementSettingsOverridesRef.current = settings;
6246
6277
  return updatePlacementSettingsRaw(settings);
6247
6278
  },
6248
6279
  [updatePlacementSettingsRaw]
6249
6280
  );
6250
- const enableRealtime = (0, import_react24.useCallback)(() => {
6281
+ const setSpreadCrops = (0, import_react25.useCallback)(
6282
+ (crops) => {
6283
+ const next = crops && Object.keys(crops).length > 0 ? crops : void 0;
6284
+ if (JSON.stringify(next ?? null) === JSON.stringify(spreadCropsRef.current ?? null)) {
6285
+ return;
6286
+ }
6287
+ spreadCropsRef.current = next;
6288
+ setSpreadCropsVersion((v) => v + 1);
6289
+ },
6290
+ []
6291
+ );
6292
+ const enableRealtime = (0, import_react25.useCallback)(() => {
6251
6293
  setIsEnabled(true);
6252
6294
  }, []);
6253
- const disableRealtime = (0, import_react24.useCallback)(() => {
6295
+ const disableRealtime = (0, import_react25.useCallback)(() => {
6254
6296
  setIsEnabled(false);
6255
6297
  }, []);
6256
- const placementDimensions = (0, import_react24.useMemo)(() => {
6298
+ const placementDimensions = (0, import_react25.useMemo)(() => {
6257
6299
  if (!productContext?.product?.placements) return [];
6258
6300
  return productContext.product.placements.map((p) => ({
6259
6301
  label: p.label,
@@ -6262,14 +6304,14 @@ function RealtimeProvider({
6262
6304
  type: p.type || "image"
6263
6305
  }));
6264
6306
  }, [productContext?.product?.placements]);
6265
- const canvasExportSize = (0, import_react24.useMemo)(() => {
6307
+ const canvasExportSize = (0, import_react25.useMemo)(() => {
6266
6308
  const firstPlacement = productContext?.product?.placements?.[0];
6267
6309
  if (firstPlacement?.width && firstPlacement?.height) {
6268
6310
  return { width: firstPlacement.width, height: firstPlacement.height };
6269
6311
  }
6270
6312
  return { width: DEFAULT_ARTBOARD_SIZE, height: DEFAULT_ARTBOARD_SIZE };
6271
6313
  }, [productContext?.product?.placements]);
6272
- const subscribeMockupResults = (0, import_react24.useCallback)(
6314
+ const subscribeMockupResults = (0, import_react25.useCallback)(
6273
6315
  (callback) => {
6274
6316
  mockupSubscribersRef.current.add(callback);
6275
6317
  return () => {
@@ -6278,7 +6320,7 @@ function RealtimeProvider({
6278
6320
  },
6279
6321
  []
6280
6322
  );
6281
- const subscribeMockupResultById = (0, import_react24.useCallback)(
6323
+ const subscribeMockupResultById = (0, import_react25.useCallback)(
6282
6324
  (mockupId, callback) => {
6283
6325
  if (!mockupSubscribersByIdRef.current.has(mockupId)) {
6284
6326
  mockupSubscribersByIdRef.current.set(mockupId, /* @__PURE__ */ new Set());
@@ -6305,7 +6347,7 @@ function RealtimeProvider({
6305
6347
  },
6306
6348
  []
6307
6349
  );
6308
- const subscribePendingBlob = (0, import_react24.useCallback)(
6350
+ const subscribePendingBlob = (0, import_react25.useCallback)(
6309
6351
  (callback) => {
6310
6352
  pendingBlobSubscribersRef.current.add(callback);
6311
6353
  return () => {
@@ -6314,7 +6356,7 @@ function RealtimeProvider({
6314
6356
  },
6315
6357
  []
6316
6358
  );
6317
- const subscribePendingExportCancelled = (0, import_react24.useCallback)(
6359
+ const subscribePendingExportCancelled = (0, import_react25.useCallback)(
6318
6360
  (callback) => {
6319
6361
  pendingExportCancelledSubscribersRef.current.add(callback);
6320
6362
  return () => {
@@ -6323,7 +6365,7 @@ function RealtimeProvider({
6323
6365
  },
6324
6366
  []
6325
6367
  );
6326
- const subscribeBlobReceived = (0, import_react24.useCallback)(
6368
+ const subscribeBlobReceived = (0, import_react25.useCallback)(
6327
6369
  (callback) => {
6328
6370
  blobReceivedSubscribersRef.current.add(callback);
6329
6371
  return () => {
@@ -6332,7 +6374,7 @@ function RealtimeProvider({
6332
6374
  },
6333
6375
  []
6334
6376
  );
6335
- const subscribeBlobSent = (0, import_react24.useCallback)(
6377
+ const subscribeBlobSent = (0, import_react25.useCallback)(
6336
6378
  (callback) => {
6337
6379
  blobSentSubscribersRef.current.add(callback);
6338
6380
  return () => {
@@ -6341,7 +6383,7 @@ function RealtimeProvider({
6341
6383
  },
6342
6384
  []
6343
6385
  );
6344
- const subscribePipelineSettled = (0, import_react24.useCallback)(
6386
+ const subscribePipelineSettled = (0, import_react25.useCallback)(
6345
6387
  (callback) => {
6346
6388
  pipelineSettledSubscribersRef.current.add(callback);
6347
6389
  return () => {
@@ -6350,7 +6392,7 @@ function RealtimeProvider({
6350
6392
  },
6351
6393
  []
6352
6394
  );
6353
- const resetPipelineSettled = (0, import_react24.useCallback)(
6395
+ const resetPipelineSettled = (0, import_react25.useCallback)(
6354
6396
  () => {
6355
6397
  pipelineGenRef.current++;
6356
6398
  hasBlobInFlightRef.current = false;
@@ -6361,7 +6403,7 @@ function RealtimeProvider({
6361
6403
  },
6362
6404
  []
6363
6405
  );
6364
- const notifyPendingExport = (0, import_react24.useCallback)(
6406
+ const notifyPendingExport = (0, import_react25.useCallback)(
6365
6407
  (placement) => {
6366
6408
  if (pendingPlacementsRef.current.has(placement)) {
6367
6409
  return;
@@ -6381,7 +6423,7 @@ function RealtimeProvider({
6381
6423
  },
6382
6424
  [productContext?.product?.mockups]
6383
6425
  );
6384
- const notifyPendingExportCancelled = (0, import_react24.useCallback)(
6426
+ const notifyPendingExportCancelled = (0, import_react25.useCallback)(
6385
6427
  (placement) => {
6386
6428
  if (!pendingPlacementsRef.current.has(placement)) {
6387
6429
  return;
@@ -6405,7 +6447,7 @@ function RealtimeProvider({
6405
6447
  },
6406
6448
  [productContext?.product?.mockups]
6407
6449
  );
6408
- const getMockupUrl3 = (0, import_react24.useCallback)((mockupId) => {
6450
+ const getMockupUrl3 = (0, import_react25.useCallback)((mockupId) => {
6409
6451
  if (pendingMockupIdsRef.current.has(mockupId)) {
6410
6452
  console.log(`[RTP] getMockupUrl("${mockupId}") \u2192 null (pending)`);
6411
6453
  return null;
@@ -6413,7 +6455,7 @@ function RealtimeProvider({
6413
6455
  const cached = mockupUrlCacheRef.current.get(mockupId);
6414
6456
  return cached?.url ?? null;
6415
6457
  }, []);
6416
- const getMockupUrls = (0, import_react24.useCallback)((mockupIds) => {
6458
+ const getMockupUrls = (0, import_react25.useCallback)((mockupIds) => {
6417
6459
  const result = {};
6418
6460
  for (const mockupId of mockupIds) {
6419
6461
  if (pendingMockupIdsRef.current.has(mockupId)) {
@@ -6425,10 +6467,10 @@ function RealtimeProvider({
6425
6467
  }
6426
6468
  return result;
6427
6469
  }, []);
6428
- const isMockupLoading = (0, import_react24.useCallback)((mockupId) => {
6470
+ const isMockupLoading = (0, import_react25.useCallback)((mockupId) => {
6429
6471
  return pendingMockupIdsRef.current.has(mockupId);
6430
6472
  }, []);
6431
- const registerBlobUrl = (0, import_react24.useCallback)((blobOrUrl, placementName) => {
6473
+ const registerBlobUrl = (0, import_react25.useCallback)((blobOrUrl, placementName) => {
6432
6474
  let url;
6433
6475
  if (blobOrUrl instanceof Blob) {
6434
6476
  if (registeredBlobUrlsRef.current.size >= MAX_CONCURRENT_BLOBS) {
@@ -6450,13 +6492,13 @@ function RealtimeProvider({
6450
6492
  }
6451
6493
  return url;
6452
6494
  }, []);
6453
- const subscribeMockupResultsRef = (0, import_react24.useRef)(subscribeMockupResults);
6454
- const subscribeMockupResultByIdRef = (0, import_react24.useRef)(subscribeMockupResultById);
6455
- const subscribePendingBlobRef = (0, import_react24.useRef)(subscribePendingBlob);
6456
- const subscribeBlobReceivedRef = (0, import_react24.useRef)(subscribeBlobReceived);
6457
- const subscribeBlobSentRef = (0, import_react24.useRef)(subscribeBlobSent);
6458
- const subscribePipelineSettledRef = (0, import_react24.useRef)(subscribePipelineSettled);
6459
- const subscribePendingExportCancelledRef = (0, import_react24.useRef)(
6495
+ const subscribeMockupResultsRef = (0, import_react25.useRef)(subscribeMockupResults);
6496
+ const subscribeMockupResultByIdRef = (0, import_react25.useRef)(subscribeMockupResultById);
6497
+ const subscribePendingBlobRef = (0, import_react25.useRef)(subscribePendingBlob);
6498
+ const subscribeBlobReceivedRef = (0, import_react25.useRef)(subscribeBlobReceived);
6499
+ const subscribeBlobSentRef = (0, import_react25.useRef)(subscribeBlobSent);
6500
+ const subscribePipelineSettledRef = (0, import_react25.useRef)(subscribePipelineSettled);
6501
+ const subscribePendingExportCancelledRef = (0, import_react25.useRef)(
6460
6502
  subscribePendingExportCancelled
6461
6503
  );
6462
6504
  subscribeMockupResultsRef.current = subscribeMockupResults;
@@ -6466,49 +6508,49 @@ function RealtimeProvider({
6466
6508
  subscribeBlobSentRef.current = subscribeBlobSent;
6467
6509
  subscribePipelineSettledRef.current = subscribePipelineSettled;
6468
6510
  subscribePendingExportCancelledRef.current = subscribePendingExportCancelled;
6469
- const stableSubscribeMockupResults = (0, import_react24.useCallback)(
6511
+ const stableSubscribeMockupResults = (0, import_react25.useCallback)(
6470
6512
  (callback) => {
6471
6513
  return subscribeMockupResultsRef.current(callback);
6472
6514
  },
6473
6515
  []
6474
6516
  );
6475
- const stableSubscribeMockupResultById = (0, import_react24.useCallback)(
6517
+ const stableSubscribeMockupResultById = (0, import_react25.useCallback)(
6476
6518
  (mockupId, callback) => {
6477
6519
  return subscribeMockupResultByIdRef.current(mockupId, callback);
6478
6520
  },
6479
6521
  []
6480
6522
  );
6481
- const stableSubscribePendingBlob = (0, import_react24.useCallback)(
6523
+ const stableSubscribePendingBlob = (0, import_react25.useCallback)(
6482
6524
  (callback) => {
6483
6525
  return subscribePendingBlobRef.current(callback);
6484
6526
  },
6485
6527
  []
6486
6528
  );
6487
- const stableSubscribePendingExportCancelled = (0, import_react24.useCallback)(
6529
+ const stableSubscribePendingExportCancelled = (0, import_react25.useCallback)(
6488
6530
  (callback) => {
6489
6531
  return subscribePendingExportCancelledRef.current(callback);
6490
6532
  },
6491
6533
  []
6492
6534
  );
6493
- const stableSubscribeBlobReceived = (0, import_react24.useCallback)(
6535
+ const stableSubscribeBlobReceived = (0, import_react25.useCallback)(
6494
6536
  (callback) => {
6495
6537
  return subscribeBlobReceivedRef.current(callback);
6496
6538
  },
6497
6539
  []
6498
6540
  );
6499
- const stableSubscribeBlobSent = (0, import_react24.useCallback)(
6541
+ const stableSubscribeBlobSent = (0, import_react25.useCallback)(
6500
6542
  (callback) => {
6501
6543
  return subscribeBlobSentRef.current(callback);
6502
6544
  },
6503
6545
  []
6504
6546
  );
6505
- const stableSubscribePipelineSettled = (0, import_react24.useCallback)(
6547
+ const stableSubscribePipelineSettled = (0, import_react25.useCallback)(
6506
6548
  (callback) => {
6507
6549
  return subscribePipelineSettledRef.current(callback);
6508
6550
  },
6509
6551
  []
6510
6552
  );
6511
- const contextValue = (0, import_react24.useMemo)(
6553
+ const contextValue = (0, import_react25.useMemo)(
6512
6554
  () => ({
6513
6555
  isEnabled,
6514
6556
  isConnected,
@@ -6532,6 +6574,7 @@ function RealtimeProvider({
6532
6574
  sendCanvasState,
6533
6575
  updateMockupIds: updateMockupIdsRaw,
6534
6576
  updatePlacementSettings: updatePlacementSettingsWrapped,
6577
+ setSpreadCrops,
6535
6578
  getMockupResultsImmediate: () => mockupResultsRef.current,
6536
6579
  subscribeMockupResults: stableSubscribeMockupResults,
6537
6580
  subscribeMockupResultById: stableSubscribeMockupResultById,
@@ -6568,6 +6611,7 @@ function RealtimeProvider({
6568
6611
  sendCanvasState,
6569
6612
  updateMockupIdsRaw,
6570
6613
  updatePlacementSettingsWrapped,
6614
+ setSpreadCrops,
6571
6615
  stableSubscribeMockupResults,
6572
6616
  stableSubscribeMockupResultById,
6573
6617
  notifyPendingExport,
@@ -6581,31 +6625,31 @@ function RealtimeProvider({
6581
6625
  registerBlobUrl
6582
6626
  ]
6583
6627
  );
6584
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(RealtimeContext.Provider, { value: contextValue, children });
6628
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(RealtimeContext.Provider, { value: contextValue, children });
6585
6629
  }
6586
6630
  function useRealtime() {
6587
- const context = (0, import_react24.useContext)(RealtimeContext);
6631
+ const context = (0, import_react25.useContext)(RealtimeContext);
6588
6632
  if (!context) {
6589
6633
  throw new Error("useRealtime must be used within a RealtimeProvider");
6590
6634
  }
6591
6635
  return context;
6592
6636
  }
6593
6637
  function useRealtimeOptional() {
6594
- return (0, import_react24.useContext)(RealtimeContext);
6638
+ return (0, import_react25.useContext)(RealtimeContext);
6595
6639
  }
6596
6640
 
6597
6641
  // src/hooks/useCanvasContext.ts
6598
6642
  function useCanvasContext() {
6599
6643
  const context = useProductOptional();
6600
6644
  const realtimeContext = useRealtimeOptional();
6601
- const sendCanvasBlobRef = (0, import_react26.useRef)(realtimeContext?.sendCanvasBlob);
6602
- const isRealtimeEnabledRef = (0, import_react26.useRef)(realtimeContext?.isEnabled ?? false);
6603
- const isConfiguredRef = (0, import_react26.useRef)(realtimeContext?.isConfigured ?? false);
6604
- const mockupCountRef = (0, import_react26.useRef)(context?.product?.mockups?.length ?? 1);
6605
- const selectedPlacementRef = (0, import_react26.useRef)(context?.selectedPlacement);
6606
- const enableRealtimeRef = (0, import_react26.useRef)(realtimeContext?.enableRealtime);
6607
- const selectedArtworkRef = (0, import_react26.useRef)(context?.selectedArtwork);
6608
- (0, import_react26.useEffect)(() => {
6645
+ const sendCanvasBlobRef = (0, import_react27.useRef)(realtimeContext?.sendCanvasBlob);
6646
+ const isRealtimeEnabledRef = (0, import_react27.useRef)(realtimeContext?.isEnabled ?? false);
6647
+ const isConfiguredRef = (0, import_react27.useRef)(realtimeContext?.isConfigured ?? false);
6648
+ const mockupCountRef = (0, import_react27.useRef)(context?.product?.mockups?.length ?? 1);
6649
+ const selectedPlacementRef = (0, import_react27.useRef)(context?.selectedPlacement);
6650
+ const enableRealtimeRef = (0, import_react27.useRef)(realtimeContext?.enableRealtime);
6651
+ const selectedArtworkRef = (0, import_react27.useRef)(context?.selectedArtwork);
6652
+ (0, import_react27.useEffect)(() => {
6609
6653
  sendCanvasBlobRef.current = realtimeContext?.sendCanvasBlob;
6610
6654
  isRealtimeEnabledRef.current = realtimeContext?.isEnabled ?? false;
6611
6655
  isConfiguredRef.current = realtimeContext?.isConfigured ?? false;
@@ -6614,7 +6658,7 @@ function useCanvasContext() {
6614
6658
  enableRealtimeRef.current = realtimeContext?.enableRealtime;
6615
6659
  selectedArtworkRef.current = context?.selectedArtwork;
6616
6660
  });
6617
- return (0, import_react26.useMemo)(() => ({
6661
+ return (0, import_react27.useMemo)(() => ({
6618
6662
  /** Ref to sendCanvasBlob function - call via sendCanvasBlobRef.current?.(...) */
6619
6663
  sendCanvasBlobRef,
6620
6664
  /** Ref to isRealtimeEnabled boolean */
@@ -6647,7 +6691,7 @@ function useCanvasContext() {
6647
6691
  function useCanvasContextStatic() {
6648
6692
  const context = useProductOptional();
6649
6693
  const realtimeContext = useRealtimeOptional();
6650
- const [staticValues] = (0, import_react26.useState)(() => ({
6694
+ const [staticValues] = (0, import_react27.useState)(() => ({
6651
6695
  sendCanvasBlob: realtimeContext?.sendCanvasBlob,
6652
6696
  isRealtimeEnabled: realtimeContext?.isEnabled ?? false,
6653
6697
  isConfigured: realtimeContext?.isConfigured ?? false,
@@ -6660,14 +6704,14 @@ function useCanvasContextStatic() {
6660
6704
  }
6661
6705
 
6662
6706
  // src/hooks/useRenderGuard.ts
6663
- var import_react27 = require("react");
6707
+ var import_react28 = require("react");
6664
6708
  function useRenderGuard({
6665
6709
  name,
6666
6710
  maxRendersPerSecond = 3,
6667
6711
  enabled = process.env.NODE_ENV === "development"
6668
6712
  }) {
6669
6713
  if (!enabled) return;
6670
- const timestampsRef = (0, import_react27.useRef)([]);
6714
+ const timestampsRef = (0, import_react28.useRef)([]);
6671
6715
  const now = performance.now();
6672
6716
  timestampsRef.current = timestampsRef.current.filter((t) => t > now - 1e3);
6673
6717
  timestampsRef.current.push(now);
@@ -6684,7 +6728,7 @@ function useRenderGuard({
6684
6728
  }
6685
6729
  }
6686
6730
  function useRenderCount(componentName) {
6687
- const countRef = (0, import_react27.useRef)(0);
6731
+ const countRef = (0, import_react28.useRef)(0);
6688
6732
  countRef.current++;
6689
6733
  if (process.env.NODE_ENV === "development" && componentName && countRef.current % 5 === 0) {
6690
6734
  }
@@ -6692,22 +6736,22 @@ function useRenderCount(componentName) {
6692
6736
  }
6693
6737
 
6694
6738
  // src/hooks/useScrollDirection.ts
6695
- var import_react28 = require("react");
6739
+ var import_react29 = require("react");
6696
6740
  var IDLE_TIMEOUT_MS = 150;
6697
6741
  var MIN_DELTA_PX = 5;
6698
6742
  function useScrollDirection() {
6699
- const [state, setState] = (0, import_react28.useState)({
6743
+ const [state, setState] = (0, import_react29.useState)({
6700
6744
  direction: "idle",
6701
6745
  velocity: 0,
6702
6746
  scrollY: typeof window !== "undefined" ? window.scrollY : 0
6703
6747
  });
6704
- const lastScrollRef = (0, import_react28.useRef)({
6748
+ const lastScrollRef = (0, import_react29.useRef)({
6705
6749
  top: typeof window !== "undefined" ? window.scrollY : 0,
6706
6750
  time: Date.now()
6707
6751
  });
6708
- const rafIdRef = (0, import_react28.useRef)(null);
6709
- const idleTimeoutRef = (0, import_react28.useRef)(null);
6710
- const handleScroll = (0, import_react28.useCallback)(() => {
6752
+ const rafIdRef = (0, import_react29.useRef)(null);
6753
+ const idleTimeoutRef = (0, import_react29.useRef)(null);
6754
+ const handleScroll = (0, import_react29.useCallback)(() => {
6711
6755
  if (rafIdRef.current !== null) return;
6712
6756
  rafIdRef.current = requestAnimationFrame(() => {
6713
6757
  const currentTop = window.scrollY;
@@ -6742,7 +6786,7 @@ function useScrollDirection() {
6742
6786
  rafIdRef.current = null;
6743
6787
  });
6744
6788
  }, []);
6745
- (0, import_react28.useEffect)(() => {
6789
+ (0, import_react29.useEffect)(() => {
6746
6790
  if (typeof window === "undefined") return;
6747
6791
  lastScrollRef.current = {
6748
6792
  top: window.scrollY,
@@ -6813,7 +6857,7 @@ function createScrollDirectionTracker() {
6813
6857
  }
6814
6858
 
6815
6859
  // src/hooks/useImageTransition.ts
6816
- var import_react29 = require("react");
6860
+ var import_react30 = require("react");
6817
6861
  var layerIdCounter = 0;
6818
6862
  function useImageTransition(options = {}) {
6819
6863
  const {
@@ -6823,7 +6867,7 @@ function useImageTransition(options = {}) {
6823
6867
  darkShimmerFadeInDuration = 300,
6824
6868
  initialUrl
6825
6869
  } = options;
6826
- const [state, setState] = (0, import_react29.useState)(() => {
6870
+ const [state, setState] = (0, import_react30.useState)(() => {
6827
6871
  return {
6828
6872
  layers: initialUrl ? [{ url: initialUrl, opacity: 1, id: ++layerIdCounter, loaded: true }] : [],
6829
6873
  preloadUrl: null,
@@ -6832,12 +6876,12 @@ function useImageTransition(options = {}) {
6832
6876
  shimmerType: "light"
6833
6877
  };
6834
6878
  });
6835
- const versionRef = (0, import_react29.useRef)(0);
6836
- const preloaderRef = (0, import_react29.useRef)(null);
6837
- const currentPreloadUrlRef = (0, import_react29.useRef)(null);
6838
- const shimmerTimerRef = (0, import_react29.useRef)(null);
6839
- const isMountedRef = (0, import_react29.useRef)(true);
6840
- (0, import_react29.useEffect)(() => {
6879
+ const versionRef = (0, import_react30.useRef)(0);
6880
+ const preloaderRef = (0, import_react30.useRef)(null);
6881
+ const currentPreloadUrlRef = (0, import_react30.useRef)(null);
6882
+ const shimmerTimerRef = (0, import_react30.useRef)(null);
6883
+ const isMountedRef = (0, import_react30.useRef)(true);
6884
+ (0, import_react30.useEffect)(() => {
6841
6885
  isMountedRef.current = true;
6842
6886
  return () => {
6843
6887
  isMountedRef.current = false;
@@ -6851,7 +6895,7 @@ function useImageTransition(options = {}) {
6851
6895
  }
6852
6896
  };
6853
6897
  }, []);
6854
- const setTargetUrl = (0, import_react29.useCallback)(
6898
+ const setTargetUrl = (0, import_react30.useCallback)(
6855
6899
  (url, shimmerType = "light") => {
6856
6900
  const version = ++versionRef.current;
6857
6901
  if (shimmerTimerRef.current) {
@@ -6969,7 +7013,7 @@ function useImageTransition(options = {}) {
6969
7013
  },
6970
7014
  [shimmerDelay]
6971
7015
  );
6972
- (0, import_react29.useEffect)(() => {
7016
+ (0, import_react30.useEffect)(() => {
6973
7017
  const topLayer = state.layers[state.layers.length - 1];
6974
7018
  if (topLayer && topLayer.opacity === 0 && !topLayer.waitForLoad) {
6975
7019
  const targetId = topLayer.id;
@@ -6989,7 +7033,7 @@ function useImageTransition(options = {}) {
6989
7033
  return () => cancelAnimationFrame(raf1);
6990
7034
  }
6991
7035
  }, [state.layers]);
6992
- (0, import_react29.useEffect)(() => {
7036
+ (0, import_react30.useEffect)(() => {
6993
7037
  if (state.showShimmer && state.shimmerOpacity === 0 && state.preloadUrl) {
6994
7038
  const raf = requestAnimationFrame(() => {
6995
7039
  if (!isMountedRef.current) return;
@@ -7004,7 +7048,7 @@ function useImageTransition(options = {}) {
7004
7048
  return () => cancelAnimationFrame(raf);
7005
7049
  }
7006
7050
  }, [state.showShimmer, state.shimmerOpacity, state.preloadUrl]);
7007
- (0, import_react29.useEffect)(() => {
7051
+ (0, import_react30.useEffect)(() => {
7008
7052
  if (state.showShimmer && state.shimmerOpacity === 0 && !state.preloadUrl) {
7009
7053
  const duration = state.shimmerType === "dark" ? fadeDuration : shimmerFadeDuration;
7010
7054
  const timer = setTimeout(() => {
@@ -7013,7 +7057,7 @@ function useImageTransition(options = {}) {
7013
7057
  return () => clearTimeout(timer);
7014
7058
  }
7015
7059
  }, [state.showShimmer, state.shimmerOpacity, state.preloadUrl, state.shimmerType, fadeDuration, shimmerFadeDuration]);
7016
- const onLayerTransitionEnd = (0, import_react29.useCallback)((layerId) => {
7060
+ const onLayerTransitionEnd = (0, import_react30.useCallback)((layerId) => {
7017
7061
  setState((prev) => {
7018
7062
  const idx = prev.layers.findIndex((l) => l.id === layerId);
7019
7063
  if (idx === -1 || prev.layers[idx].opacity !== 1) return prev;
@@ -7027,11 +7071,11 @@ function useImageTransition(options = {}) {
7027
7071
  return prev;
7028
7072
  });
7029
7073
  }, []);
7030
- const onPreloadComplete = (0, import_react29.useCallback)((_loadedUrl) => {
7074
+ const onPreloadComplete = (0, import_react30.useCallback)((_loadedUrl) => {
7031
7075
  }, []);
7032
- const onPreloadError = (0, import_react29.useCallback)(() => {
7076
+ const onPreloadError = (0, import_react30.useCallback)(() => {
7033
7077
  }, []);
7034
- const addLayerDirectly = (0, import_react29.useCallback)((url, options2) => {
7078
+ const addLayerDirectly = (0, import_react30.useCallback)((url, options2) => {
7035
7079
  const shouldShowShimmer = options2?.showShimmer ?? true;
7036
7080
  const skipTransition = options2?.skipTransition ?? false;
7037
7081
  const currentVersion = ++versionRef.current;
@@ -7122,7 +7166,7 @@ function useImageTransition(options = {}) {
7122
7166
  }, 500);
7123
7167
  }
7124
7168
  }, []);
7125
- const triggerShimmer = (0, import_react29.useCallback)((type = "dark") => {
7169
+ const triggerShimmer = (0, import_react30.useCallback)((type = "dark") => {
7126
7170
  setState((prev) => {
7127
7171
  if (prev.layers.length === 0) {
7128
7172
  return prev;
@@ -7141,7 +7185,7 @@ function useImageTransition(options = {}) {
7141
7185
  };
7142
7186
  });
7143
7187
  }, []);
7144
- const onImageLoad = (0, import_react29.useCallback)((layerId) => {
7188
+ const onImageLoad = (0, import_react30.useCallback)((layerId) => {
7145
7189
  if (shimmerTimerRef.current) {
7146
7190
  clearTimeout(shimmerTimerRef.current);
7147
7191
  shimmerTimerRef.current = null;
@@ -7183,7 +7227,7 @@ function useImageTransition(options = {}) {
7183
7227
  }
7184
7228
 
7185
7229
  // src/hooks/useImagePreloader.ts
7186
- var import_react30 = require("react");
7230
+ var import_react31 = require("react");
7187
7231
 
7188
7232
  // src/hooks/visibility/observerPool.ts
7189
7233
  var observerCallbacks = /* @__PURE__ */ new WeakMap();
@@ -7245,12 +7289,12 @@ function getObservedElementCount() {
7245
7289
  // src/hooks/useImagePreloader.ts
7246
7290
  function useImagePreloader(options = {}) {
7247
7291
  const { preloadMargin = 1e3, maxConcurrent = 2 } = options;
7248
- const [preloadedUrls, setPreloadedUrls] = (0, import_react30.useState)(/* @__PURE__ */ new Set());
7249
- const entriesRef = (0, import_react30.useRef)(/* @__PURE__ */ new Map());
7250
- const preloadingCountRef = (0, import_react30.useRef)(0);
7251
- const preloadQueueRef = (0, import_react30.useRef)([]);
7252
- const preloadingUrlsRef = (0, import_react30.useRef)(/* @__PURE__ */ new Set());
7253
- const processQueue = (0, import_react30.useCallback)(() => {
7292
+ const [preloadedUrls, setPreloadedUrls] = (0, import_react31.useState)(/* @__PURE__ */ new Set());
7293
+ const entriesRef = (0, import_react31.useRef)(/* @__PURE__ */ new Map());
7294
+ const preloadingCountRef = (0, import_react31.useRef)(0);
7295
+ const preloadQueueRef = (0, import_react31.useRef)([]);
7296
+ const preloadingUrlsRef = (0, import_react31.useRef)(/* @__PURE__ */ new Set());
7297
+ const processQueue = (0, import_react31.useCallback)(() => {
7254
7298
  while (preloadingCountRef.current < maxConcurrent && preloadQueueRef.current.length > 0) {
7255
7299
  const src = preloadQueueRef.current.shift();
7256
7300
  if (preloadingUrlsRef.current.has(src) || preloadedUrls.has(src)) {
@@ -7275,17 +7319,17 @@ function useImagePreloader(options = {}) {
7275
7319
  img.onerror = handleComplete;
7276
7320
  }
7277
7321
  }, [maxConcurrent, preloadedUrls]);
7278
- const observerOptionsRef = (0, import_react30.useRef)({
7322
+ const observerOptionsRef = (0, import_react31.useRef)({
7279
7323
  rootMargin: `${preloadMargin}px 0px`,
7280
7324
  threshold: 0
7281
7325
  });
7282
- (0, import_react30.useEffect)(() => {
7326
+ (0, import_react31.useEffect)(() => {
7283
7327
  observerOptionsRef.current = {
7284
7328
  rootMargin: `${preloadMargin}px 0px`,
7285
7329
  threshold: 0
7286
7330
  };
7287
7331
  }, [preloadMargin]);
7288
- const registerElement = (0, import_react30.useCallback)(
7332
+ const registerElement = (0, import_react31.useCallback)(
7289
7333
  (key, element, src) => {
7290
7334
  const entries = entriesRef.current;
7291
7335
  const existingEntry = entries.get(key);
@@ -7349,14 +7393,14 @@ function useImagePreloader(options = {}) {
7349
7393
  },
7350
7394
  [preloadedUrls, processQueue]
7351
7395
  );
7352
- const isPreloaded = (0, import_react30.useCallback)(
7396
+ const isPreloaded = (0, import_react31.useCallback)(
7353
7397
  (src) => {
7354
7398
  if (!src) return false;
7355
7399
  return preloadedUrls.has(src);
7356
7400
  },
7357
7401
  [preloadedUrls]
7358
7402
  );
7359
- (0, import_react30.useEffect)(() => {
7403
+ (0, import_react31.useEffect)(() => {
7360
7404
  return () => {
7361
7405
  entriesRef.current.forEach((entry) => {
7362
7406
  if (entry.unobserve) {
@@ -7374,11 +7418,11 @@ function useImagePreloader(options = {}) {
7374
7418
  }
7375
7419
 
7376
7420
  // src/hooks/useDeviceDetection.ts
7377
- var import_react31 = require("react");
7421
+ var import_react32 = require("react");
7378
7422
  function useDeviceDetection() {
7379
- const [isTouchDevice, setIsTouchDevice] = (0, import_react31.useState)(false);
7380
- const [isSafari, setIsSafari] = (0, import_react31.useState)(false);
7381
- (0, import_react31.useEffect)(() => {
7423
+ const [isTouchDevice, setIsTouchDevice] = (0, import_react32.useState)(false);
7424
+ const [isSafari, setIsSafari] = (0, import_react32.useState)(false);
7425
+ (0, import_react32.useEffect)(() => {
7382
7426
  const hasTouch = "ontouchstart" in window || navigator.maxTouchPoints > 0;
7383
7427
  setIsTouchDevice(hasTouch);
7384
7428
  const userAgent = navigator.userAgent;
@@ -7397,51 +7441,51 @@ function useDeviceDetection() {
7397
7441
  }
7398
7442
 
7399
7443
  // src/hooks/useProductPage.ts
7400
- var import_react33 = require("react");
7444
+ var import_react34 = require("react");
7401
7445
 
7402
7446
  // src/patterns/MockupPriorityProvider.tsx
7403
- var import_react32 = require("react");
7404
- var import_jsx_runtime52 = require("react/jsx-runtime");
7447
+ var import_react33 = require("react");
7448
+ var import_jsx_runtime53 = require("react/jsx-runtime");
7405
7449
  var MAX_LEVEL3_PREFETCH = 5;
7406
7450
  var PRIORITY_RECALC_DEBOUNCE_MS = 50;
7407
7451
  var PRELOAD_MARGIN_PX = 750;
7408
- var MockupPriorityContext = (0, import_react32.createContext)(
7452
+ var MockupPriorityContext = (0, import_react33.createContext)(
7409
7453
  void 0
7410
7454
  );
7411
7455
  function MockupPriorityProvider({ children }) {
7412
- (0, import_react32.useEffect)(() => {
7456
+ (0, import_react33.useEffect)(() => {
7413
7457
  return () => {
7414
7458
  };
7415
7459
  }, []);
7416
- const visibilityMapRef = (0, import_react32.useRef)(/* @__PURE__ */ new Map());
7417
- const prioritiesRef = (0, import_react32.useRef)(/* @__PURE__ */ new Map());
7418
- const level1MockupRef = (0, import_react32.useRef)(null);
7419
- const level2MockupsRef = (0, import_react32.useRef)([]);
7420
- const level3QueueRef = (0, import_react32.useRef)([]);
7421
- const mobileCarouselRef = (0, import_react32.useRef)(null);
7422
- const registrationOrderRef = (0, import_react32.useRef)([]);
7423
- const elementRefsRef = (0, import_react32.useRef)(/* @__PURE__ */ new Map());
7424
- const prioritySubscribersRef = (0, import_react32.useRef)(
7460
+ const visibilityMapRef = (0, import_react33.useRef)(/* @__PURE__ */ new Map());
7461
+ const prioritiesRef = (0, import_react33.useRef)(/* @__PURE__ */ new Map());
7462
+ const level1MockupRef = (0, import_react33.useRef)(null);
7463
+ const level2MockupsRef = (0, import_react33.useRef)([]);
7464
+ const level3QueueRef = (0, import_react33.useRef)([]);
7465
+ const mobileCarouselRef = (0, import_react33.useRef)(null);
7466
+ const registrationOrderRef = (0, import_react33.useRef)([]);
7467
+ const elementRefsRef = (0, import_react33.useRef)(/* @__PURE__ */ new Map());
7468
+ const prioritySubscribersRef = (0, import_react33.useRef)(
7425
7469
  /* @__PURE__ */ new Map()
7426
7470
  );
7427
- const level1SubscribersRef = (0, import_react32.useRef)(
7471
+ const level1SubscribersRef = (0, import_react33.useRef)(
7428
7472
  /* @__PURE__ */ new Set()
7429
7473
  );
7430
7474
  const scrollState = useScrollDirection();
7431
- const scrollDirectionRef = (0, import_react32.useRef)("idle");
7475
+ const scrollDirectionRef = (0, import_react33.useRef)("idle");
7432
7476
  scrollDirectionRef.current = scrollState.direction;
7433
- const recalcTimeoutRef = (0, import_react32.useRef)(null);
7434
- const pendingRafRef = (0, import_react32.useRef)(null);
7435
- const [level1MockupId, setLevel1MockupId] = (0, import_react32.useState)(null);
7477
+ const recalcTimeoutRef = (0, import_react33.useRef)(null);
7478
+ const pendingRafRef = (0, import_react33.useRef)(null);
7479
+ const [level1MockupId, setLevel1MockupId] = (0, import_react33.useState)(null);
7436
7480
  const realtimeContext = useRealtimeOptional();
7437
- const currentRenderingLevelRef = (0, import_react32.useRef)(null);
7438
- const pendingMockupsRef = (0, import_react32.useRef)(/* @__PURE__ */ new Set());
7439
- const renderedMockupsRef = (0, import_react32.useRef)(/* @__PURE__ */ new Set());
7440
- const lastPendingBlobTimeRef = (0, import_react32.useRef)(0);
7481
+ const currentRenderingLevelRef = (0, import_react33.useRef)(null);
7482
+ const pendingMockupsRef = (0, import_react33.useRef)(/* @__PURE__ */ new Set());
7483
+ const renderedMockupsRef = (0, import_react33.useRef)(/* @__PURE__ */ new Set());
7484
+ const lastPendingBlobTimeRef = (0, import_react33.useRef)(0);
7441
7485
  const DRAG_STOP_DEBOUNCE_MS = 250;
7442
7486
  const BLOB_SEND_DELAY_MS = 100;
7443
- const pendingBlobRequestTimeoutRef = (0, import_react32.useRef)(null);
7444
- const requestMockupsForLevel = (0, import_react32.useCallback)((level) => {
7487
+ const pendingBlobRequestTimeoutRef = (0, import_react33.useRef)(null);
7488
+ const requestMockupsForLevel = (0, import_react33.useCallback)((level) => {
7445
7489
  if (!realtimeContext?.updateMockupIds) {
7446
7490
  return;
7447
7491
  }
@@ -7469,8 +7513,8 @@ function MockupPriorityProvider({ children }) {
7469
7513
  pendingMockupsRef.current = new Set(mockupIds);
7470
7514
  realtimeContext.updateMockupIds(mockupIds);
7471
7515
  }, [realtimeContext]);
7472
- const levelAdvanceTimeoutRef = (0, import_react32.useRef)(null);
7473
- const handleMockupResult = (0, import_react32.useCallback)((mockupId) => {
7516
+ const levelAdvanceTimeoutRef = (0, import_react33.useRef)(null);
7517
+ const handleMockupResult = (0, import_react33.useCallback)((mockupId) => {
7474
7518
  renderedMockupsRef.current.add(mockupId);
7475
7519
  pendingMockupsRef.current.delete(mockupId);
7476
7520
  const currentLevel = currentRenderingLevelRef.current;
@@ -7506,7 +7550,7 @@ function MockupPriorityProvider({ children }) {
7506
7550
  }
7507
7551
  }
7508
7552
  }, [requestMockupsForLevel]);
7509
- (0, import_react32.useEffect)(() => {
7553
+ (0, import_react33.useEffect)(() => {
7510
7554
  if (!realtimeContext?.subscribeMockupResults) return;
7511
7555
  const unsubscribe = realtimeContext.subscribeMockupResults((results) => {
7512
7556
  results.forEach((result) => {
@@ -7515,13 +7559,13 @@ function MockupPriorityProvider({ children }) {
7515
7559
  });
7516
7560
  return unsubscribe;
7517
7561
  }, [realtimeContext, handleMockupResult]);
7518
- (0, import_react32.useEffect)(() => {
7562
+ (0, import_react33.useEffect)(() => {
7519
7563
  if (realtimeContext?.isConfigured && level1MockupRef.current) {
7520
7564
  renderedMockupsRef.current.clear();
7521
7565
  requestMockupsForLevel(1);
7522
7566
  }
7523
7567
  }, [realtimeContext, requestMockupsForLevel]);
7524
- (0, import_react32.useEffect)(() => {
7568
+ (0, import_react33.useEffect)(() => {
7525
7569
  if (level1MockupId === null) {
7526
7570
  return;
7527
7571
  }
@@ -7531,7 +7575,7 @@ function MockupPriorityProvider({ children }) {
7531
7575
  renderedMockupsRef.current.clear();
7532
7576
  requestMockupsForLevel(1);
7533
7577
  }, [level1MockupId, realtimeContext?.isConfigured, requestMockupsForLevel]);
7534
- (0, import_react32.useEffect)(() => {
7578
+ (0, import_react33.useEffect)(() => {
7535
7579
  if (!realtimeContext?.subscribePendingBlob) return;
7536
7580
  const handlePendingBlob = (placement) => {
7537
7581
  lastPendingBlobTimeRef.current = Date.now();
@@ -7543,7 +7587,7 @@ function MockupPriorityProvider({ children }) {
7543
7587
  const unsubscribe = realtimeContext.subscribePendingBlob(handlePendingBlob);
7544
7588
  return unsubscribe;
7545
7589
  }, [realtimeContext]);
7546
- (0, import_react32.useEffect)(() => {
7590
+ (0, import_react33.useEffect)(() => {
7547
7591
  if (!realtimeContext?.subscribeBlobSent) return;
7548
7592
  const handleBlobSent = (placement) => {
7549
7593
  if (pendingBlobRequestTimeoutRef.current) {
@@ -7560,7 +7604,7 @@ function MockupPriorityProvider({ children }) {
7560
7604
  const unsubscribe = realtimeContext.subscribeBlobSent(handleBlobSent);
7561
7605
  return unsubscribe;
7562
7606
  }, [realtimeContext, requestMockupsForLevel]);
7563
- const recalculatePriorities = (0, import_react32.useCallback)(() => {
7607
+ const recalculatePriorities = (0, import_react33.useCallback)(() => {
7564
7608
  const mobileState = mobileCarouselRef.current;
7565
7609
  if (mobileState && mobileState.mockupIds.length > 0) {
7566
7610
  const { currentIndex, mockupIds } = mobileState;
@@ -7650,7 +7694,7 @@ function MockupPriorityProvider({ children }) {
7650
7694
  subscribers?.forEach((cb) => cb(newLevel));
7651
7695
  });
7652
7696
  }, []);
7653
- const scheduleRecalculation = (0, import_react32.useCallback)(() => {
7697
+ const scheduleRecalculation = (0, import_react33.useCallback)(() => {
7654
7698
  if (recalcTimeoutRef.current) {
7655
7699
  clearTimeout(recalcTimeoutRef.current);
7656
7700
  }
@@ -7659,7 +7703,7 @@ function MockupPriorityProvider({ children }) {
7659
7703
  recalcTimeoutRef.current = null;
7660
7704
  }, PRIORITY_RECALC_DEBOUNCE_MS);
7661
7705
  }, [recalculatePriorities]);
7662
- (0, import_react32.useEffect)(() => {
7706
+ (0, import_react33.useEffect)(() => {
7663
7707
  return () => {
7664
7708
  if (recalcTimeoutRef.current) {
7665
7709
  clearTimeout(recalcTimeoutRef.current);
@@ -7675,7 +7719,7 @@ function MockupPriorityProvider({ children }) {
7675
7719
  }
7676
7720
  };
7677
7721
  }, []);
7678
- const updateVisibilityFromRefs = (0, import_react32.useCallback)(() => {
7722
+ const updateVisibilityFromRefs = (0, import_react33.useCallback)(() => {
7679
7723
  const viewportHeight = typeof window !== "undefined" ? window.innerHeight : 800;
7680
7724
  const viewportWidth = typeof window !== "undefined" ? window.innerWidth : 1200;
7681
7725
  const viewportCenterY = viewportHeight / 2;
@@ -7716,7 +7760,7 @@ function MockupPriorityProvider({ children }) {
7716
7760
  });
7717
7761
  });
7718
7762
  }, []);
7719
- (0, import_react32.useEffect)(() => {
7763
+ (0, import_react33.useEffect)(() => {
7720
7764
  const pollVisibility = () => {
7721
7765
  updateVisibilityFromRefs();
7722
7766
  recalculatePriorities();
@@ -7729,7 +7773,7 @@ function MockupPriorityProvider({ children }) {
7729
7773
  window.removeEventListener("scroll", pollVisibility);
7730
7774
  };
7731
7775
  }, [updateVisibilityFromRefs, recalculatePriorities]);
7732
- const registerMockup = (0, import_react32.useCallback)(
7776
+ const registerMockup = (0, import_react33.useCallback)(
7733
7777
  (mockupId, placement, initialPriority, elementRef) => {
7734
7778
  if (!registrationOrderRef.current.includes(mockupId)) {
7735
7779
  registrationOrderRef.current.push(mockupId);
@@ -7778,7 +7822,7 @@ function MockupPriorityProvider({ children }) {
7778
7822
  },
7779
7823
  []
7780
7824
  );
7781
- const unregisterMockup = (0, import_react32.useCallback)((mockupId) => {
7825
+ const unregisterMockup = (0, import_react33.useCallback)((mockupId) => {
7782
7826
  visibilityMapRef.current.delete(mockupId);
7783
7827
  prioritiesRef.current.delete(mockupId);
7784
7828
  prioritySubscribersRef.current.delete(mockupId);
@@ -7793,7 +7837,7 @@ function MockupPriorityProvider({ children }) {
7793
7837
  scheduleRecalculation();
7794
7838
  }
7795
7839
  }, [scheduleRecalculation]);
7796
- const updateElementRef = (0, import_react32.useCallback)((mockupId, element) => {
7840
+ const updateElementRef = (0, import_react33.useCallback)((mockupId, element) => {
7797
7841
  if (element) {
7798
7842
  const rect = element.getBoundingClientRect();
7799
7843
  if (rect.height === 0 || rect.width === 0) {
@@ -7806,7 +7850,7 @@ function MockupPriorityProvider({ children }) {
7806
7850
  elementRefsRef.current.delete(mockupId);
7807
7851
  }
7808
7852
  }, [updateVisibilityFromRefs, scheduleRecalculation]);
7809
- const reportVisibility = (0, import_react32.useCallback)(
7853
+ const reportVisibility = (0, import_react33.useCallback)(
7810
7854
  (mockupId, ratio, boundingRect) => {
7811
7855
  const existing = visibilityMapRef.current.get(mockupId);
7812
7856
  if (!existing) {
@@ -7855,21 +7899,21 @@ function MockupPriorityProvider({ children }) {
7855
7899
  },
7856
7900
  [scheduleRecalculation, recalculatePriorities]
7857
7901
  );
7858
- const reportMobileCarouselIndex = (0, import_react32.useCallback)(
7902
+ const reportMobileCarouselIndex = (0, import_react33.useCallback)(
7859
7903
  (currentIndex, mockupIds) => {
7860
7904
  mobileCarouselRef.current = { currentIndex, mockupIds };
7861
7905
  recalculatePriorities();
7862
7906
  },
7863
7907
  [recalculatePriorities]
7864
7908
  );
7865
- const clearMobileCarouselMode = (0, import_react32.useCallback)(() => {
7909
+ const clearMobileCarouselMode = (0, import_react33.useCallback)(() => {
7866
7910
  mobileCarouselRef.current = null;
7867
7911
  recalculatePriorities();
7868
7912
  }, [recalculatePriorities]);
7869
- const getPriorityLevel = (0, import_react32.useCallback)((mockupId) => {
7913
+ const getPriorityLevel = (0, import_react33.useCallback)((mockupId) => {
7870
7914
  return prioritiesRef.current.get(mockupId) || 3;
7871
7915
  }, []);
7872
- const getQueuePriority = (0, import_react32.useCallback)((mockupId) => {
7916
+ const getQueuePriority = (0, import_react33.useCallback)((mockupId) => {
7873
7917
  const level = prioritiesRef.current.get(mockupId) || 3;
7874
7918
  switch (level) {
7875
7919
  case 1:
@@ -7882,19 +7926,19 @@ function MockupPriorityProvider({ children }) {
7882
7926
  return 10;
7883
7927
  }
7884
7928
  }, []);
7885
- const getLevel1Mockup = (0, import_react32.useCallback)(() => {
7929
+ const getLevel1Mockup = (0, import_react33.useCallback)(() => {
7886
7930
  return level1MockupRef.current;
7887
7931
  }, []);
7888
- const getLevel2Mockups = (0, import_react32.useCallback)(() => {
7932
+ const getLevel2Mockups = (0, import_react33.useCallback)(() => {
7889
7933
  return [...level2MockupsRef.current];
7890
7934
  }, []);
7891
- const getLevel3Queue = (0, import_react32.useCallback)(() => {
7935
+ const getLevel3Queue = (0, import_react33.useCallback)(() => {
7892
7936
  return [...level3QueueRef.current];
7893
7937
  }, []);
7894
- const getVisibility = (0, import_react32.useCallback)((mockupId) => {
7938
+ const getVisibility = (0, import_react33.useCallback)((mockupId) => {
7895
7939
  return visibilityMapRef.current.get(mockupId) || null;
7896
7940
  }, []);
7897
- const getMockupIdsForLevel = (0, import_react32.useCallback)((level) => {
7941
+ const getMockupIdsForLevel = (0, import_react33.useCallback)((level) => {
7898
7942
  switch (level) {
7899
7943
  case 1:
7900
7944
  return level1MockupRef.current ? [level1MockupRef.current] : [];
@@ -7906,16 +7950,16 @@ function MockupPriorityProvider({ children }) {
7906
7950
  return [];
7907
7951
  }
7908
7952
  }, []);
7909
- const shouldPauseLevel = (0, import_react32.useCallback)((level) => {
7953
+ const shouldPauseLevel = (0, import_react33.useCallback)((level) => {
7910
7954
  if (level === 2) {
7911
7955
  return level1MockupRef.current !== null;
7912
7956
  }
7913
7957
  return level1MockupRef.current !== null || level2MockupsRef.current.length > 0;
7914
7958
  }, []);
7915
- const isLevel1Active = (0, import_react32.useCallback)(() => {
7959
+ const isLevel1Active = (0, import_react33.useCallback)(() => {
7916
7960
  return level1MockupRef.current !== null;
7917
7961
  }, []);
7918
- const subscribePriorityChange = (0, import_react32.useCallback)(
7962
+ const subscribePriorityChange = (0, import_react33.useCallback)(
7919
7963
  (mockupId, callback) => {
7920
7964
  if (!prioritySubscribersRef.current.has(mockupId)) {
7921
7965
  prioritySubscribersRef.current.set(mockupId, /* @__PURE__ */ new Set());
@@ -7935,7 +7979,7 @@ function MockupPriorityProvider({ children }) {
7935
7979
  },
7936
7980
  []
7937
7981
  );
7938
- const subscribeLevel1Change = (0, import_react32.useCallback)(
7982
+ const subscribeLevel1Change = (0, import_react33.useCallback)(
7939
7983
  (callback) => {
7940
7984
  level1SubscribersRef.current.add(callback);
7941
7985
  callback(level1MockupRef.current);
@@ -7945,7 +7989,7 @@ function MockupPriorityProvider({ children }) {
7945
7989
  },
7946
7990
  []
7947
7991
  );
7948
- const contextValue = (0, import_react32.useMemo)(
7992
+ const contextValue = (0, import_react33.useMemo)(
7949
7993
  () => ({
7950
7994
  registerMockup,
7951
7995
  unregisterMockup,
@@ -7985,10 +8029,10 @@ function MockupPriorityProvider({ children }) {
7985
8029
  subscribeLevel1Change
7986
8030
  ]
7987
8031
  );
7988
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(MockupPriorityContext.Provider, { value: contextValue, children });
8032
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(MockupPriorityContext.Provider, { value: contextValue, children });
7989
8033
  }
7990
8034
  function useMockupPriority() {
7991
- const context = (0, import_react32.useContext)(MockupPriorityContext);
8035
+ const context = (0, import_react33.useContext)(MockupPriorityContext);
7992
8036
  if (!context) {
7993
8037
  throw new Error(
7994
8038
  "useMockupPriority must be used within a MockupPriorityProvider"
@@ -7997,7 +8041,7 @@ function useMockupPriority() {
7997
8041
  return context;
7998
8042
  }
7999
8043
  function useMockupPriorityOptional() {
8000
- return (0, import_react32.useContext)(MockupPriorityContext);
8044
+ return (0, import_react33.useContext)(MockupPriorityContext);
8001
8045
  }
8002
8046
 
8003
8047
  // src/hooks/useProductPage.ts
@@ -8028,7 +8072,7 @@ function useProductPage() {
8028
8072
  const realtime = useRealtimeOptional();
8029
8073
  const priority = useMockupPriorityOptional();
8030
8074
  const providers = useProviderStatus();
8031
- return (0, import_react33.useMemo)(
8075
+ return (0, import_react34.useMemo)(
8032
8076
  () => ({
8033
8077
  // Product Data
8034
8078
  product: productCtx.product,
@@ -8122,7 +8166,7 @@ function useArtworkAlignment(placement) {
8122
8166
  }
8123
8167
  function useSetArtworkAlignment() {
8124
8168
  const productCtx = useProductOptional();
8125
- return (0, import_react33.useCallback)(
8169
+ return (0, import_react34.useCallback)(
8126
8170
  (placement, alignment) => {
8127
8171
  if (productCtx) {
8128
8172
  const currentDesign = productCtx.placements[placement];
@@ -8139,7 +8183,7 @@ function useSelectedArtwork() {
8139
8183
  const productCtx = useProductOptional();
8140
8184
  const shopCtx = useShopOptional();
8141
8185
  const ctx = productCtx || shopCtx;
8142
- const setArtwork = (0, import_react33.useCallback)(
8186
+ const setArtwork = (0, import_react34.useCallback)(
8143
8187
  (artwork) => {
8144
8188
  ctx?.setSelectedArtwork(artwork);
8145
8189
  },
@@ -8149,7 +8193,7 @@ function useSelectedArtwork() {
8149
8193
  }
8150
8194
  function useProductSelection() {
8151
8195
  const productCtx = useProductOptional();
8152
- const update = (0, import_react33.useCallback)(
8196
+ const update = (0, import_react34.useCallback)(
8153
8197
  (selection) => {
8154
8198
  productCtx?.updateSelection?.(selection);
8155
8199
  },
@@ -8159,7 +8203,7 @@ function useProductSelection() {
8159
8203
  }
8160
8204
  function usePlacementClipShape(placement) {
8161
8205
  const productCtx = useProductOptional();
8162
- const setShape = (0, import_react33.useCallback)(
8206
+ const setShape = (0, import_react34.useCallback)(
8163
8207
  (shape) => {
8164
8208
  productCtx?.setPlacementClipShape(placement, shape);
8165
8209
  },
@@ -8172,10 +8216,10 @@ function usePlacementClipShape(placement) {
8172
8216
  }
8173
8217
 
8174
8218
  // src/hooks/viewport/useMediaQuery.ts
8175
- var import_react34 = require("react");
8219
+ var import_react35 = require("react");
8176
8220
  function useMediaQuery(query) {
8177
- const [matches, setMatches] = (0, import_react34.useState)(null);
8178
- (0, import_react34.useEffect)(() => {
8221
+ const [matches, setMatches] = (0, import_react35.useState)(null);
8222
+ (0, import_react35.useEffect)(() => {
8179
8223
  const media = window.matchMedia(query);
8180
8224
  setMatches(media.matches);
8181
8225
  const listener = () => setMatches(media.matches);
@@ -8186,15 +8230,15 @@ function useMediaQuery(query) {
8186
8230
  }
8187
8231
 
8188
8232
  // src/hooks/viewport/useViewportDimensions.ts
8189
- var import_react35 = require("react");
8233
+ var import_react36 = require("react");
8190
8234
  function useViewportDimensions(isDesktop) {
8191
- const [dimensions, setDimensions] = (0, import_react35.useState)({
8235
+ const [dimensions, setDimensions] = (0, import_react36.useState)({
8192
8236
  width: 0,
8193
8237
  height: 0,
8194
8238
  aspectRatio: 0,
8195
8239
  resizeVersion: 0
8196
8240
  });
8197
- (0, import_react35.useEffect)(() => {
8241
+ (0, import_react36.useEffect)(() => {
8198
8242
  const width = window.innerWidth;
8199
8243
  const height = window.innerHeight;
8200
8244
  setDimensions((prev) => ({
@@ -8205,7 +8249,7 @@ function useViewportDimensions(isDesktop) {
8205
8249
  // Keep at 0 for initial mount
8206
8250
  }));
8207
8251
  }, []);
8208
- (0, import_react35.useLayoutEffect)(() => {
8252
+ (0, import_react36.useLayoutEffect)(() => {
8209
8253
  if (isDesktop !== true) return;
8210
8254
  const width = window.innerWidth;
8211
8255
  const height = window.innerHeight;
@@ -8217,7 +8261,7 @@ function useViewportDimensions(isDesktop) {
8217
8261
  resizeVersion: prev.resizeVersion + 1
8218
8262
  }));
8219
8263
  }, [isDesktop]);
8220
- (0, import_react35.useEffect)(() => {
8264
+ (0, import_react36.useEffect)(() => {
8221
8265
  if (isDesktop !== true) return;
8222
8266
  let resizeTimeout = null;
8223
8267
  let lastWidth = window.innerWidth;
@@ -8258,7 +8302,7 @@ function useViewportDimensions(isDesktop) {
8258
8302
  }
8259
8303
 
8260
8304
  // src/hooks/viewport/useResponsiveImageCap.ts
8261
- var import_react36 = require("react");
8305
+ var import_react37 = require("react");
8262
8306
  var DEFAULT_IMAGE_CONFIG = {
8263
8307
  ASPECT_RATIO: 16 / 9,
8264
8308
  WIDTH_VW: 140,
@@ -8270,7 +8314,7 @@ var DEFAULT_IMAGE_CONFIG = {
8270
8314
  };
8271
8315
  function useResponsiveImageCap(dimensions, options = {}) {
8272
8316
  const { aspectRatio = DEFAULT_IMAGE_CONFIG.ASPECT_RATIO, sidebarWidthPx } = options;
8273
- return (0, import_react36.useMemo)(() => {
8317
+ return (0, import_react37.useMemo)(() => {
8274
8318
  const vw = dimensions.width;
8275
8319
  const vh = dimensions.height;
8276
8320
  const viewportAspectRatio = dimensions.aspectRatio;
@@ -8328,7 +8372,7 @@ function useResponsiveImageCap(dimensions, options = {}) {
8328
8372
  }
8329
8373
 
8330
8374
  // src/hooks/viewport/useWideMonitorMode.ts
8331
- var import_react37 = require("react");
8375
+ var import_react38 = require("react");
8332
8376
  var LAYOUT_CONFIG = {
8333
8377
  SIDEBAR_MAX_PX: 384,
8334
8378
  SIDEBAR_MARGIN_PX: 32,
@@ -8368,7 +8412,7 @@ function hasEdgeBlur(viewportWidth, maxWidthPx, sidebarPercent = 0.35, sidebarWi
8368
8412
  return gap > 10;
8369
8413
  }
8370
8414
  function useWideMonitorMode(imageCapInfo, sidebarPercent) {
8371
- return (0, import_react37.useMemo)(() => {
8415
+ return (0, import_react38.useMemo)(() => {
8372
8416
  const { viewportWidth, maxWidthPx } = imageCapInfo;
8373
8417
  if (viewportWidth < 768) return false;
8374
8418
  const effectiveSidebarPercent = sidebarPercent ?? (viewportWidth >= 1280 ? 0.35 : 0.3);
@@ -8723,8 +8767,8 @@ var CanvasExportService = class _CanvasExportService {
8723
8767
  var canvasExportService = new CanvasExportService();
8724
8768
 
8725
8769
  // src/components/CanvasIsolationBoundary.tsx
8726
- var import_react38 = __toESM(require("react"), 1);
8727
- var import_jsx_runtime53 = require("react/jsx-runtime");
8770
+ var import_react39 = __toESM(require("react"), 1);
8771
+ var import_jsx_runtime54 = require("react/jsx-runtime");
8728
8772
  function CanvasIsolationConfigurator({
8729
8773
  placementName: placementNameProp,
8730
8774
  onArtworkChange,
@@ -8733,7 +8777,7 @@ function CanvasIsolationConfigurator({
8733
8777
  }) {
8734
8778
  const productContext = useProductOptional();
8735
8779
  const realtimeContext = useRealtimeOptional();
8736
- (0, import_react38.useEffect)(() => {
8780
+ (0, import_react39.useEffect)(() => {
8737
8781
  canvasExportService.configure({
8738
8782
  sendCanvasBlob: realtimeContext?.sendCanvasBlob,
8739
8783
  sendCanvasState: realtimeContext?.sendCanvasState,
@@ -8764,16 +8808,16 @@ function CanvasIsolationConfigurator({
8764
8808
  onArtworkChange,
8765
8809
  clearImageBitmapCache
8766
8810
  ]);
8767
- (0, import_react38.useEffect)(() => {
8811
+ (0, import_react39.useEffect)(() => {
8768
8812
  return () => {
8769
8813
  canvasExportService.reset();
8770
8814
  };
8771
8815
  }, []);
8772
8816
  return null;
8773
8817
  }
8774
- var IsolatedChildren = import_react38.default.memo(
8818
+ var IsolatedChildren = import_react39.default.memo(
8775
8819
  function IsolatedChildren2({ children }) {
8776
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_jsx_runtime53.Fragment, { children });
8820
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_jsx_runtime54.Fragment, { children });
8777
8821
  },
8778
8822
  // Custom comparison: ALWAYS return true (never re-render due to parent changes)
8779
8823
  // This is intentional - children should use refs/services for updates that need to bypass this
@@ -8786,8 +8830,8 @@ function CanvasIsolationBoundary({
8786
8830
  clearImageBitmapCache,
8787
8831
  serializeStateForServer
8788
8832
  }) {
8789
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_jsx_runtime53.Fragment, { children: [
8790
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
8833
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_jsx_runtime54.Fragment, { children: [
8834
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
8791
8835
  CanvasIsolationConfigurator,
8792
8836
  {
8793
8837
  placementName,
@@ -8796,7 +8840,7 @@ function CanvasIsolationBoundary({
8796
8840
  serializeStateForServer
8797
8841
  }
8798
8842
  ),
8799
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(IsolatedChildren, { children })
8843
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(IsolatedChildren, { children })
8800
8844
  ] });
8801
8845
  }
8802
8846
  function useIsolatedCanvas() {
@@ -8819,8 +8863,8 @@ function useIsolatedCanvas() {
8819
8863
  }
8820
8864
 
8821
8865
  // src/components/LoadingOverlayPrism.tsx
8822
- var import_react39 = require("react");
8823
- var import_jsx_runtime54 = require("react/jsx-runtime");
8866
+ var import_react40 = require("react");
8867
+ var import_jsx_runtime55 = require("react/jsx-runtime");
8824
8868
  function generateParticles() {
8825
8869
  return Array.from({ length: 16 }, () => ({
8826
8870
  left: 10 + Math.random() * 80,
@@ -8924,18 +8968,18 @@ function LoadingOverlayPrism({
8924
8968
  }) {
8925
8969
  ensureStyles();
8926
8970
  console.log(`[Prism] render visible=${visible}`);
8927
- const [mounted, setMounted] = (0, import_react39.useState)(false);
8928
- (0, import_react39.useEffect)(() => {
8971
+ const [mounted, setMounted] = (0, import_react40.useState)(false);
8972
+ (0, import_react40.useEffect)(() => {
8929
8973
  console.log(`[Prism] MOUNTED \u2014 scheduling fade-in`);
8930
8974
  const raf = requestAnimationFrame(() => setMounted(true));
8931
8975
  return () => cancelAnimationFrame(raf);
8932
8976
  }, []);
8933
- const [particles, setParticles] = (0, import_react39.useState)([]);
8934
- (0, import_react39.useEffect)(() => {
8977
+ const [particles, setParticles] = (0, import_react40.useState)([]);
8978
+ (0, import_react40.useEffect)(() => {
8935
8979
  setParticles(generateParticles());
8936
8980
  }, []);
8937
- const prevVisibleRef = (0, import_react39.useRef)(visible);
8938
- (0, import_react39.useEffect)(() => {
8981
+ const prevVisibleRef = (0, import_react40.useRef)(visible);
8982
+ (0, import_react40.useEffect)(() => {
8939
8983
  if (prevVisibleRef.current && !visible) {
8940
8984
  console.log(`[Prism] visible changed true\u2192false \u2014 FADE-OUT STARTING`);
8941
8985
  } else if (!prevVisibleRef.current && visible) {
@@ -8943,7 +8987,7 @@ function LoadingOverlayPrism({
8943
8987
  }
8944
8988
  prevVisibleRef.current = visible;
8945
8989
  }, [visible]);
8946
- const handleTransitionEnd = (0, import_react39.useCallback)(() => {
8990
+ const handleTransitionEnd = (0, import_react40.useCallback)(() => {
8947
8991
  if (!visible) {
8948
8992
  console.log(`[Prism] FADE-OUT COMPLETE \u2014 calling onExited`);
8949
8993
  onExited?.();
@@ -8957,20 +9001,20 @@ function LoadingOverlayPrism({
8957
9001
  } else if (mounted) {
8958
9002
  fadeClass = " prism-fade-in";
8959
9003
  }
8960
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
9004
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
8961
9005
  "div",
8962
9006
  {
8963
9007
  className: `prism-loading-overlay absolute inset-0${fadeClass}`,
8964
9008
  onTransitionEnd: handleTransitionEnd,
8965
9009
  children: [
8966
- /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "prism-loading-rainbow", children: [
8967
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "prism-loading-band" }),
8968
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "prism-loading-band" }),
8969
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "prism-loading-band" }),
8970
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "prism-loading-band" }),
8971
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "prism-loading-band" })
9010
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "prism-loading-rainbow", children: [
9011
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "prism-loading-band" }),
9012
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "prism-loading-band" }),
9013
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "prism-loading-band" }),
9014
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "prism-loading-band" }),
9015
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "prism-loading-band" })
8972
9016
  ] }),
8973
- particles.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
9017
+ particles.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
8974
9018
  "div",
8975
9019
  {
8976
9020
  className: "prism-loading-particle",
@@ -8992,9 +9036,9 @@ function LoadingOverlayPrism({
8992
9036
  }
8993
9037
  var SHOW_DELAY_MS = 200;
8994
9038
  function useLoadingOverlay(isLoading) {
8995
- const [showOverlay, setShowOverlay] = (0, import_react39.useState)(false);
8996
- const timerRef = (0, import_react39.useRef)(null);
8997
- (0, import_react39.useEffect)(() => {
9039
+ const [showOverlay, setShowOverlay] = (0, import_react40.useState)(false);
9040
+ const timerRef = (0, import_react40.useRef)(null);
9041
+ (0, import_react40.useEffect)(() => {
8998
9042
  if (isLoading) {
8999
9043
  timerRef.current = setTimeout(() => {
9000
9044
  setShowOverlay(true);
@@ -9012,7 +9056,7 @@ function useLoadingOverlay(isLoading) {
9012
9056
  }
9013
9057
  };
9014
9058
  }, [isLoading]);
9015
- const handleExited = (0, import_react39.useCallback)(() => {
9059
+ const handleExited = (0, import_react40.useCallback)(() => {
9016
9060
  setShowOverlay(false);
9017
9061
  }, []);
9018
9062
  return {
@@ -9023,9 +9067,9 @@ function useLoadingOverlay(isLoading) {
9023
9067
  }
9024
9068
 
9025
9069
  // src/components/LoadingOverlayPrismCandy.tsx
9026
- var import_react40 = require("react");
9070
+ var import_react41 = require("react");
9027
9071
  var import_react_dom2 = require("react-dom");
9028
- var import_jsx_runtime55 = require("react/jsx-runtime");
9072
+ var import_jsx_runtime56 = require("react/jsx-runtime");
9029
9073
  var BANDS = [
9030
9074
  { rgb: "230, 45, 55", delay: "-0.0s" },
9031
9075
  // red
@@ -9195,19 +9239,19 @@ function CandyVisual({
9195
9239
  onTransitionEnd,
9196
9240
  variantClass = ""
9197
9241
  }) {
9198
- const [particles, setParticles] = (0, import_react40.useState)([]);
9199
- (0, import_react40.useEffect)(() => {
9242
+ const [particles, setParticles] = (0, import_react41.useState)([]);
9243
+ (0, import_react41.useEffect)(() => {
9200
9244
  setParticles(generateParticles2());
9201
9245
  }, []);
9202
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
9246
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
9203
9247
  "div",
9204
9248
  {
9205
9249
  className: `candy-loading-overlay ${variantClass} ${fadeClass}`.trim(),
9206
9250
  style,
9207
9251
  onTransitionEnd,
9208
9252
  children: [
9209
- BANDS.map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "candy-band" }, `b-${i}`)),
9210
- particles.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
9253
+ BANDS.map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "candy-band" }, `b-${i}`)),
9254
+ particles.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
9211
9255
  "div",
9212
9256
  {
9213
9257
  className: "candy-particle",
@@ -9226,15 +9270,15 @@ function CandyVisual({
9226
9270
  }
9227
9271
  );
9228
9272
  }
9229
- var LoadingOverlayPrismCandy = (0, import_react40.memo)(function LoadingOverlayPrismCandy2({
9273
+ var LoadingOverlayPrismCandy = (0, import_react41.memo)(function LoadingOverlayPrismCandy2({
9230
9274
  visible = true,
9231
9275
  onExited
9232
9276
  }) {
9233
9277
  ensureStyles2();
9234
- const anchorRef = (0, import_react40.useRef)(null);
9235
- const [bounds, setBounds] = (0, import_react40.useState)(null);
9236
- const [mounted, setMounted] = (0, import_react40.useState)(false);
9237
- const measure = (0, import_react40.useCallback)(() => {
9278
+ const anchorRef = (0, import_react41.useRef)(null);
9279
+ const [bounds, setBounds] = (0, import_react41.useState)(null);
9280
+ const [mounted, setMounted] = (0, import_react41.useState)(false);
9281
+ const measure = (0, import_react41.useCallback)(() => {
9238
9282
  const el = anchorRef.current;
9239
9283
  if (!el) return;
9240
9284
  const r = el.getBoundingClientRect();
@@ -9245,7 +9289,7 @@ var LoadingOverlayPrismCandy = (0, import_react40.memo)(function LoadingOverlayP
9245
9289
  height: r.height
9246
9290
  });
9247
9291
  }, []);
9248
- (0, import_react40.useLayoutEffect)(() => {
9292
+ (0, import_react41.useLayoutEffect)(() => {
9249
9293
  measure();
9250
9294
  window.addEventListener("resize", measure);
9251
9295
  let ro = null;
@@ -9258,11 +9302,11 @@ var LoadingOverlayPrismCandy = (0, import_react40.memo)(function LoadingOverlayP
9258
9302
  ro?.disconnect();
9259
9303
  };
9260
9304
  }, [measure]);
9261
- (0, import_react40.useEffect)(() => {
9305
+ (0, import_react41.useEffect)(() => {
9262
9306
  const raf = requestAnimationFrame(() => setMounted(true));
9263
9307
  return () => cancelAnimationFrame(raf);
9264
9308
  }, []);
9265
- const handleTransitionEnd = (0, import_react40.useCallback)(
9309
+ const handleTransitionEnd = (0, import_react41.useCallback)(
9266
9310
  (e) => {
9267
9311
  if (e.propertyName !== "background-color") return;
9268
9312
  if (!visible) onExited?.();
@@ -9272,8 +9316,8 @@ var LoadingOverlayPrismCandy = (0, import_react40.memo)(function LoadingOverlayP
9272
9316
  let fadeClass = "";
9273
9317
  if (!visible) fadeClass = "candy-fade-out";
9274
9318
  else if (mounted) fadeClass = "candy-fade-in";
9275
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(import_jsx_runtime55.Fragment, { children: [
9276
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
9319
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
9320
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
9277
9321
  "div",
9278
9322
  {
9279
9323
  ref: anchorRef,
@@ -9286,7 +9330,7 @@ var LoadingOverlayPrismCandy = (0, import_react40.memo)(function LoadingOverlayP
9286
9330
  }
9287
9331
  ),
9288
9332
  bounds && typeof document !== "undefined" && (0, import_react_dom2.createPortal)(
9289
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
9333
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
9290
9334
  CandyVisual,
9291
9335
  {
9292
9336
  fadeClass,
@@ -9305,19 +9349,19 @@ var LoadingOverlayPrismCandy = (0, import_react40.memo)(function LoadingOverlayP
9305
9349
  )
9306
9350
  ] });
9307
9351
  });
9308
- var LoadingOverlayPrismCandyInline = (0, import_react40.memo)(
9352
+ var LoadingOverlayPrismCandyInline = (0, import_react41.memo)(
9309
9353
  function LoadingOverlayPrismCandyInline2({
9310
9354
  visible = true,
9311
9355
  onExited,
9312
9356
  variant = "dark"
9313
9357
  }) {
9314
9358
  ensureStyles2();
9315
- const [mounted, setMounted] = (0, import_react40.useState)(false);
9316
- (0, import_react40.useEffect)(() => {
9359
+ const [mounted, setMounted] = (0, import_react41.useState)(false);
9360
+ (0, import_react41.useEffect)(() => {
9317
9361
  const raf = requestAnimationFrame(() => setMounted(true));
9318
9362
  return () => cancelAnimationFrame(raf);
9319
9363
  }, []);
9320
- const handleTransitionEnd = (0, import_react40.useCallback)(
9364
+ const handleTransitionEnd = (0, import_react41.useCallback)(
9321
9365
  (e) => {
9322
9366
  if (e.propertyName !== "background-color") return;
9323
9367
  if (!visible) onExited?.();
@@ -9327,7 +9371,7 @@ var LoadingOverlayPrismCandyInline = (0, import_react40.memo)(
9327
9371
  let fadeClass = "";
9328
9372
  if (!visible) fadeClass = "candy-fade-out";
9329
9373
  else if (mounted) fadeClass = "candy-fade-in";
9330
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
9374
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
9331
9375
  CandyVisual,
9332
9376
  {
9333
9377
  fadeClass,
@@ -9347,17 +9391,6 @@ var LoadingOverlayPrismCandyInline = (0, import_react40.memo)(
9347
9391
  var import_react71 = require("@snowcone-app/sdk/react");
9348
9392
  var import_sdk11 = require("@snowcone-app/sdk");
9349
9393
 
9350
- // src/patterns/MockupBackground.tsx
9351
- var import_react41 = require("react");
9352
- var import_jsx_runtime56 = require("react/jsx-runtime");
9353
- var MockupBackgroundContext = (0, import_react41.createContext)(void 0);
9354
- function MockupBackground({ bg, children }) {
9355
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(MockupBackgroundContext.Provider, { value: bg, children });
9356
- }
9357
- function useMockupBackgroundOptional() {
9358
- return (0, import_react41.useContext)(MockupBackgroundContext);
9359
- }
9360
-
9361
9394
  // src/patterns/ProductPageProvider.tsx
9362
9395
  var import_jsx_runtime57 = require("react/jsx-runtime");
9363
9396
  function ProductPageProvider({