@depict-ai/ui 4.7.33 → 4.7.35

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.
@@ -12,6 +12,7 @@ function $parcel$export(e, n, v, s) {
12
12
  configurable: true
13
13
  });
14
14
  }
15
+ $parcel$export(module.exports, "ModernResponsiveImage", () => $d212a67662c5cf38$export$140423fa4bfb6d63);
15
16
  $parcel$export(module.exports, "setExtraDisplayTransformers", () => $606c221d98ba4d92$export$f98b8d5ea7207a1);
16
17
  $parcel$export(module.exports, "getExtraDisplayTransformers", () => $606c221d98ba4d92$export$b2d94be4f02525b2);
17
18
  $parcel$export(module.exports, "remap_blocks_to_index", () => $d92f338ba8f9da9b$export$92aa5d691d588f3f);
@@ -54,7 +55,6 @@ $parcel$export(module.exports, "make_accurate_width_accessor", () => $f13855d1b9
54
55
  $parcel$export(module.exports, "RecommendationSlider", () => $72f96c4782db0b1b$export$9574e176201e5e8d);
55
56
  $parcel$export(module.exports, "RecommendationGrid", () => $1f8dbf7e28b3eff2$export$9756467d34d91cdb);
56
57
  $parcel$export(module.exports, "ShopifyResponsiveImg", () => $19950faaac026e09$export$6e5611bc7e57e477);
57
- $parcel$export(module.exports, "makeSizeAccessor", () => $19950faaac026e09$export$e6fffe67d4cdd848);
58
58
  $parcel$export(module.exports, "ImageContainer", () => $93304d59a9747aa6$export$94026ee33dbabc26);
59
59
  $parcel$export(module.exports, "SentryErrorBoundary", () => $edafe91daf3091d7$export$b69d0d92862de18b);
60
60
  $parcel$export(module.exports, "ExtraSentryContextProvider", () => $edafe91daf3091d7$export$240ecf5363d76c0f);
@@ -106,38 +106,245 @@ $parcel$export(module.exports, "SearchField", () => $c0a0659cf97e8eb2$export$316
106
106
  $parcel$export(module.exports, "BreadCrumbs", () => $1f4925833f07df29$export$5b7c3ce0ebe51f86);
107
107
  $parcel$export(module.exports, "QuickLinks", () => $1f4925833f07df29$export$de035477d6fef996);
108
108
  $parcel$export(module.exports, "CategoryPage", () => $14f289047713d67a$export$e2bf8ce7779e827e);
109
+ $parcel$export(module.exports, "makeSizeAccessors", () => $128302ab61dab8f1$export$54c6d6ff54e72743);
109
110
  /*! Depict.ai search and product listing SDK */
110
- const $b757f75811f3261f$export$83d89fbfd8236492 = "4.7.33";
111
-
112
- // Value first so shopify merchants can set (extra) display transformers in the shopify app
113
- // Calling these functions normally doesn't do anything, but our shopify app respects them
114
- // Them being here is value first too because this can be easily imported in the product card editor
115
- let $606c221d98ba4d92$var$extraDisplayTransformers;
116
- const $606c221d98ba4d92$export$b2d94be4f02525b2 = () => $606c221d98ba4d92$var$extraDisplayTransformers;
117
- const $606c221d98ba4d92$export$f98b8d5ea7207a1 = displayTransformers => $606c221d98ba4d92$var$extraDisplayTransformers = displayTransformers;
118
- function $b54e6192d0caa293$export$d9f36cf74e24d595(media_query) {
119
- const signal = $5vyXB$solidjs.createSignal(false);
120
- $5vyXB$solidjs.onCleanup($5vyXB$depictaiutilishared.javascript_media_query(media_query, ({
121
- matches: matches
122
- }) => signal[1](matches)).remove);
123
- return signal[0];
111
+ const $b757f75811f3261f$export$83d89fbfd8236492 = "4.7.35";
112
+ const $84798aaa863a4909$var$ListingContext = /*@__PURE__*/$5vyXB$solidjs.createContext();
113
+ function $84798aaa863a4909$export$e68cff63f76bd15b(props) {
114
+ const our_object = {};
115
+ return $5vyXB$solidjsweb.createComponent($84798aaa863a4909$var$ListingContext.Provider, {
116
+ value: our_object,
117
+ get children() {
118
+ return props.children;
119
+ }
120
+ });
124
121
  }
125
- function $17d06b3bcb035500$export$a79e666719b3647c(cols_at_size_) {
126
- const size_active = $5vyXB$solidjs.createMemo(() => cols_at_size_().map(([n_cols, min_width, max_width]) => {
127
- const media_query = $5vyXB$depictaiutilishared.layout_media_query_header(min_width, max_width).replaceAll("@media", "");
128
- const matches = $b54e6192d0caa293$export$d9f36cf74e24d595(media_query);
129
- return [matches, n_cols];
130
- }));
131
- const n_cols_currently_showing = $5vyXB$solidjs.createMemo(() => {
132
- try {
133
- const [, n_cols_currently_showing] = size_active().find(([media_query]) => media_query());
134
- return n_cols_currently_showing;
135
- } catch (e) {
136
- $5vyXB$depictaiutilishared.dwarn("No active size found in columnsAtSize - can't render content blocks or looks");
137
- return null;
122
+ function $84798aaa863a4909$export$8d0c4fdbb05a2f2e() {
123
+ return $5vyXB$solidjs.useContext($84798aaa863a4909$var$ListingContext);
124
+ }
125
+ var $93304d59a9747aa6$var$_tmpl$ = ["<div", ' style="', '"', ">", "</div>"];
126
+ function $93304d59a9747aa6$export$94026ee33dbabc26(props) {
127
+ return $5vyXB$solidjsweb.ssr($93304d59a9747aa6$var$_tmpl$, $5vyXB$solidjsweb.ssrHydrationKey(), $5vyXB$solidjsweb.ssrStyle(`padding-bottom:calc(calc(1 / ${props.aspectRatio}) * 100%)`), $5vyXB$solidjsweb.ssrAttribute("class", "s-image-container" + (props.class ? " " + $5vyXB$solidjsweb.escape(props.class, true) : ""), false), $5vyXB$solidjsweb.escape(props.children));
128
+ }
129
+ const $129b9b9c010039d0$var$ProductCardIndexContext = /*@__PURE__*/$5vyXB$solidjs.createContext();
130
+ function $129b9b9c010039d0$export$11354f017ddc9790(props) {
131
+ return $5vyXB$solidjsweb.createComponent($129b9b9c010039d0$var$ProductCardIndexContext.Provider, {
132
+ get value() {
133
+ return props.index_;
134
+ },
135
+ get children() {
136
+ return props.children;
138
137
  }
139
138
  });
140
- return n_cols_currently_showing;
139
+ }
140
+ function $129b9b9c010039d0$export$e3faf4d95300054f() {
141
+ return $5vyXB$solidjs.useContext($129b9b9c010039d0$var$ProductCardIndexContext);
142
+ }
143
+ let $3ea8e0af95b5b7d2$var$browserIsBugged = false;
144
+ function $3ea8e0af95b5b7d2$export$2972b890694ced75(callback, {
145
+ timeout: timeout
146
+ }) {
147
+ if ($3ea8e0af95b5b7d2$var$browserIsBugged) timeout /= 4;
148
+ const cancel = () => {
149
+ cancelIdleCallback(idleHandle);
150
+ clearTimeout(racingTimeout);
151
+ };
152
+ const idleHandle = requestIdleCallback(deadline => {
153
+ cancel();
154
+ return callback(deadline);
155
+ }, {
156
+ timeout: timeout
157
+ });
158
+ const racingTimeout = setTimeout(() => {
159
+ $5vyXB$depictaiutilishared.dwarn("Browser did not respect requestIdleCallback timeout");
160
+ $3ea8e0af95b5b7d2$var$browserIsBugged = true;
161
+ cancel();
162
+ callback({
163
+ didTimeout: false,
164
+ timeRemaining() {
165
+ return 500;
166
+ }
167
+ });
168
+ }, timeout + 1000);
169
+ return cancel;
170
+ }
171
+ const $19950faaac026e09$var$onIdleFunctionsSymbol = /*@__PURE__*/Symbol("onIdleFunctions");
172
+ const $19950faaac026e09$export$f8945274f08a3105 = /*@__PURE__*/Symbol("listingContextAspectRatios");
173
+ const $19950faaac026e09$export$6066eb417ed2e9f7 = /*@__PURE__*/Symbol("listingContextAspectRatios");
174
+ function $19950faaac026e09$export$6e5611bc7e57e477(props) {
175
+ const img = new Image(); // Need to use new Image or browser might not start loading image before it's in the DOM
176
+ const [ourRatioKeyed, setOurRatioKeyed] = $5vyXB$solidjs.createSignal();
177
+ const sizeToUse = $5vyXB$solidjs.createMemo(() => {
178
+ // props.size could be a getter that expects a cleanup so get it in this memo instead of where we set img.sizes (also we need to multiply, and it's good with some diffing here so people calling the comp don't have to)
179
+ const incomingSize = props.size();
180
+ const ratio = ourRatioKeyed();
181
+ const containerHeight = props.sizeHeight?.();
182
+ if (!incomingSize || !ratio || !containerHeight || getComputedStyle(img).objectFit !== "cover") return incomingSize;
183
+ const maybeCorrectedSize = ratio * containerHeight;
184
+ return Math.round(Math.max(incomingSize, maybeCorrectedSize));
185
+ });
186
+ const src_options = $5vyXB$solidjs.createMemo(() => {
187
+ const {
188
+ src: src,
189
+ customUrls: customUrls
190
+ } = props;
191
+ const fallback_src = (customUrls || $19950faaac026e09$export$1d6267828870adda)(src, 400);
192
+ const srcset = $19950faaac026e09$var$make_srcset(props.src, props.resolutions || [64, 128, 256, 300, 400, 512, 640, 768, 1024, 1280, 1536, 2048, 2560, 3072, 3584, 4096], customUrls);
193
+ // The order here *might* matter - I've seen mobile safari always start with loading the 400px version when it was reversed
194
+ return {
195
+ srcset: srcset,
196
+ src: fallback_src
197
+ };
198
+ });
199
+ // Work around https://github.com/solidjs/solid/issues/1828
200
+ const [, otherAttributes] = $5vyXB$solidjs.splitProps(props, ["resolutions", "size", "src", "srcSet", "loading", "keyRatioUpdating", "sizeHeight", "customUrls" // Can't have properties ending on underscore because the property name mangling will get confused by this <-
201
+ ]);
202
+
203
+ const [hasSetSize, setHasSetSize] = $5vyXB$solidjs.createSignal(false);
204
+ const [hasDecoded, setHasDecoded] = $5vyXB$solidjs.createSignal(false);
205
+ const productCardIndexAccessor = $129b9b9c010039d0$export$e3faf4d95300054f();
206
+ const listingContext = $84798aaa863a4909$export$8d0c4fdbb05a2f2e();
207
+ const isPrioritisedImage = $5vyXB$solidjs.createMemo(() => productCardIndexAccessor?.() < 8);
208
+ const shouldActuallyEnableLazyLoading = $5vyXB$solidjs.createMemo(() => {
209
+ const {
210
+ loading: loading
211
+ } = props;
212
+ if (loading === "force-lazy") return true;
213
+ return loading === "lazy" && !isPrioritisedImage();
214
+ });
215
+ const modifiedOtherAttributes = $5vyXB$solidjs.mergeProps(otherAttributes, {
216
+ get loading() {
217
+ return shouldActuallyEnableLazyLoading() ? "lazy" : undefined;
218
+ }
219
+ });
220
+ // Batch idle callbacks so that MutationObserver can batch the resulting mutations better, so we don't lose tons of CPU time to MutationObservers doing lots of things for each image
221
+ // Happened on singular, they have some weird observer (+we also have one but ours is at least 3x more efficient)
222
+ const executeWhenIdleBatched = (fn, isSizesUpdate) => {
223
+ if (typeof requestIdleCallback !== "function") return setTimeout(fn); // Old browsers don't get optimisation
224
+ if ((!isSizesUpdate || !sizeSetFastPath) && $5vyXB$solidjs.untrack(isPrioritisedImage)) return fn(); // If we're one of the first 8 images, execute the callbacks immediately (improves lighthouse metrics)
225
+ // unless we're just a `sizes` update after the initial sizes setting (this optimisation makes the looks animation a lot smoother on low-cpu devices)
226
+ const existingStack = listingContext?.[$19950faaac026e09$var$onIdleFunctionsSymbol];
227
+ if (existingStack) return existingStack.add(fn);
228
+ const newStack = new Set([fn]);
229
+ if (listingContext) listingContext[$19950faaac026e09$var$onIdleFunctionsSymbol] = newStack;
230
+ const processStackWhenIdle = () => $3ea8e0af95b5b7d2$export$2972b890694ced75($5vyXB$depictaiutilishared.catchify(deadline => {
231
+ const start = performance.now();
232
+ const thirdDeadlineTime = deadline.timeRemaining() / 3; // observers coming after this take up 2-3x the time so don't use all of it
233
+ for (const fn of newStack) {
234
+ newStack.delete(fn);
235
+ fn();
236
+ const timeTaken = performance.now() - start;
237
+ if ((!deadline.timeRemaining() || timeTaken > thirdDeadlineTime) && newStack.size) {
238
+ // There's still work to be done but no time, so schedule another idle callback
239
+ processStackWhenIdle();
240
+ return;
241
+ }
242
+ }
243
+ // Stack is empty
244
+ if (listingContext) delete listingContext[$19950faaac026e09$var$onIdleFunctionsSymbol];
245
+ }), {
246
+ timeout: 15000
247
+ } // long timeout, better to not have images than to freeze the browser. But also we don't want to confuse user why no iamges are loading
248
+ );
249
+
250
+ processStackWhenIdle();
251
+ };
252
+ let sizeSetFastPath = false;
253
+ let hasDecodedFastPath = false;
254
+ let timeoutSet = false;
255
+ let gotCleanedUp = false;
256
+ let srcJustChanged = true;
257
+ img.classList.add("s-responsive-image");
258
+ if (listingContext) {
259
+ let prevValue;
260
+ const aspectRatios = listingContext[$19950faaac026e09$export$f8945274f08a3105] ||= new Set();
261
+ const [, setMostPrevalentAspectRatio] = listingContext[$19950faaac026e09$export$6066eb417ed2e9f7] ||= $5vyXB$solidjs.createSignal();
262
+ img.addEventListener("load", $5vyXB$depictaiutilishared.catchify(() => {
263
+ const aspectRatio_ = img.naturalWidth / img.naturalHeight;
264
+ if (srcJustChanged)
265
+ // Always key object-fit-cover compensation to one src, to avoid loading-different-images-infinite-loop
266
+ setOurRatioKeyed(aspectRatio_);else if (props.keyRatioUpdating) return;
267
+ srcJustChanged = false;
268
+ // Save our aspect ratio whenever it changes, so that we can base the containers on the most dominant aspect ratio, used in SearchModalV2 and LookItem
269
+ if (prevValue) aspectRatios.delete(prevValue);
270
+ const newValue = !isNaN(aspectRatio_) ? {
271
+ aspectRatio_: aspectRatio_
272
+ } : undefined;
273
+ if (newValue) aspectRatios.add(newValue);
274
+ prevValue = newValue;
275
+ // Do all calculations resulting of an update directly, for performance
276
+ const asArray = [...aspectRatios].map(({
277
+ aspectRatio_: aspectRatio_
278
+ }) => aspectRatio_);
279
+ const mostPrevalentAspectRatio = $5vyXB$depictaiutilishared.findMostFrequentItem(asArray);
280
+ setMostPrevalentAspectRatio(mostPrevalentAspectRatio);
281
+ }));
282
+ $5vyXB$solidjs.onCleanup(() => prevValue && aspectRatios.delete(prevValue));
283
+ }
284
+ $5vyXB$solidjs.onCleanup(() => gotCleanedUp = true);
285
+ $5vyXB$solidjsweb.spread(img, $5vyXB$solidjs.mergeProps(modifiedOtherAttributes), false, true);
286
+ $5vyXB$solidjs.createRenderEffect(() => {
287
+ props.src;
288
+ srcJustChanged = true;
289
+ });
290
+ $5vyXB$solidjs.createEffect(() => {
291
+ if (!sizeToUse()) return; // wait until we have a size, run every time the size changes
292
+ if (timeoutSet) return;
293
+ const handler = $5vyXB$depictaiutilishared.catchify(() => {
294
+ if (gotCleanedUp) return;
295
+ img.sizes = `${sizeToUse()}px`; // use latest available value of size in case it has changed
296
+ if (!sizeSetFastPath) {
297
+ setHasSetSize(true);
298
+ sizeSetFastPath = true;
299
+ }
300
+ timeoutSet = false;
301
+ });
302
+ // Throttle the updating of sizes to avoid unnecessary image re-fetches during resize
303
+ // And also because we first set src after sizes has been set, wait with loading and decoding images until browser is idle
304
+ // This greatly improves performance when loading (more) products
305
+ // See https://depictaiworkspace.slack.com/archives/C05NJ0K3WRL/p1698220617663139
306
+ timeoutSet = true; // Important to set timeoutSet before the call to executeWhenIdleBatched since if this is an important image executeWhenIdleBatched will execute fn immediately
307
+ executeWhenIdleBatched(handler, true);
308
+ });
309
+ const dontLoadImageYet = $5vyXB$solidjs.createMemo(() => !sizeToUse() || !hasSetSize()); // Moving this condition into a memo saves us from re-setting src and srcset (expensive) if just props.size changes
310
+ $5vyXB$solidjs.createEffect(() => {
311
+ if (dontLoadImageYet()) return; // If size isn't known or set, don't assign src yet since it would cause the most low res image to load
312
+ Object.assign(img, src_options());
313
+ // Add to DOM once decoded to not require/block any paints before image has completed loading and avoid showing broken image symbol
314
+ // We can do this because there has to be a container around us giving us a size
315
+ // No need to listen if we're already in the DOM
316
+ if (hasDecodedFastPath) return;
317
+ if (shouldActuallyEnableLazyLoading()) {
318
+ // For lazy loading there's no decoding to wait for as it only occurs when the image is visible
319
+ // Make sure src is set before we put the image into the DOM though so no broken image symbol is shown
320
+ setHasDecoded(true);
321
+ hasDecodedFastPath = true;
322
+ return;
323
+ }
324
+ img.decode().catch(e => $5vyXB$depictaiutilishared.dwarn("Failed to decode image", e, img)) // Display the image also if loading failed so webdev can debug and doesn't get "no image"
325
+ .then(async () => {
326
+ // Also wait with inserting image (i.e. paint) until browser is idle
327
+ await new Promise(r => executeWhenIdleBatched(r, false));
328
+ if (gotCleanedUp) return;
329
+ setHasDecoded(true);
330
+ hasDecodedFastPath = true;
331
+ });
332
+ });
333
+ return $5vyXB$solidjsweb.createComponent((0, $5vyXB$solidjs.Show), {
334
+ get when() {
335
+ return hasDecoded();
336
+ },
337
+ children: img
338
+ });
339
+ }
340
+ function $19950faaac026e09$var$make_srcset(url, resolutions, customGenerateImageUrl_) {
341
+ return resolutions.map(width => `${(customGenerateImageUrl_ || $19950faaac026e09$export$1d6267828870adda)(url, width)} ${width}w`).join(", ");
342
+ }
343
+ function $19950faaac026e09$export$1d6267828870adda(url, width) {
344
+ // Even just creating one `URL` object per image src and then setting the search parameter is quite slow (0.25ms to set the width param)
345
+ // We're making the assumptions that the url has already at least one query parameter and that the image resizing service will choose the last one out of a duplicate width parameter (shopify's does)
346
+ // That way we can just to string concatenation which is insanely fast
347
+ return url + "&width=" + encodeURIComponent(width);
141
348
  }
142
349
  var $9fe9883b1d8ecccc$var$_tmpl$ = ["<span", ' class="', '" style="', '"></span>'];
143
350
  function $9fe9883b1d8ecccc$export$acb3eaade4b23afd(props) {
@@ -175,19 +382,190 @@ function $3bc4a89b971a3af5$export$3f37af283f8fb843(props) {
175
382
  }
176
383
  });
177
384
  }
178
- var $d92f338ba8f9da9b$var$_tmpl$ = ["<div", ' class="', '" style="', '">', "</div>"];
179
- function $d92f338ba8f9da9b$export$791ef57e62e21c3f({
180
- content_blocks_: incoming_content_blocks,
181
- cols_at_size_: cols_at_size_,
182
- set_top_row_shortened_by_: set_top_row_shortened_by_
183
- }) {
184
- // these are by row
185
- const [content_blocks, set_content_blocks] = $5vyXB$solidjsstore.createStore([]);
186
- const n_cols_currently_showing_ = $17d06b3bcb035500$export$a79e666719b3647c(cols_at_size_);
187
- $5vyXB$solidjs.createEffect(() => {
188
- const incoming_value = incoming_content_blocks();
189
- if (!incoming_value) {
190
- set_content_blocks([]);
385
+ function $061ff5b4c3d36171$export$89c6019e4baa40b1(props) {
386
+ const style = $5vyXB$solidjs.createMemo(() => {
387
+ const {
388
+ style: style,
389
+ height: height,
390
+ width: width
391
+ } = props;
392
+ return {
393
+ ...(style || {}),
394
+ height: height ?? "1em",
395
+ ...(width && {
396
+ width: width
397
+ })
398
+ };
399
+ });
400
+ return $5vyXB$solidjsweb.createComponent((0, $9fe9883b1d8ecccc$export$acb3eaade4b23afd), {
401
+ get style() {
402
+ return style();
403
+ },
404
+ get ["class"]() {
405
+ return props.class;
406
+ }
407
+ });
408
+ }
409
+ var $6f604560873e4f69$var$_tmpl$ = ["<div", ' class="instant-card"><div class="img-part">', '</div><div class="right-part"><div class="title-brand-tagline"><span class="title">', '</span></div><div class="price-container">', "</div></div></div>"];
410
+ const $6f604560873e4f69$export$8a2234b5b1a5ebd4 = "--image-aspect-ratio";
411
+ function $6f604560873e4f69$export$ee1733d9a8495996() {
412
+ return $5vyXB$solidjsweb.ssr($6f604560873e4f69$var$_tmpl$, $5vyXB$solidjsweb.ssrHydrationKey(), $5vyXB$solidjsweb.escape($5vyXB$solidjsweb.createComponent((0, $3bc4a89b971a3af5$export$3f37af283f8fb843), {
413
+ aspectRatio: `var(${$6f604560873e4f69$export$8a2234b5b1a5ebd4}, 1)`
414
+ })), $5vyXB$solidjsweb.escape($5vyXB$solidjsweb.createComponent((0, $061ff5b4c3d36171$export$89c6019e4baa40b1), {
415
+ width: "20ch",
416
+ height: "1em"
417
+ })), $5vyXB$solidjsweb.escape($5vyXB$solidjsweb.createComponent((0, $061ff5b4c3d36171$export$89c6019e4baa40b1), {
418
+ width: "5ch",
419
+ height: "1em",
420
+ "class": "price"
421
+ })));
422
+ }
423
+ function $128302ab61dab8f1$export$54c6d6ff54e72743(whatToWatch) {
424
+ const [width, setWidth] = $5vyXB$solidjs.createSignal(0);
425
+ const [height, setHeight] = $5vyXB$solidjs.createSignal(0);
426
+ const resizeObserver = new ResizeObserver($5vyXB$depictaiutilishared.catchify(records => $5vyXB$solidjs.batch(() => {
427
+ for (let j = 0; j < records.length; j++) {
428
+ const {
429
+ width: width,
430
+ height: height
431
+ } = records[j].contentRect;
432
+ // Padding hack makes that we can't use contentRect to get the height since that's apparently without padding
433
+ const definitiveHeight = height || whatToWatch.getBoundingClientRect().height;
434
+ if (definitiveHeight) setHeight(Math.ceil(definitiveHeight));
435
+ if (width) setWidth(Math.ceil(width));
436
+ }
437
+ })));
438
+ // If we start observing elements before they're in the DOM Chrome (Version 117.0.5938.92 (Official Build) (arm64)) sometimes gives us a resize event with a width of 0 and then doesn't dispatch one with the actual width once it's in the DOM. So we wait until the element is in the DOM before we start observing it.
439
+ // It doesn't seem to work even when waiting for it to be in the DOM, also wait an animation frame
440
+ const disconnect = (0, $5vyXB$depictaiutilishared.observer).onexists(whatToWatch, ({
441
+ element: element
442
+ }) => requestAnimationFrame($5vyXB$depictaiutilishared.catchify(() => resizeObserver.observe(element))));
443
+ $5vyXB$solidjs.onCleanup(() => {
444
+ resizeObserver.disconnect();
445
+ disconnect();
446
+ });
447
+ return [width, height];
448
+ }
449
+ const $a33065cfed827fc0$var$backupSizeSignal = /*@__PURE__*/$5vyXB$solidjs.createSignal();
450
+ const $a33065cfed827fc0$export$d7b7ab832c20e2f4 = /*@__PURE__*/Symbol("ShopifyContainedImage");
451
+ function $a33065cfed827fc0$export$e4b984597b71e989(props) {
452
+ const context = $84798aaa863a4909$export$8d0c4fdbb05a2f2e();
453
+ if (context && !context[$a33065cfed827fc0$export$d7b7ab832c20e2f4])
454
+ // create a signal that's the same for all items in this listing
455
+ context[$a33065cfed827fc0$export$d7b7ab832c20e2f4] = $5vyXB$solidjs.createSignal();
456
+ const [currentImageSize, setCurrentImageSize] = context?.[$a33065cfed827fc0$export$d7b7ab832c20e2f4] || $a33065cfed827fc0$var$backupSizeSignal; // use global fallback signal (might lead to blurry images) if no context is available
457
+ const [mostPrevalentAspectRatio] = context ?
458
+ // If the context exists we have to create the signal here as getting it here would be too late when it's created by ShopifyResponsiveImg below
459
+ context[(0, $19950faaac026e09$export$6066eb417ed2e9f7)] ||= $5vyXB$solidjs.createSignal() : [];
460
+ const container = $93304d59a9747aa6$export$94026ee33dbabc26({
461
+ // Write getters manually instead of using JSX, so we can do more complex logic in the aspectRatio getter without increasing bundle size
462
+ get class() {
463
+ return props.class;
464
+ },
465
+ get aspectRatio() {
466
+ if (props.autoAdjustAspectRatio) {
467
+ const targetRatio = mostPrevalentAspectRatio?.();
468
+ if (targetRatio != undefined) return `var(${(0, $6f604560873e4f69$export$8a2234b5b1a5ebd4)}, ${targetRatio})`;
469
+ }
470
+ return props.aspectRatio;
471
+ }
472
+ });
473
+ const owner = $5vyXB$solidjs.getOwner();
474
+ let createdSizeAccessor = false;
475
+ let wasCleanedUp = false;
476
+ $5vyXB$solidjs.createEffect(() => {
477
+ if (currentImageSize() || wasCleanedUp) return; // We get into the effect when onCleanup is called if we don't have wasCleanedUp
478
+ // ensure we always have a size accessor
479
+ // what this whole thing does is set the sizes attribute to the actual size of one of the existing image containers, therefore the value doesn't have to manually be specified
480
+ createdSizeAccessor = true;
481
+ setCurrentImageSize(() => $5vyXB$solidjs.runWithOwner(owner, () => $128302ab61dab8f1$export$54c6d6ff54e72743(container)));
482
+ });
483
+ $5vyXB$solidjs.onCleanup(() => {
484
+ wasCleanedUp = true; // important to set this before the function call below and always, so the dead effects don't create dead size accessors
485
+ if (!createdSizeAccessor) return;
486
+ $5vyXB$depictaiutilishared.queueMacroTask(() => setCurrentImageSize()); // unset the size accessor next event loop iteration, so that all onCleanup's have time to run, since the effects run more aggressively and can create a size accessor with a cleaned up owner otherwise
487
+ });
488
+
489
+ $5vyXB$solidjsweb.insert(container, $5vyXB$solidjsweb.createComponent((0, $19950faaac026e09$export$6e5611bc7e57e477), $5vyXB$solidjsweb.mergeProps({
490
+ size: () => currentImageSize()?.[0]?.() || 0,
491
+ sizeHeight: () => currentImageSize()?.[1]?.() || 0,
492
+ get src() {
493
+ return props.src;
494
+ }
495
+ }, () => props.imgProps, {
496
+ get style() {
497
+ return props.imgProps?.style;
498
+ }
499
+ })));
500
+ return container;
501
+ }
502
+ const $d212a67662c5cf38$var$customUrls = (url, width) => {
503
+ if (url?.startsWith?.("https://cdn.shopify.com"))
504
+ // The shopify image resizing CDN blocks Cloudflare's image resizer. It's possible that we can't detect shopify image URLs sometimes because they go to the merchant's domain,
505
+ // but it seems like the URLs returned by the Depict API always goes to the cdn.shopify.com version of an image, so this simple workaround works.
506
+ return $19950faaac026e09$export$1d6267828870adda(url, width);
507
+ // Use cloudflare image resizer instead of img.depict.ai because it's a lot faster (and also auto-chooses other formats if webp is not supported)
508
+ return `https://app.depict.ai/cdn-cgi/image/width=${width},format=auto/${url}`;
509
+ };
510
+ function $d212a67662c5cf38$export$9d4a4b669b1929ab(props) {
511
+ return $5vyXB$solidjsweb.createComponent((0, $a33065cfed827fc0$export$e4b984597b71e989), $5vyXB$solidjsweb.mergeProps(props, {
512
+ get imgProps() {
513
+ return {
514
+ ...props.imgProps,
515
+ customUrls: $d212a67662c5cf38$var$customUrls
516
+ };
517
+ }
518
+ }));
519
+ }
520
+ function $d212a67662c5cf38$export$140423fa4bfb6d63(props) {
521
+ return $5vyXB$solidjsweb.createComponent((0, $19950faaac026e09$export$6e5611bc7e57e477), $5vyXB$solidjsweb.mergeProps(props, {
522
+ customUrls: $d212a67662c5cf38$var$customUrls
523
+ }));
524
+ }
525
+
526
+ // Value first so shopify merchants can set (extra) display transformers in the shopify app
527
+ // Calling these functions normally doesn't do anything, but our shopify app respects them
528
+ // Them being here is value first too because this can be easily imported in the product card editor
529
+ let $606c221d98ba4d92$var$extraDisplayTransformers;
530
+ const $606c221d98ba4d92$export$b2d94be4f02525b2 = () => $606c221d98ba4d92$var$extraDisplayTransformers;
531
+ const $606c221d98ba4d92$export$f98b8d5ea7207a1 = displayTransformers => $606c221d98ba4d92$var$extraDisplayTransformers = displayTransformers;
532
+ function $b54e6192d0caa293$export$d9f36cf74e24d595(media_query) {
533
+ const signal = $5vyXB$solidjs.createSignal(false);
534
+ $5vyXB$solidjs.onCleanup($5vyXB$depictaiutilishared.javascript_media_query(media_query, ({
535
+ matches: matches
536
+ }) => signal[1](matches)).remove);
537
+ return signal[0];
538
+ }
539
+ function $17d06b3bcb035500$export$a79e666719b3647c(cols_at_size_) {
540
+ const size_active = $5vyXB$solidjs.createMemo(() => cols_at_size_().map(([n_cols, min_width, max_width]) => {
541
+ const media_query = $5vyXB$depictaiutilishared.layout_media_query_header(min_width, max_width).replaceAll("@media", "");
542
+ const matches = $b54e6192d0caa293$export$d9f36cf74e24d595(media_query);
543
+ return [matches, n_cols];
544
+ }));
545
+ const n_cols_currently_showing = $5vyXB$solidjs.createMemo(() => {
546
+ try {
547
+ const [, n_cols_currently_showing] = size_active().find(([media_query]) => media_query());
548
+ return n_cols_currently_showing;
549
+ } catch (e) {
550
+ $5vyXB$depictaiutilishared.dwarn("No active size found in columnsAtSize - can't render content blocks or looks");
551
+ return null;
552
+ }
553
+ });
554
+ return n_cols_currently_showing;
555
+ }
556
+ var $d92f338ba8f9da9b$var$_tmpl$ = ["<div", ' class="', '" style="', '">', "</div>"];
557
+ function $d92f338ba8f9da9b$export$791ef57e62e21c3f({
558
+ content_blocks_: incoming_content_blocks,
559
+ cols_at_size_: cols_at_size_,
560
+ set_top_row_shortened_by_: set_top_row_shortened_by_
561
+ }) {
562
+ // these are by row
563
+ const [content_blocks, set_content_blocks] = $5vyXB$solidjsstore.createStore([]);
564
+ const n_cols_currently_showing_ = $17d06b3bcb035500$export$a79e666719b3647c(cols_at_size_);
565
+ $5vyXB$solidjs.createEffect(() => {
566
+ const incoming_value = incoming_content_blocks();
567
+ if (!incoming_value) {
568
+ set_content_blocks([]);
191
569
  return;
192
570
  }
193
571
  set_content_blocks($5vyXB$solidjsstore.reconcile(incoming_value, {
@@ -504,20 +882,6 @@ function $5f7d55c710fd1bc2$var$unwrapping_helper(elements) {
504
882
  } else if (typeof elements == "function") result.push(...$5f7d55c710fd1bc2$var$unwrapping_helper(elements()));else if (elements != undefined && typeof elements != "boolean") result.push(elements);
505
883
  return result;
506
884
  }
507
- const $129b9b9c010039d0$var$ProductCardIndexContext = /*@__PURE__*/$5vyXB$solidjs.createContext();
508
- function $129b9b9c010039d0$export$11354f017ddc9790(props) {
509
- return $5vyXB$solidjsweb.createComponent($129b9b9c010039d0$var$ProductCardIndexContext.Provider, {
510
- get value() {
511
- return props.index_;
512
- },
513
- get children() {
514
- return props.children;
515
- }
516
- });
517
- }
518
- function $129b9b9c010039d0$export$e3faf4d95300054f() {
519
- return $5vyXB$solidjs.useContext($129b9b9c010039d0$var$ProductCardIndexContext);
520
- }
521
885
 
522
886
  /**
523
887
  * This is a function that will safely clone an object that may contain promises.
@@ -1071,521 +1435,170 @@ function $f48d0fbb00835aaa$export$445d8d3f5f706a40(props, container_element, ins
1071
1435
  const view_less_button_container = $5vyXB$solidjs.createMemo(() => have_a_view_less_button() && $5vyXB$solidjsweb.ssr($f48d0fbb00835aaa$var$_tmpl$, $5vyXB$solidjsweb.ssrHydrationKey(), `load-less-container ${$5vyXB$solidjsweb.escape(view_less_button_class, true)}`, $5vyXB$solidjsweb.escape(rows_or_empty_object().view_less_button)));
1072
1436
  const [force_style_update, set_force_style_update] = $5vyXB$solidjs.createSignal("");
1073
1437
  $5vyXB$solidjs.createComputed(() => {
1074
- // Make sure we don't have more rows visible than max_rows (this could happen by max_rows being decreased)
1075
- const rows_visible = get_rows_visible();
1076
- const max_rows = rows_or_empty_object().max_rows;
1077
- if (!isNaN(max_rows) && max_rows >= 0 && rows_visible > max_rows) set_rows_visible()(max_rows);
1078
- });
1079
- $5vyXB$solidjs.createEffect(() => set_force_style_update(" ")); // force style update after hydration due to https://discord.com/channels/722131463138705510/722167424186843267/1151544212517552168
1080
- $5vyXB$solidjs.createRenderEffect(() => {
1081
- // Be careful to only read show_all_rows in here (ofc doesn't apply to nested effects)
1082
- if (show_all_rows()) {
1083
- // no view more functionality requested
1084
- set_styling(() => col_styling);
1085
- return;
1086
- }
1087
- update_children_count();
1088
- if (!(0, $5vyXB$solidjsweb.isServer)) {
1089
- const mutation_observer = new MutationObserver($5vyXB$depictaiutilishared.catchify(update_children_count));
1090
- mutation_observer.observe(container_element, {
1091
- childList: true
1092
- });
1093
- $5vyXB$solidjs.onCleanup(() => mutation_observer.disconnect());
1094
- }
1095
- set_styling(
1096
- // this is needed because solid will think that the memo-accessor is a setter function otherwise
1097
- () => $5vyXB$solidjs.createMemo(() => {
1098
- const {
1099
- rows_per_click: rows_per_click,
1100
- max_rows = -1,
1101
- start_rows: start_rows
1102
- } = rows_or_empty_object();
1103
- const rows_visible = get_rows_visible();
1104
- const children_count = get_children_count();
1105
- return force_style_update() + col_styling() + props.cols_at_size.map(options => {
1106
- const [recs_per_row, min, max] = options;
1107
- let should_hide_view_more_button;
1108
- let visible_recs;
1109
- if (props.disable_partial_rows) {
1110
- visible_recs = $5vyXB$depictaiutilishared.layout_get_visible_recs_without_partial_rows(rows_visible, children_count, options);
1111
- const visible_recs_next_show_more = $5vyXB$depictaiutilishared.layout_get_visible_recs_without_partial_rows(rows_visible + (rows_per_click || 0),
1112
- // Should this really be zero when we default rows_per_click to 1?
1113
- children_count, options);
1114
- should_hide_view_more_button = visible_recs === visible_recs_next_show_more;
1115
- } else {
1116
- visible_recs = $5vyXB$depictaiutilishared.layout_get_total_rec_amount_for_row(rows_visible, options);
1117
- should_hide_view_more_button = visible_recs >= children_count;
1118
- }
1119
- const should_hide_button_final = should_hide_view_more_button || max_rows !== -1 && rows_visible >= max_rows;
1120
- // I don't really understand the logic for when the view more button gets hidden so IDK if below is correct, but it works how it should for now
1121
- const should_hide_view_less_button = !should_hide_view_more_button || start_rows == undefined || rows_visible <= start_rows || children_count <= recs_per_row * start_rows;
1122
- return `${$5vyXB$depictaiutilishared.layout_media_query_header(min, max)}{${selector_beginning}:nth-child(n+${visible_recs + 1}){display:none}${props.layout == "slider" ? `${selector_beginning}:nth-child(n+${visible_recs}){margin-right:0}` : ""}${should_hide_button_final ? `.depict .${view_more_button_class}{display:none!important}` : ``}${should_hide_view_less_button ? `.depict .${view_less_button_class}{display:none!important}` : ``}}`;
1123
- }).join("");
1124
- }));
1125
- });
1126
- const style_element = $5vyXB$solidjsweb.ssr($f48d0fbb00835aaa$var$_tmpl$2, $5vyXB$solidjsweb.ssrHydrationKey(), get_styling); // need to create this after set_styling has been called or else there will be no styling in the SSR'd output
1127
- if (insert_after_container) container_element.after(style_element);
1128
- return [container_element, view_more_button_container(), view_less_button_container(), style_element];
1129
- }
1130
- var $363ce4d1d71041aa$var$_tmpl$ = ["<h2", ' class="recs-title">', "</h2>"];
1131
- function $363ce4d1d71041aa$export$d41d19e89346fa2({
1132
- recommendations_resource_: recommendations_resource_,
1133
- product_card_template_: product_card_template_,
1134
- layout_options_: layout_options_,
1135
- title_: title_,
1136
- NoResultsFallback_: NoResultsFallback_,
1137
- placeholderCacheKey_: placeholderCacheKey_
1138
- }) {
1139
- const is_showing_something = $5vyXB$solidjs.createMemo(() => recommendations_resource_.loading || recommendations_resource_()?.length);
1140
- const title = $5vyXB$solidjs.createMemo(() => title_?.()); // In case getter/accessor creates elements, don't create them twice
1141
- const num_placeholders_ = () => 20;
1142
- const slider = [$5vyXB$solidjsweb.createComponent((0, $5vyXB$solidjs.Show), {
1143
- get when() {
1144
- return title();
1145
- },
1146
- get children() {
1147
- return $5vyXB$solidjsweb.ssr($363ce4d1d71041aa$var$_tmpl$, $5vyXB$solidjsweb.ssrHydrationKey(), $5vyXB$solidjsweb.escape(title()));
1148
- }
1149
- }), $5vyXB$solidjsweb.createComponent((0, $a0e53f99354809d9$export$6649caad96ef8870), {
1150
- arrow_height_: 25,
1151
- arrow_width_: 12.5,
1152
- disable_fading_: true,
1153
- slider_ref_: slider => {
1154
- const {
1155
- insert_here: insert_here,
1156
- container: container
1157
- } = slider;
1158
- const Layout = props => $f48d0fbb00835aaa$export$445d8d3f5f706a40(props, insert_here, true);
1159
- // Do like this, so we don't have to call mergeProps ourselves
1160
- $5vyXB$solidjsweb.createComponent(Layout, $5vyXB$solidjsweb.mergeProps({
1161
- rows: "all",
1162
- layout: "slider"
1163
- }, layout_options_));
1164
- $5vyXB$depictaiutilishared.slider_fractional_factory(0, 0.75).constructor_plugin.call(slider, {}); // enable fractional scrolling
1165
- insert_here.before($fc23d7668ae0011d$export$a2cc176055f8f08());
1166
- container.classList.add("products");
1167
- },
1168
- get children() {
1169
- return $5vyXB$solidjsweb.createComponent((0, $5vyXB$solidjs.Suspense), {
1170
- get fallback() {
1171
- return $0caf87eaa19079da$export$f33414a4df0afd3f({
1172
- num_placeholders_: num_placeholders_,
1173
- product_card_template_: product_card_template_,
1174
- placeholderCacheKey_: placeholderCacheKey_
1175
- });
1176
- },
1177
- get children() {
1178
- return (() => {
1179
- // IIFE to make sure we access both the recommendations_resource and the resources containing the product card rendering results themselves within the Suspense boundary
1180
- const displays_by_key_ = $a73063cc642f3e5f$export$7f8bd308237ab5a5($5vyXB$solidjs.createMemo(() => recommendations_resource_() || []));
1181
- const {
1182
- renderedDisplays_: renderedDisplays_
1183
- } = $67155e1aeb7073f6$export$4a14175d33d81a96({
1184
- displays_by_key_: displays_by_key_,
1185
- product_card_template_: product_card_template_
1186
- });
1187
- return renderedDisplays_;
1188
- })();
1189
- }
1190
- });
1191
- }
1192
- })];
1193
- return $5vyXB$solidjsweb.createComponent((0, $5vyXB$solidjs.Show), {
1194
- get when() {
1195
- return is_showing_something();
1196
- },
1197
- get fallback() {
1198
- return NoResultsFallback_?.();
1199
- },
1200
- children: slider
1201
- });
1202
- }
1203
- function $95837413165cc2df$export$23fca46f3143581f(component, error_message) {
1204
- const component_in_error_boundary = do_with_elements => {
1205
- const error_boundary_wrapped = $edafe91daf3091d7$export$b69d0d92862de18b({
1206
- severity_: "error",
1207
- message_: error_message,
1208
- get children() {
1209
- const elements = component();
1210
- do_with_elements?.(elements);
1211
- return elements;
1212
- }
1213
- });
1214
- // This might return an accessor, in that case we need to "unwrap" it since our SDK consumers expect HTML elements or arrays thereof
1215
- if (typeof error_boundary_wrapped === "function")
1216
- // @ts-ignore
1217
- return error_boundary_wrapped();
1218
- // On the server it returns a string, so we just return that
1219
- return error_boundary_wrapped;
1220
- };
1221
- const owner = $5vyXB$solidjs.getOwner();
1222
- if (owner == null) return $5vyXB$solidjs.createRoot(dispose => {
1223
- // if we're not already run in a root, create a root and automatically dispose it when the first returned element is removed from the DOM
1224
- return component_in_error_boundary(elements => {
1225
- const have_multiple = Array.isArray(elements);
1226
- if (have_multiple ? !elements?.length : !elements) return;
1227
- (0, $5vyXB$depictaiutilishared.observer).onremoved(have_multiple ? elements[0] : elements, ({
1228
- element: element
1229
- }) => {
1230
- if (document.documentElement.contains(element)) return; // If element has instantly been re-inserted, don't dispose
1231
- // See https://depictaiworkspace.slack.com/archives/C050GHEPBTR/p1695809102791259?thread_ts=1695106805.459729&cid=C050GHEPBTR
1232
- dispose();
1233
- });
1234
- });
1235
- });else
1236
- // we're already in a root so cleanups are handled
1237
- return component_in_error_boundary();
1238
- }
1239
- const $84798aaa863a4909$var$ListingContext = /*@__PURE__*/$5vyXB$solidjs.createContext();
1240
- function $84798aaa863a4909$export$e68cff63f76bd15b(props) {
1241
- const our_object = {};
1242
- return $5vyXB$solidjsweb.createComponent($84798aaa863a4909$var$ListingContext.Provider, {
1243
- value: our_object,
1244
- get children() {
1245
- return props.children;
1246
- }
1247
- });
1248
- }
1249
- function $84798aaa863a4909$export$8d0c4fdbb05a2f2e() {
1250
- return $5vyXB$solidjs.useContext($84798aaa863a4909$var$ListingContext);
1251
- }
1252
- function $061ff5b4c3d36171$export$89c6019e4baa40b1(props) {
1253
- const style = $5vyXB$solidjs.createMemo(() => {
1254
- const {
1255
- style: style,
1256
- height: height,
1257
- width: width
1258
- } = props;
1259
- return {
1260
- ...(style || {}),
1261
- height: height ?? "1em",
1262
- ...(width && {
1263
- width: width
1264
- })
1265
- };
1266
- });
1267
- return $5vyXB$solidjsweb.createComponent((0, $9fe9883b1d8ecccc$export$acb3eaade4b23afd), {
1268
- get style() {
1269
- return style();
1270
- },
1271
- get ["class"]() {
1272
- return props.class;
1273
- }
1274
- });
1275
- }
1276
- var $6f604560873e4f69$var$_tmpl$ = ["<div", ' class="instant-card"><div class="img-part">', '</div><div class="right-part"><div class="title-brand-tagline"><span class="title">', '</span></div><div class="price-container">', "</div></div></div>"];
1277
- const $6f604560873e4f69$export$8a2234b5b1a5ebd4 = "--image-aspect-ratio";
1278
- function $6f604560873e4f69$export$ee1733d9a8495996() {
1279
- return $5vyXB$solidjsweb.ssr($6f604560873e4f69$var$_tmpl$, $5vyXB$solidjsweb.ssrHydrationKey(), $5vyXB$solidjsweb.escape($5vyXB$solidjsweb.createComponent((0, $3bc4a89b971a3af5$export$3f37af283f8fb843), {
1280
- aspectRatio: `var(${$6f604560873e4f69$export$8a2234b5b1a5ebd4}, 1)`
1281
- })), $5vyXB$solidjsweb.escape($5vyXB$solidjsweb.createComponent((0, $061ff5b4c3d36171$export$89c6019e4baa40b1), {
1282
- width: "20ch",
1283
- height: "1em"
1284
- })), $5vyXB$solidjsweb.escape($5vyXB$solidjsweb.createComponent((0, $061ff5b4c3d36171$export$89c6019e4baa40b1), {
1285
- width: "5ch",
1286
- height: "1em",
1287
- "class": "price"
1288
- })));
1289
- }
1290
- var $93304d59a9747aa6$var$_tmpl$ = ["<div", ' style="', '"', ">", "</div>"];
1291
- function $93304d59a9747aa6$export$94026ee33dbabc26(props) {
1292
- return $5vyXB$solidjsweb.ssr($93304d59a9747aa6$var$_tmpl$, $5vyXB$solidjsweb.ssrHydrationKey(), $5vyXB$solidjsweb.ssrStyle(`padding-bottom:calc(calc(1 / ${props.aspectRatio}) * 100%)`), $5vyXB$solidjsweb.ssrAttribute("class", "s-image-container" + (props.class ? " " + $5vyXB$solidjsweb.escape(props.class, true) : ""), false), $5vyXB$solidjsweb.escape(props.children));
1293
- }
1294
- let $3ea8e0af95b5b7d2$var$browserIsBugged = false;
1295
- function $3ea8e0af95b5b7d2$export$2972b890694ced75(callback, {
1296
- timeout: timeout
1297
- }) {
1298
- if ($3ea8e0af95b5b7d2$var$browserIsBugged) timeout /= 4;
1299
- const cancel = () => {
1300
- cancelIdleCallback(idleHandle);
1301
- clearTimeout(racingTimeout);
1302
- };
1303
- const idleHandle = requestIdleCallback(deadline => {
1304
- cancel();
1305
- return callback(deadline);
1306
- }, {
1307
- timeout: timeout
1308
- });
1309
- const racingTimeout = setTimeout(() => {
1310
- $5vyXB$depictaiutilishared.dwarn("Browser did not respect requestIdleCallback timeout");
1311
- $3ea8e0af95b5b7d2$var$browserIsBugged = true;
1312
- cancel();
1313
- callback({
1314
- didTimeout: false,
1315
- timeRemaining() {
1316
- return 500;
1317
- }
1318
- });
1319
- }, timeout + 1000);
1320
- return cancel;
1321
- }
1322
- function $19950faaac026e09$export$e6fffe67d4cdd848(whatToWatch) {
1323
- const [size, setSize] = $5vyXB$solidjs.createSignal(0);
1324
- const resizeObserver = new ResizeObserver($5vyXB$depictaiutilishared.catchify(records => {
1325
- for (let j = 0; j < records.length; j++) {
1326
- const {
1327
- width: width
1328
- } = records[j].contentRect;
1329
- if (!width) continue;
1330
- setSize(Math.ceil(width));
1331
- }
1332
- }));
1333
- // If we start observing elements before they're in the DOM Chrome (Version 117.0.5938.92 (Official Build) (arm64)) sometimes gives us a resize event with a width of 0 and then doesn't dispatch one with the actual width once it's in the DOM. So we wait until the element is in the DOM before we start observing it.
1334
- // It doesn't seem to work even when waiting for it to be in the DOM, also wait an animation frame
1335
- const disconnect = (0, $5vyXB$depictaiutilishared.observer).onexists(whatToWatch, ({
1336
- element: element
1337
- }) => requestAnimationFrame($5vyXB$depictaiutilishared.catchify(() => resizeObserver.observe(element))));
1338
- $5vyXB$solidjs.onCleanup(() => {
1339
- resizeObserver.disconnect();
1340
- disconnect();
1341
- });
1342
- return size;
1343
- }
1344
- const $19950faaac026e09$var$onIdleFunctionsSymbol = /*@__PURE__*/Symbol("onIdleFunctions");
1345
- const $19950faaac026e09$export$f8945274f08a3105 = /*@__PURE__*/Symbol("listingContextAspectRatios");
1346
- const $19950faaac026e09$export$6066eb417ed2e9f7 = /*@__PURE__*/Symbol("listingContextAspectRatios");
1347
- function $19950faaac026e09$export$6e5611bc7e57e477(props) {
1348
- const src_options = $5vyXB$solidjs.createMemo(() => {
1349
- const {
1350
- src: src,
1351
- customUrls: customUrls
1352
- } = props;
1353
- const fallback_src = (customUrls || $19950faaac026e09$export$1d6267828870adda)(src, 400);
1354
- const srcset = $19950faaac026e09$var$make_srcset(props.src, props.resolutions || [64, 128, 256, 300, 400, 512, 640, 768, 1024, 1280, 1536, 2048, 2560, 3072, 3584, 4096], customUrls);
1355
- // The order here *might* matter - I've seen mobile safari always start with loading the 400px version when it was reversed
1356
- return {
1357
- srcset: srcset,
1358
- src: fallback_src
1359
- };
1360
- });
1361
- // Work around https://github.com/solidjs/solid/issues/1828
1362
- const img = new Image(); // Need to use new Image or browser might not start loading image before it's in the DOM
1363
- const [, otherAttributes] = $5vyXB$solidjs.splitProps(props, ["resolutions", "size", "src", "srcSet", "loading", "keyRatioUpdating", "customUrls" // Can't have properties ending on underscore because the property name mangling will get confused by this <-
1364
- ]);
1365
-
1366
- const [hasSetSize, setHasSetSize] = $5vyXB$solidjs.createSignal(false);
1367
- const [hasDecoded, setHasDecoded] = $5vyXB$solidjs.createSignal(false);
1368
- const productCardIndexAccessor = $129b9b9c010039d0$export$e3faf4d95300054f();
1369
- const sizePX = $5vyXB$solidjs.createMemo(() => `${props.size()}px`); // props.size could be a getter that expects a cleanup so get it in this memo instead of where we set img.sizes
1370
- const listingContext = $84798aaa863a4909$export$8d0c4fdbb05a2f2e();
1371
- const isPrioritisedImage = $5vyXB$solidjs.createMemo(() => productCardIndexAccessor?.() < 8);
1372
- const shouldActuallyEnableLazyLoading = $5vyXB$solidjs.createMemo(() => {
1373
- const {
1374
- loading: loading
1375
- } = props;
1376
- if (loading === "force-lazy") return true;
1377
- return loading === "lazy" && !isPrioritisedImage();
1378
- });
1379
- const modifiedOtherAttributes = $5vyXB$solidjs.mergeProps(otherAttributes, {
1380
- get loading() {
1381
- return shouldActuallyEnableLazyLoading() ? "lazy" : undefined;
1382
- }
1383
- });
1384
- // Batch idle callbacks so that MutationObserver can batch the resulting mutations better, so we don't lose tons of CPU time to MutationObservers doing lots of things for each image
1385
- // Happened on singular, they have some weird observer (+we also have one but ours is at least 3x more efficient)
1386
- const executeWhenIdleBatched = (fn, isSizesUpdate) => {
1387
- if (typeof requestIdleCallback !== "function") return setTimeout(fn); // Old browsers don't get optimisation
1388
- if ((!isSizesUpdate || !sizeSetFastPath) && $5vyXB$solidjs.untrack(isPrioritisedImage)) return fn(); // If we're one of the first 8 images, execute the callbacks immediately (improves lighthouse metrics)
1389
- // unless we're just a `sizes` update after the initial sizes setting (this optimisation makes the looks animation a lot smoother on low-cpu devices)
1390
- const existingStack = listingContext?.[$19950faaac026e09$var$onIdleFunctionsSymbol];
1391
- if (existingStack) return existingStack.add(fn);
1392
- const newStack = new Set([fn]);
1393
- if (listingContext) listingContext[$19950faaac026e09$var$onIdleFunctionsSymbol] = newStack;
1394
- const processStackWhenIdle = () => $3ea8e0af95b5b7d2$export$2972b890694ced75($5vyXB$depictaiutilishared.catchify(deadline => {
1395
- const start = performance.now();
1396
- const thirdDeadlineTime = deadline.timeRemaining() / 3; // observers coming after this take up 2-3x the time so don't use all of it
1397
- for (const fn of newStack) {
1398
- newStack.delete(fn);
1399
- fn();
1400
- const timeTaken = performance.now() - start;
1401
- if ((!deadline.timeRemaining() || timeTaken > thirdDeadlineTime) && newStack.size) {
1402
- // There's still work to be done but no time, so schedule another idle callback
1403
- processStackWhenIdle();
1404
- return;
1405
- }
1406
- }
1407
- // Stack is empty
1408
- if (listingContext) delete listingContext[$19950faaac026e09$var$onIdleFunctionsSymbol];
1409
- }), {
1410
- timeout: 15000
1411
- } // long timeout, better to not have images than to freeze the browser. But also we don't want to confuse user why no iamges are loading
1412
- );
1413
-
1414
- processStackWhenIdle();
1415
- };
1416
- let sizeSetFastPath = false;
1417
- let hasDecodedFastPath = false;
1418
- let timeoutSet = false;
1419
- let gotCleanedUp = false;
1420
- let srcJustChanged = true;
1421
- img.classList.add("s-responsive-image");
1422
- if (listingContext) {
1423
- let prevValue;
1424
- const aspectRatios = listingContext[$19950faaac026e09$export$f8945274f08a3105] ||= new Set();
1425
- const [, setMostPrevalentAspectRatio] = listingContext[$19950faaac026e09$export$6066eb417ed2e9f7] ||= $5vyXB$solidjs.createSignal();
1426
- img.addEventListener("load", $5vyXB$depictaiutilishared.catchify(() => {
1427
- if (props.keyRatioUpdating) {
1428
- if (!srcJustChanged) return;
1429
- srcJustChanged = false;
1430
- }
1431
- // Save our aspect ratio whenever it changes, so that we can base the containers on the most dominant aspect ratio, used in SearchModalV2 and LookItem
1432
- const aspectRatio_ = img.naturalWidth / img.naturalHeight;
1433
- if (prevValue) aspectRatios.delete(prevValue);
1434
- const newValue = !isNaN(aspectRatio_) ? {
1435
- aspectRatio_: aspectRatio_
1436
- } : undefined;
1437
- if (newValue) aspectRatios.add(newValue);
1438
- prevValue = newValue;
1439
- // Do all calculations resulting of an update directly, for performance
1440
- const asArray = [...aspectRatios].map(({
1441
- aspectRatio_: aspectRatio_
1442
- }) => aspectRatio_);
1443
- const mostPrevalentAspectRatio = $5vyXB$depictaiutilishared.findMostFrequentItem(asArray);
1444
- setMostPrevalentAspectRatio(mostPrevalentAspectRatio);
1445
- }));
1446
- $5vyXB$solidjs.onCleanup(() => prevValue && aspectRatios.delete(prevValue));
1447
- }
1448
- $5vyXB$solidjs.onCleanup(() => gotCleanedUp = true);
1449
- $5vyXB$solidjsweb.spread(img, $5vyXB$solidjs.mergeProps(modifiedOtherAttributes), false, true);
1450
- $5vyXB$solidjs.createRenderEffect(() => {
1451
- props.src;
1452
- srcJustChanged = true;
1453
- });
1454
- $5vyXB$solidjs.createEffect(() => {
1455
- if (!props.size()) return; // wait until we have a size, run every time the size changes
1456
- if (timeoutSet) return;
1457
- const handler = $5vyXB$depictaiutilishared.catchify(() => {
1458
- if (gotCleanedUp) return;
1459
- img.sizes = sizePX(); // use latest available value of props.size
1460
- if (!sizeSetFastPath) {
1461
- setHasSetSize(true);
1462
- sizeSetFastPath = true;
1463
- }
1464
- timeoutSet = false;
1465
- });
1466
- // Throttle the updating of sizes to avoid unnecessary image re-fetches during resize
1467
- // And also because we first set src after sizes has been set, wait with loading and decoding images until browser is idle
1468
- // This greatly improves performance when loading (more) products
1469
- // See https://depictaiworkspace.slack.com/archives/C05NJ0K3WRL/p1698220617663139
1470
- timeoutSet = true; // Important to set timeoutSet before the call to executeWhenIdleBatched since if this is an important image executeWhenIdleBatched will execute fn immediately
1471
- executeWhenIdleBatched(handler, true);
1438
+ // Make sure we don't have more rows visible than max_rows (this could happen by max_rows being decreased)
1439
+ const rows_visible = get_rows_visible();
1440
+ const max_rows = rows_or_empty_object().max_rows;
1441
+ if (!isNaN(max_rows) && max_rows >= 0 && rows_visible > max_rows) set_rows_visible()(max_rows);
1472
1442
  });
1473
- const dontLoadImageYet = $5vyXB$solidjs.createMemo(() => !props.size() || !hasSetSize()); // Moving this condition into a memo saves us from re-setting src and srcset (expensive) if just props.size changes
1474
- $5vyXB$solidjs.createEffect(() => {
1475
- if (dontLoadImageYet()) return; // If size isn't known or set, don't assign src yet since it would cause the most low res image to load
1476
- Object.assign(img, src_options());
1477
- // Add to DOM once decoded to not require/block any paints before image has completed loading and avoid showing broken image symbol
1478
- // We can do this because there has to be a container around us giving us a size
1479
- // No need to listen if we're already in the DOM
1480
- if (hasDecodedFastPath) return;
1481
- if (shouldActuallyEnableLazyLoading()) {
1482
- // For lazy loading there's no decoding to wait for as it only occurs when the image is visible
1483
- // Make sure src is set before we put the image into the DOM though so no broken image symbol is shown
1484
- setHasDecoded(true);
1485
- hasDecodedFastPath = true;
1443
+ $5vyXB$solidjs.createEffect(() => set_force_style_update(" ")); // force style update after hydration due to https://discord.com/channels/722131463138705510/722167424186843267/1151544212517552168
1444
+ $5vyXB$solidjs.createRenderEffect(() => {
1445
+ // Be careful to only read show_all_rows in here (ofc doesn't apply to nested effects)
1446
+ if (show_all_rows()) {
1447
+ // no view more functionality requested
1448
+ set_styling(() => col_styling);
1486
1449
  return;
1487
1450
  }
1488
- img.decode().catch(e => $5vyXB$depictaiutilishared.dwarn("Failed to decode image", e, img)) // Display the image also if loading failed so webdev can debug and doesn't get "no image"
1489
- .then(async () => {
1490
- // Also wait with inserting image (i.e. paint) until browser is idle
1491
- await new Promise(r => executeWhenIdleBatched(r, false));
1492
- if (gotCleanedUp) return;
1493
- setHasDecoded(true);
1494
- hasDecodedFastPath = true;
1495
- });
1451
+ update_children_count();
1452
+ if (!(0, $5vyXB$solidjsweb.isServer)) {
1453
+ const mutation_observer = new MutationObserver($5vyXB$depictaiutilishared.catchify(update_children_count));
1454
+ mutation_observer.observe(container_element, {
1455
+ childList: true
1456
+ });
1457
+ $5vyXB$solidjs.onCleanup(() => mutation_observer.disconnect());
1458
+ }
1459
+ set_styling(
1460
+ // this is needed because solid will think that the memo-accessor is a setter function otherwise
1461
+ () => $5vyXB$solidjs.createMemo(() => {
1462
+ const {
1463
+ rows_per_click: rows_per_click,
1464
+ max_rows = -1,
1465
+ start_rows: start_rows
1466
+ } = rows_or_empty_object();
1467
+ const rows_visible = get_rows_visible();
1468
+ const children_count = get_children_count();
1469
+ return force_style_update() + col_styling() + props.cols_at_size.map(options => {
1470
+ const [recs_per_row, min, max] = options;
1471
+ let should_hide_view_more_button;
1472
+ let visible_recs;
1473
+ if (props.disable_partial_rows) {
1474
+ visible_recs = $5vyXB$depictaiutilishared.layout_get_visible_recs_without_partial_rows(rows_visible, children_count, options);
1475
+ const visible_recs_next_show_more = $5vyXB$depictaiutilishared.layout_get_visible_recs_without_partial_rows(rows_visible + (rows_per_click || 0),
1476
+ // Should this really be zero when we default rows_per_click to 1?
1477
+ children_count, options);
1478
+ should_hide_view_more_button = visible_recs === visible_recs_next_show_more;
1479
+ } else {
1480
+ visible_recs = $5vyXB$depictaiutilishared.layout_get_total_rec_amount_for_row(rows_visible, options);
1481
+ should_hide_view_more_button = visible_recs >= children_count;
1482
+ }
1483
+ const should_hide_button_final = should_hide_view_more_button || max_rows !== -1 && rows_visible >= max_rows;
1484
+ // I don't really understand the logic for when the view more button gets hidden so IDK if below is correct, but it works how it should for now
1485
+ const should_hide_view_less_button = !should_hide_view_more_button || start_rows == undefined || rows_visible <= start_rows || children_count <= recs_per_row * start_rows;
1486
+ return `${$5vyXB$depictaiutilishared.layout_media_query_header(min, max)}{${selector_beginning}:nth-child(n+${visible_recs + 1}){display:none}${props.layout == "slider" ? `${selector_beginning}:nth-child(n+${visible_recs}){margin-right:0}` : ""}${should_hide_button_final ? `.depict .${view_more_button_class}{display:none!important}` : ``}${should_hide_view_less_button ? `.depict .${view_less_button_class}{display:none!important}` : ``}}`;
1487
+ }).join("");
1488
+ }));
1496
1489
  });
1490
+ const style_element = $5vyXB$solidjsweb.ssr($f48d0fbb00835aaa$var$_tmpl$2, $5vyXB$solidjsweb.ssrHydrationKey(), get_styling); // need to create this after set_styling has been called or else there will be no styling in the SSR'd output
1491
+ if (insert_after_container) container_element.after(style_element);
1492
+ return [container_element, view_more_button_container(), view_less_button_container(), style_element];
1493
+ }
1494
+ var $363ce4d1d71041aa$var$_tmpl$ = ["<h2", ' class="recs-title">', "</h2>"];
1495
+ function $363ce4d1d71041aa$export$d41d19e89346fa2({
1496
+ recommendations_resource_: recommendations_resource_,
1497
+ product_card_template_: product_card_template_,
1498
+ layout_options_: layout_options_,
1499
+ title_: title_,
1500
+ NoResultsFallback_: NoResultsFallback_,
1501
+ placeholderCacheKey_: placeholderCacheKey_
1502
+ }) {
1503
+ const is_showing_something = $5vyXB$solidjs.createMemo(() => recommendations_resource_.loading || recommendations_resource_()?.length);
1504
+ const title = $5vyXB$solidjs.createMemo(() => title_?.()); // In case getter/accessor creates elements, don't create them twice
1505
+ const num_placeholders_ = () => 20;
1506
+ const slider = [$5vyXB$solidjsweb.createComponent((0, $5vyXB$solidjs.Show), {
1507
+ get when() {
1508
+ return title();
1509
+ },
1510
+ get children() {
1511
+ return $5vyXB$solidjsweb.ssr($363ce4d1d71041aa$var$_tmpl$, $5vyXB$solidjsweb.ssrHydrationKey(), $5vyXB$solidjsweb.escape(title()));
1512
+ }
1513
+ }), $5vyXB$solidjsweb.createComponent((0, $a0e53f99354809d9$export$6649caad96ef8870), {
1514
+ arrow_height_: 25,
1515
+ arrow_width_: 12.5,
1516
+ disable_fading_: true,
1517
+ slider_ref_: slider => {
1518
+ const {
1519
+ insert_here: insert_here,
1520
+ container: container
1521
+ } = slider;
1522
+ const Layout = props => $f48d0fbb00835aaa$export$445d8d3f5f706a40(props, insert_here, true);
1523
+ // Do like this, so we don't have to call mergeProps ourselves
1524
+ $5vyXB$solidjsweb.createComponent(Layout, $5vyXB$solidjsweb.mergeProps({
1525
+ rows: "all",
1526
+ layout: "slider"
1527
+ }, layout_options_));
1528
+ $5vyXB$depictaiutilishared.slider_fractional_factory(0, 0.75).constructor_plugin.call(slider, {}); // enable fractional scrolling
1529
+ insert_here.before($fc23d7668ae0011d$export$a2cc176055f8f08());
1530
+ container.classList.add("products");
1531
+ },
1532
+ get children() {
1533
+ return $5vyXB$solidjsweb.createComponent((0, $5vyXB$solidjs.Suspense), {
1534
+ get fallback() {
1535
+ return $0caf87eaa19079da$export$f33414a4df0afd3f({
1536
+ num_placeholders_: num_placeholders_,
1537
+ product_card_template_: product_card_template_,
1538
+ placeholderCacheKey_: placeholderCacheKey_
1539
+ });
1540
+ },
1541
+ get children() {
1542
+ return (() => {
1543
+ // IIFE to make sure we access both the recommendations_resource and the resources containing the product card rendering results themselves within the Suspense boundary
1544
+ const displays_by_key_ = $a73063cc642f3e5f$export$7f8bd308237ab5a5($5vyXB$solidjs.createMemo(() => recommendations_resource_() || []));
1545
+ const {
1546
+ renderedDisplays_: renderedDisplays_
1547
+ } = $67155e1aeb7073f6$export$4a14175d33d81a96({
1548
+ displays_by_key_: displays_by_key_,
1549
+ product_card_template_: product_card_template_
1550
+ });
1551
+ return renderedDisplays_;
1552
+ })();
1553
+ }
1554
+ });
1555
+ }
1556
+ })];
1497
1557
  return $5vyXB$solidjsweb.createComponent((0, $5vyXB$solidjs.Show), {
1498
1558
  get when() {
1499
- return hasDecoded();
1559
+ return is_showing_something();
1500
1560
  },
1501
- children: img
1561
+ get fallback() {
1562
+ return NoResultsFallback_?.();
1563
+ },
1564
+ children: slider
1502
1565
  });
1503
1566
  }
1504
- function $19950faaac026e09$var$make_srcset(url, resolutions, customGenerateImageUrl_) {
1505
- return resolutions.map(width => `${(customGenerateImageUrl_ || $19950faaac026e09$export$1d6267828870adda)(url, width)} ${width}w`).join(", ");
1506
- }
1507
- function $19950faaac026e09$export$1d6267828870adda(url, width) {
1508
- // Even just creating one `URL` object per image src and then setting the search parameter is quite slow (0.25ms to set the width param)
1509
- // We're making the assumptions that the url has already at least one query parameter and that the image resizing service will choose the last one out of a duplicate width parameter (shopify's does)
1510
- // That way we can just to string concatenation which is insanely fast
1511
- return url + "&width=" + encodeURIComponent(width);
1512
- }
1513
- const $a33065cfed827fc0$var$backupSizeSignal = /*@__PURE__*/$5vyXB$solidjs.createSignal();
1514
- const $a33065cfed827fc0$export$d7b7ab832c20e2f4 = /*@__PURE__*/Symbol("ShopifyContainedImage");
1515
- function $a33065cfed827fc0$export$e4b984597b71e989(props) {
1516
- const context = $84798aaa863a4909$export$8d0c4fdbb05a2f2e();
1517
- if (context && !context[$a33065cfed827fc0$export$d7b7ab832c20e2f4])
1518
- // create a signal that's the same for all items in this listing
1519
- context[$a33065cfed827fc0$export$d7b7ab832c20e2f4] = $5vyXB$solidjs.createSignal();
1520
- const [currentImageSize, setCurrentImageSize] = context?.[$a33065cfed827fc0$export$d7b7ab832c20e2f4] || $a33065cfed827fc0$var$backupSizeSignal; // use global fallback signal (might lead to blurry images) if no context is available
1521
- const [mostPrevalentAspectRatio] = context ?
1522
- // If the context exists we have to create the signal here as getting it here would be too late when it's created by ShopifyResponsiveImg below
1523
- context[(0, $19950faaac026e09$export$6066eb417ed2e9f7)] ||= $5vyXB$solidjs.createSignal() : [];
1524
- const container = $93304d59a9747aa6$export$94026ee33dbabc26({
1525
- // Write getters manually instead of using JSX, so we can do more complex logic in the aspectRatio getter without increasing bundle size
1526
- get class() {
1527
- return props.class;
1528
- },
1529
- get aspectRatio() {
1530
- if (props.autoAdjustAspectRatio) {
1531
- const targetRatio = mostPrevalentAspectRatio?.();
1532
- if (targetRatio != undefined) return `var(${(0, $6f604560873e4f69$export$8a2234b5b1a5ebd4)}, ${targetRatio})`;
1567
+ function $95837413165cc2df$export$23fca46f3143581f(component, error_message) {
1568
+ const component_in_error_boundary = do_with_elements => {
1569
+ const error_boundary_wrapped = $edafe91daf3091d7$export$b69d0d92862de18b({
1570
+ severity_: "error",
1571
+ message_: error_message,
1572
+ get children() {
1573
+ const elements = component();
1574
+ do_with_elements?.(elements);
1575
+ return elements;
1533
1576
  }
1534
- return props.aspectRatio;
1535
- }
1536
- });
1577
+ });
1578
+ // This might return an accessor, in that case we need to "unwrap" it since our SDK consumers expect HTML elements or arrays thereof
1579
+ if (typeof error_boundary_wrapped === "function")
1580
+ // @ts-ignore
1581
+ return error_boundary_wrapped();
1582
+ // On the server it returns a string, so we just return that
1583
+ return error_boundary_wrapped;
1584
+ };
1537
1585
  const owner = $5vyXB$solidjs.getOwner();
1538
- let createdSizeAccessor = false;
1539
- let wasCleanedUp = false;
1540
- $5vyXB$solidjs.createEffect(() => {
1541
- if (currentImageSize() || wasCleanedUp) return; // We get into the effect when onCleanup is called if we don't have wasCleanedUp
1542
- // ensure we always have a size accessor
1543
- // what this whole thing does is set the sizes attribute to the actual size of one of the existing image containers, therefore the value doesn't have to manually be specified
1544
- createdSizeAccessor = true;
1545
- setCurrentImageSize(() => $5vyXB$solidjs.runWithOwner(owner, () => $19950faaac026e09$export$e6fffe67d4cdd848(container)));
1546
- });
1547
- $5vyXB$solidjs.onCleanup(() => {
1548
- wasCleanedUp = true; // important to set this before the function call below and always, so the dead effects don't create dead size accessors
1549
- if (!createdSizeAccessor) return;
1550
- $5vyXB$depictaiutilishared.queueMacroTask(() => setCurrentImageSize()); // unset the size accessor next event loop iteration, so that all onCleanup's have time to run, since the effects run more aggressively and can create a size accessor with a cleaned up owner otherwise
1551
- });
1552
-
1553
- $5vyXB$solidjsweb.insert(container, $5vyXB$solidjsweb.createComponent((0, $19950faaac026e09$export$6e5611bc7e57e477), $5vyXB$solidjsweb.mergeProps({
1554
- get size() {
1555
- return $5vyXB$solidjs.createMemo(() => currentImageSize()?.() || 0);
1556
- },
1557
- get src() {
1558
- return props.src;
1559
- }
1560
- }, () => props.imgProps, {
1561
- get style() {
1562
- return props.imgProps?.style;
1563
- }
1564
- })));
1565
- return container;
1566
- }
1567
- const $d212a67662c5cf38$var$customUrls = (url, width) => {
1568
- if (url?.startsWith?.("https://cdn.shopify.com"))
1569
- // The shopify image resizing CDN blocks Cloudflare's image resizer. It's possible that we can't detect shopify image URLs sometimes because they go to the merchant's domain,
1570
- // but it seems like the URLs returned by the Depict API always goes to the cdn.shopify.com version of an image, so this simple workaround works.
1571
- return $19950faaac026e09$export$1d6267828870adda(url, width);
1572
- // Use cloudflare image resizer instead of img.depict.ai because it's a lot faster (and also auto-chooses other formats if webp is not supported)
1573
- return `https://app.depict.ai/cdn-cgi/image/width=${width},format=auto/${url}`;
1574
- };
1575
- function $d212a67662c5cf38$export$9d4a4b669b1929ab(props) {
1576
- return $5vyXB$solidjsweb.createComponent((0, $a33065cfed827fc0$export$e4b984597b71e989), $5vyXB$solidjsweb.mergeProps(props, {
1577
- get imgProps() {
1578
- return {
1579
- ...props.imgProps,
1580
- customUrls: $d212a67662c5cf38$var$customUrls
1581
- };
1582
- }
1583
- }));
1584
- }
1585
- function $d212a67662c5cf38$export$140423fa4bfb6d63(props) {
1586
- return $5vyXB$solidjsweb.createComponent((0, $19950faaac026e09$export$6e5611bc7e57e477), $5vyXB$solidjsweb.mergeProps(props, {
1587
- customUrls: $d212a67662c5cf38$var$customUrls
1588
- }));
1586
+ if (owner == null) return $5vyXB$solidjs.createRoot(dispose => {
1587
+ // if we're not already run in a root, create a root and automatically dispose it when the first returned element is removed from the DOM
1588
+ return component_in_error_boundary(elements => {
1589
+ const have_multiple = Array.isArray(elements);
1590
+ if (have_multiple ? !elements?.length : !elements) return;
1591
+ (0, $5vyXB$depictaiutilishared.observer).onremoved(have_multiple ? elements[0] : elements, ({
1592
+ element: element
1593
+ }) => {
1594
+ if (document.documentElement.contains(element)) return; // If element has instantly been re-inserted, don't dispose
1595
+ // See https://depictaiworkspace.slack.com/archives/C050GHEPBTR/p1695809102791259?thread_ts=1695106805.459729&cid=C050GHEPBTR
1596
+ dispose();
1597
+ });
1598
+ });
1599
+ });else
1600
+ // we're already in a root so cleanups are handled
1601
+ return component_in_error_boundary();
1589
1602
  }
1590
1603
  function $d659702496cb72ea$export$a71e92cfbb498adc(props) {
1591
1604
  return $5vyXB$solidjs.createMemo(() => {
@@ -12377,9 +12390,8 @@ function $32c662f618f5d80d$export$780a853d15174484({
12377
12390
  }, {
12378
12391
  get children() {
12379
12392
  return $5vyXB$solidjsweb.createComponent((0, $d212a67662c5cf38$export$140423fa4bfb6d63), {
12380
- get size() {
12381
- return $5vyXB$solidjs.createMemo(() => wrapperSize()?.() || 0);
12382
- },
12393
+ size: () => wrapperSize()?.[0]?.() || 0,
12394
+ sizeHeight: () => wrapperSize()?.[1]?.() || 0,
12383
12395
  src: mediaUrl,
12384
12396
  "class": "d-standard-content"
12385
12397
  });
@@ -12398,9 +12410,12 @@ function $0a80939bf0a1e9cc$export$7a92d995f1bf3592(history_content_blocks_, plp_
12398
12410
  if (serverContentBlock && JSON.stringify(serverContentBlock) !== JSON.stringify(historyContentBlocks())) setHistoryContentBlocks(serverContentBlock);
12399
12411
  });
12400
12412
  const contentBlocksByRow = $5vyXB$solidjs.createMemo(() => {
12401
- if (content_blocks_by_row_()) return content_blocks_by_row_();
12413
+ const developerProvided = content_blocks_by_row_();
12414
+ const fromHistory = historyContentBlocks();
12415
+ // If none come from backend/History, fall back to developer provided/what usually is undefined. layout="slider" and layout="slider-without-filters" is only supported if content blocks is undefined, so if we don't do that those layouts are broken.
12416
+ if (developerProvided || !fromHistory.length) return developerProvided;
12402
12417
  const content = [];
12403
- historyContentBlocks().forEach(row => {
12418
+ fromHistory.forEach(row => {
12404
12419
  const contentBlock = {
12405
12420
  span_columns: row.span_columns,
12406
12421
  span_rows: row.span_rows,