@depict-ai/ui 4.7.32 → 4.7.34

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,9 @@ function $parcel$export(e, n, v, s) {
12
12
  configurable: true
13
13
  });
14
14
  }
15
+ $parcel$export(module.exports, "ModernResponsiveImage", () => $d212a67662c5cf38$export$140423fa4bfb6d63);
16
+ $parcel$export(module.exports, "setExtraDisplayTransformers", () => $606c221d98ba4d92$export$f98b8d5ea7207a1);
17
+ $parcel$export(module.exports, "getExtraDisplayTransformers", () => $606c221d98ba4d92$export$b2d94be4f02525b2);
15
18
  $parcel$export(module.exports, "remap_blocks_to_index", () => $d92f338ba8f9da9b$export$92aa5d691d588f3f);
16
19
  $parcel$export(module.exports, "useMobileHover", () => $8bf678c45948a297$export$d4d96868197be50e);
17
20
  $parcel$export(module.exports, "useVisibilityState", () => $55cbacb79d3e0cea$export$54299a3c81f5425);
@@ -52,7 +55,6 @@ $parcel$export(module.exports, "make_accurate_width_accessor", () => $f13855d1b9
52
55
  $parcel$export(module.exports, "RecommendationSlider", () => $72f96c4782db0b1b$export$9574e176201e5e8d);
53
56
  $parcel$export(module.exports, "RecommendationGrid", () => $1f8dbf7e28b3eff2$export$9756467d34d91cdb);
54
57
  $parcel$export(module.exports, "ShopifyResponsiveImg", () => $19950faaac026e09$export$6e5611bc7e57e477);
55
- $parcel$export(module.exports, "makeSizeAccessor", () => $19950faaac026e09$export$e6fffe67d4cdd848);
56
58
  $parcel$export(module.exports, "ImageContainer", () => $93304d59a9747aa6$export$94026ee33dbabc26);
57
59
  $parcel$export(module.exports, "SentryErrorBoundary", () => $edafe91daf3091d7$export$b69d0d92862de18b);
58
60
  $parcel$export(module.exports, "ExtraSentryContextProvider", () => $edafe91daf3091d7$export$240ecf5363d76c0f);
@@ -104,31 +106,245 @@ $parcel$export(module.exports, "SearchField", () => $c0a0659cf97e8eb2$export$316
104
106
  $parcel$export(module.exports, "BreadCrumbs", () => $1f4925833f07df29$export$5b7c3ce0ebe51f86);
105
107
  $parcel$export(module.exports, "QuickLinks", () => $1f4925833f07df29$export$de035477d6fef996);
106
108
  $parcel$export(module.exports, "CategoryPage", () => $14f289047713d67a$export$e2bf8ce7779e827e);
109
+ $parcel$export(module.exports, "makeSizeAccessors", () => $128302ab61dab8f1$export$54c6d6ff54e72743);
107
110
  /*! Depict.ai search and product listing SDK */
108
- const $b757f75811f3261f$export$83d89fbfd8236492 = "4.7.32";
109
- function $b54e6192d0caa293$export$d9f36cf74e24d595(media_query) {
110
- const signal = $5vyXB$solidjs.createSignal(false);
111
- $5vyXB$solidjs.onCleanup($5vyXB$depictaiutilishared.javascript_media_query(media_query, ({
112
- matches: matches
113
- }) => signal[1](matches)).remove);
114
- return signal[0];
111
+ const $b757f75811f3261f$export$83d89fbfd8236492 = "4.7.34";
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
+ });
115
121
  }
116
- function $17d06b3bcb035500$export$a79e666719b3647c(cols_at_size_) {
117
- const size_active = $5vyXB$solidjs.createMemo(() => cols_at_size_().map(([n_cols, min_width, max_width]) => {
118
- const media_query = $5vyXB$depictaiutilishared.layout_media_query_header(min_width, max_width).replaceAll("@media", "");
119
- const matches = $b54e6192d0caa293$export$d9f36cf74e24d595(media_query);
120
- return [matches, n_cols];
121
- }));
122
- const n_cols_currently_showing = $5vyXB$solidjs.createMemo(() => {
123
- try {
124
- const [, n_cols_currently_showing] = size_active().find(([media_query]) => media_query());
125
- return n_cols_currently_showing;
126
- } catch (e) {
127
- $5vyXB$depictaiutilishared.dwarn("No active size found in columnsAtSize - can't render content blocks or looks");
128
- 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;
129
137
  }
130
138
  });
131
- 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 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);
132
348
  }
133
349
  var $9fe9883b1d8ecccc$var$_tmpl$ = ["<span", ' class="', '" style="', '"></span>'];
134
350
  function $9fe9883b1d8ecccc$export$acb3eaade4b23afd(props) {
@@ -166,26 +382,197 @@ function $3bc4a89b971a3af5$export$3f37af283f8fb843(props) {
166
382
  }
167
383
  });
168
384
  }
169
- var $d92f338ba8f9da9b$var$_tmpl$ = ["<div", ' class="', '" style="', '">', "</div>"];
170
- function $d92f338ba8f9da9b$export$791ef57e62e21c3f({
171
- content_blocks_: incoming_content_blocks,
172
- cols_at_size_: cols_at_size_,
173
- set_top_row_shortened_by_: set_top_row_shortened_by_
174
- }) {
175
- // these are by row
176
- const [content_blocks, set_content_blocks] = $5vyXB$solidjsstore.createStore([]);
177
- const n_cols_currently_showing_ = $17d06b3bcb035500$export$a79e666719b3647c(cols_at_size_);
178
- $5vyXB$solidjs.createEffect(() => {
179
- const incoming_value = incoming_content_blocks();
180
- if (!incoming_value) {
181
- set_content_blocks([]);
182
- return;
183
- }
184
- set_content_blocks($5vyXB$solidjsstore.reconcile(incoming_value, {
185
- key: "content"
186
- })); // key: Make moving blocks faster, see https://github.com/solidjs/solid/issues/1925#issuecomment-1769671596
187
- });
188
-
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([]);
569
+ return;
570
+ }
571
+ set_content_blocks($5vyXB$solidjsstore.reconcile(incoming_value, {
572
+ key: "content"
573
+ })); // key: Make moving blocks faster, see https://github.com/solidjs/solid/issues/1925#issuecomment-1769671596
574
+ });
575
+
189
576
  const get_wrapped_blocks_ = $d92f338ba8f9da9b$var$wrap_blocks_in_div(content_blocks, n_cols_currently_showing_);
190
577
  $5vyXB$solidjs.createComputed(() => {
191
578
  // Update our styling if a content block forces some items that should be in the top row into a lower one, so we can generate margin-top declarations for them
@@ -495,20 +882,6 @@ function $5f7d55c710fd1bc2$var$unwrapping_helper(elements) {
495
882
  } else if (typeof elements == "function") result.push(...$5f7d55c710fd1bc2$var$unwrapping_helper(elements()));else if (elements != undefined && typeof elements != "boolean") result.push(elements);
496
883
  return result;
497
884
  }
498
- const $129b9b9c010039d0$var$ProductCardIndexContext = /*@__PURE__*/$5vyXB$solidjs.createContext();
499
- function $129b9b9c010039d0$export$11354f017ddc9790(props) {
500
- return $5vyXB$solidjsweb.createComponent($129b9b9c010039d0$var$ProductCardIndexContext.Provider, {
501
- get value() {
502
- return props.index_;
503
- },
504
- get children() {
505
- return props.children;
506
- }
507
- });
508
- }
509
- function $129b9b9c010039d0$export$e3faf4d95300054f() {
510
- return $5vyXB$solidjs.useContext($129b9b9c010039d0$var$ProductCardIndexContext);
511
- }
512
885
 
513
886
  /**
514
887
  * This is a function that will safely clone an object that may contain promises.
@@ -1049,529 +1422,183 @@ function $f48d0fbb00835aaa$export$445d8d3f5f706a40(props, container_element, ins
1049
1422
  const [get_styling, set_styling] = $5vyXB$solidjs.createSignal();
1050
1423
  const selector_beginning = `.depict .${container_class}>`; // class so ppl can have id if needed
1051
1424
  const [get_children_count, set_children_count] = $5vyXB$solidjs.createSignal(0);
1052
- const update_children_count = () => (0, $5vyXB$solidjsweb.isServer) ? 20 : set_children_count(container_element.children.length);
1053
- const col_styling = $5vyXB$solidjs.createMemo(() => $5vyXB$depictaiutilishared.n_col_styling_with_dist(selector_beginning, props.grid_spacing, props.cols_at_size, props.layout, props.override_vertical_spacing));
1054
- const default_currently_visible_signal = $5vyXB$solidjs.createSignal($5vyXB$solidjs.untrack(() => rows_or_empty_object().start_rows ?? 1)); // Keep this signal here, so it doesn't change when rows_or_empty_object and I think it's to be expected that the "internal default signal" stays the same
1055
- const rows_visible_signal = $5vyXB$solidjs.createMemo(() => rows_or_empty_object().currently_visible || default_currently_visible_signal);
1056
- const get_rows_visible = $5vyXB$solidjs.createMemo(() => rows_visible_signal()[0]());
1057
- const set_rows_visible = $5vyXB$solidjs.createMemo(() => rows_visible_signal()[1]);
1058
- const view_more_button_class = "m" + $5vyXB$solidjs.createUniqueId();
1059
- const view_less_button_class = "l" + $5vyXB$solidjs.createUniqueId(); // https://github.com/solidjs/solid-docs/issues/263#issuecomment-1622388079
1060
- const view_more_button_container = $5vyXB$solidjs.createMemo(() => have_a_view_more_button() && $5vyXB$solidjsweb.ssr($f48d0fbb00835aaa$var$_tmpl$, $5vyXB$solidjsweb.ssrHydrationKey(), `load-more-container ${$5vyXB$solidjsweb.escape(view_more_button_class, true)}`, $5vyXB$solidjsweb.escape(rows_or_empty_object().button)));
1061
- // We need to have duplicate buttons because which ones is shown depends on the number of rows visible and therefore on the viewport size and therefore on the css media queries
1062
- 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)));
1063
- const [force_style_update, set_force_style_update] = $5vyXB$solidjs.createSignal("");
1064
- $5vyXB$solidjs.createComputed(() => {
1065
- // Make sure we don't have more rows visible than max_rows (this could happen by max_rows being decreased)
1066
- const rows_visible = get_rows_visible();
1067
- const max_rows = rows_or_empty_object().max_rows;
1068
- if (!isNaN(max_rows) && max_rows >= 0 && rows_visible > max_rows) set_rows_visible()(max_rows);
1069
- });
1070
- $5vyXB$solidjs.createEffect(() => set_force_style_update(" ")); // force style update after hydration due to https://discord.com/channels/722131463138705510/722167424186843267/1151544212517552168
1071
- $5vyXB$solidjs.createRenderEffect(() => {
1072
- // Be careful to only read show_all_rows in here (ofc doesn't apply to nested effects)
1073
- if (show_all_rows()) {
1074
- // no view more functionality requested
1075
- set_styling(() => col_styling);
1076
- return;
1077
- }
1078
- update_children_count();
1079
- if (!(0, $5vyXB$solidjsweb.isServer)) {
1080
- const mutation_observer = new MutationObserver($5vyXB$depictaiutilishared.catchify(update_children_count));
1081
- mutation_observer.observe(container_element, {
1082
- childList: true
1083
- });
1084
- $5vyXB$solidjs.onCleanup(() => mutation_observer.disconnect());
1085
- }
1086
- set_styling(
1087
- // this is needed because solid will think that the memo-accessor is a setter function otherwise
1088
- () => $5vyXB$solidjs.createMemo(() => {
1089
- const {
1090
- rows_per_click: rows_per_click,
1091
- max_rows = -1,
1092
- start_rows: start_rows
1093
- } = rows_or_empty_object();
1094
- const rows_visible = get_rows_visible();
1095
- const children_count = get_children_count();
1096
- return force_style_update() + col_styling() + props.cols_at_size.map(options => {
1097
- const [recs_per_row, min, max] = options;
1098
- let should_hide_view_more_button;
1099
- let visible_recs;
1100
- if (props.disable_partial_rows) {
1101
- visible_recs = $5vyXB$depictaiutilishared.layout_get_visible_recs_without_partial_rows(rows_visible, children_count, options);
1102
- const visible_recs_next_show_more = $5vyXB$depictaiutilishared.layout_get_visible_recs_without_partial_rows(rows_visible + (rows_per_click || 0),
1103
- // Should this really be zero when we default rows_per_click to 1?
1104
- children_count, options);
1105
- should_hide_view_more_button = visible_recs === visible_recs_next_show_more;
1106
- } else {
1107
- visible_recs = $5vyXB$depictaiutilishared.layout_get_total_rec_amount_for_row(rows_visible, options);
1108
- should_hide_view_more_button = visible_recs >= children_count;
1109
- }
1110
- const should_hide_button_final = should_hide_view_more_button || max_rows !== -1 && rows_visible >= max_rows;
1111
- // 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
1112
- 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;
1113
- 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}` : ``}}`;
1114
- }).join("");
1115
- }));
1116
- });
1117
- 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
1118
- if (insert_after_container) container_element.after(style_element);
1119
- return [container_element, view_more_button_container(), view_less_button_container(), style_element];
1120
- }
1121
- var $363ce4d1d71041aa$var$_tmpl$ = ["<h2", ' class="recs-title">', "</h2>"];
1122
- function $363ce4d1d71041aa$export$d41d19e89346fa2({
1123
- recommendations_resource_: recommendations_resource_,
1124
- product_card_template_: product_card_template_,
1125
- layout_options_: layout_options_,
1126
- title_: title_,
1127
- NoResultsFallback_: NoResultsFallback_,
1128
- placeholderCacheKey_: placeholderCacheKey_
1129
- }) {
1130
- const is_showing_something = $5vyXB$solidjs.createMemo(() => recommendations_resource_.loading || recommendations_resource_()?.length);
1131
- const title = $5vyXB$solidjs.createMemo(() => title_?.()); // In case getter/accessor creates elements, don't create them twice
1132
- const num_placeholders_ = () => 20;
1133
- const slider = [$5vyXB$solidjsweb.createComponent((0, $5vyXB$solidjs.Show), {
1134
- get when() {
1135
- return title();
1136
- },
1137
- get children() {
1138
- return $5vyXB$solidjsweb.ssr($363ce4d1d71041aa$var$_tmpl$, $5vyXB$solidjsweb.ssrHydrationKey(), $5vyXB$solidjsweb.escape(title()));
1139
- }
1140
- }), $5vyXB$solidjsweb.createComponent((0, $a0e53f99354809d9$export$6649caad96ef8870), {
1141
- arrow_height_: 25,
1142
- arrow_width_: 12.5,
1143
- disable_fading_: true,
1144
- slider_ref_: slider => {
1145
- const {
1146
- insert_here: insert_here,
1147
- container: container
1148
- } = slider;
1149
- const Layout = props => $f48d0fbb00835aaa$export$445d8d3f5f706a40(props, insert_here, true);
1150
- // Do like this, so we don't have to call mergeProps ourselves
1151
- $5vyXB$solidjsweb.createComponent(Layout, $5vyXB$solidjsweb.mergeProps({
1152
- rows: "all",
1153
- layout: "slider"
1154
- }, layout_options_));
1155
- $5vyXB$depictaiutilishared.slider_fractional_factory(0, 0.75).constructor_plugin.call(slider, {}); // enable fractional scrolling
1156
- insert_here.before($fc23d7668ae0011d$export$a2cc176055f8f08());
1157
- container.classList.add("products");
1158
- },
1159
- get children() {
1160
- return $5vyXB$solidjsweb.createComponent((0, $5vyXB$solidjs.Suspense), {
1161
- get fallback() {
1162
- return $0caf87eaa19079da$export$f33414a4df0afd3f({
1163
- num_placeholders_: num_placeholders_,
1164
- product_card_template_: product_card_template_,
1165
- placeholderCacheKey_: placeholderCacheKey_
1166
- });
1167
- },
1168
- get children() {
1169
- return (() => {
1170
- // IIFE to make sure we access both the recommendations_resource and the resources containing the product card rendering results themselves within the Suspense boundary
1171
- const displays_by_key_ = $a73063cc642f3e5f$export$7f8bd308237ab5a5($5vyXB$solidjs.createMemo(() => recommendations_resource_() || []));
1172
- const {
1173
- renderedDisplays_: renderedDisplays_
1174
- } = $67155e1aeb7073f6$export$4a14175d33d81a96({
1175
- displays_by_key_: displays_by_key_,
1176
- product_card_template_: product_card_template_
1177
- });
1178
- return renderedDisplays_;
1179
- })();
1180
- }
1181
- });
1182
- }
1183
- })];
1184
- return $5vyXB$solidjsweb.createComponent((0, $5vyXB$solidjs.Show), {
1185
- get when() {
1186
- return is_showing_something();
1187
- },
1188
- get fallback() {
1189
- return NoResultsFallback_?.();
1190
- },
1191
- children: slider
1192
- });
1193
- }
1194
- function $95837413165cc2df$export$23fca46f3143581f(component, error_message) {
1195
- const component_in_error_boundary = do_with_elements => {
1196
- const error_boundary_wrapped = $edafe91daf3091d7$export$b69d0d92862de18b({
1197
- severity_: "error",
1198
- message_: error_message,
1199
- get children() {
1200
- const elements = component();
1201
- do_with_elements?.(elements);
1202
- return elements;
1203
- }
1204
- });
1205
- // This might return an accessor, in that case we need to "unwrap" it since our SDK consumers expect HTML elements or arrays thereof
1206
- if (typeof error_boundary_wrapped === "function")
1207
- // @ts-ignore
1208
- return error_boundary_wrapped();
1209
- // On the server it returns a string, so we just return that
1210
- return error_boundary_wrapped;
1211
- };
1212
- const owner = $5vyXB$solidjs.getOwner();
1213
- if (owner == null) return $5vyXB$solidjs.createRoot(dispose => {
1214
- // 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
1215
- return component_in_error_boundary(elements => {
1216
- const have_multiple = Array.isArray(elements);
1217
- if (have_multiple ? !elements?.length : !elements) return;
1218
- (0, $5vyXB$depictaiutilishared.observer).onremoved(have_multiple ? elements[0] : elements, ({
1219
- element: element
1220
- }) => {
1221
- if (document.documentElement.contains(element)) return; // If element has instantly been re-inserted, don't dispose
1222
- // See https://depictaiworkspace.slack.com/archives/C050GHEPBTR/p1695809102791259?thread_ts=1695106805.459729&cid=C050GHEPBTR
1223
- dispose();
1224
- });
1225
- });
1226
- });else
1227
- // we're already in a root so cleanups are handled
1228
- return component_in_error_boundary();
1229
- }
1230
- const $84798aaa863a4909$var$ListingContext = /*@__PURE__*/$5vyXB$solidjs.createContext();
1231
- function $84798aaa863a4909$export$e68cff63f76bd15b(props) {
1232
- const our_object = {};
1233
- return $5vyXB$solidjsweb.createComponent($84798aaa863a4909$var$ListingContext.Provider, {
1234
- value: our_object,
1235
- get children() {
1236
- return props.children;
1237
- }
1238
- });
1239
- }
1240
- function $84798aaa863a4909$export$8d0c4fdbb05a2f2e() {
1241
- return $5vyXB$solidjs.useContext($84798aaa863a4909$var$ListingContext);
1242
- }
1243
- function $061ff5b4c3d36171$export$89c6019e4baa40b1(props) {
1244
- const style = $5vyXB$solidjs.createMemo(() => {
1245
- const {
1246
- style: style,
1247
- height: height,
1248
- width: width
1249
- } = props;
1250
- return {
1251
- ...(style || {}),
1252
- height: height ?? "1em",
1253
- ...(width && {
1254
- width: width
1255
- })
1256
- };
1257
- });
1258
- return $5vyXB$solidjsweb.createComponent((0, $9fe9883b1d8ecccc$export$acb3eaade4b23afd), {
1259
- get style() {
1260
- return style();
1261
- },
1262
- get ["class"]() {
1263
- return props.class;
1264
- }
1265
- });
1266
- }
1267
- 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>"];
1268
- const $6f604560873e4f69$export$8a2234b5b1a5ebd4 = "--image-aspect-ratio";
1269
- function $6f604560873e4f69$export$ee1733d9a8495996() {
1270
- return $5vyXB$solidjsweb.ssr($6f604560873e4f69$var$_tmpl$, $5vyXB$solidjsweb.ssrHydrationKey(), $5vyXB$solidjsweb.escape($5vyXB$solidjsweb.createComponent((0, $3bc4a89b971a3af5$export$3f37af283f8fb843), {
1271
- aspectRatio: `var(${$6f604560873e4f69$export$8a2234b5b1a5ebd4}, 1)`
1272
- })), $5vyXB$solidjsweb.escape($5vyXB$solidjsweb.createComponent((0, $061ff5b4c3d36171$export$89c6019e4baa40b1), {
1273
- width: "20ch",
1274
- height: "1em"
1275
- })), $5vyXB$solidjsweb.escape($5vyXB$solidjsweb.createComponent((0, $061ff5b4c3d36171$export$89c6019e4baa40b1), {
1276
- width: "5ch",
1277
- height: "1em",
1278
- "class": "price"
1279
- })));
1280
- }
1281
- var $93304d59a9747aa6$var$_tmpl$ = ["<div", ' style="', '"', ">", "</div>"];
1282
- function $93304d59a9747aa6$export$94026ee33dbabc26(props) {
1283
- 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));
1284
- }
1285
- let $3ea8e0af95b5b7d2$var$browserIsBugged = false;
1286
- function $3ea8e0af95b5b7d2$export$2972b890694ced75(callback, {
1287
- timeout: timeout
1288
- }) {
1289
- if ($3ea8e0af95b5b7d2$var$browserIsBugged) timeout /= 4;
1290
- const cancel = () => {
1291
- cancelIdleCallback(idleHandle);
1292
- clearTimeout(racingTimeout);
1293
- };
1294
- const idleHandle = requestIdleCallback(deadline => {
1295
- cancel();
1296
- return callback(deadline);
1297
- }, {
1298
- timeout: timeout
1299
- });
1300
- const racingTimeout = setTimeout(() => {
1301
- $5vyXB$depictaiutilishared.dwarn("Browser did not respect requestIdleCallback timeout");
1302
- $3ea8e0af95b5b7d2$var$browserIsBugged = true;
1303
- cancel();
1304
- callback({
1305
- didTimeout: false,
1306
- timeRemaining() {
1307
- return 500;
1308
- }
1309
- });
1310
- }, timeout + 1000);
1311
- return cancel;
1312
- }
1313
- function $19950faaac026e09$export$e6fffe67d4cdd848(whatToWatch) {
1314
- const [size, setSize] = $5vyXB$solidjs.createSignal(0);
1315
- const resizeObserver = new ResizeObserver($5vyXB$depictaiutilishared.catchify(records => {
1316
- for (let j = 0; j < records.length; j++) {
1317
- const {
1318
- width: width
1319
- } = records[j].contentRect;
1320
- if (!width) continue;
1321
- setSize(Math.ceil(width));
1322
- }
1323
- }));
1324
- // 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.
1325
- // It doesn't seem to work even when waiting for it to be in the DOM, also wait an animation frame
1326
- const disconnect = (0, $5vyXB$depictaiutilishared.observer).onexists(whatToWatch, ({
1327
- element: element
1328
- }) => requestAnimationFrame($5vyXB$depictaiutilishared.catchify(() => resizeObserver.observe(element))));
1329
- $5vyXB$solidjs.onCleanup(() => {
1330
- resizeObserver.disconnect();
1331
- disconnect();
1332
- });
1333
- return size;
1334
- }
1335
- const $19950faaac026e09$var$onIdleFunctionsSymbol = /*@__PURE__*/Symbol("onIdleFunctions");
1336
- const $19950faaac026e09$export$f8945274f08a3105 = /*@__PURE__*/Symbol("listingContextAspectRatios");
1337
- const $19950faaac026e09$export$6066eb417ed2e9f7 = /*@__PURE__*/Symbol("listingContextAspectRatios");
1338
- function $19950faaac026e09$export$6e5611bc7e57e477(props) {
1339
- const src_options = $5vyXB$solidjs.createMemo(() => {
1340
- const {
1341
- src: src,
1342
- customUrls: customUrls
1343
- } = props;
1344
- const fallback_src = (customUrls || $19950faaac026e09$export$1d6267828870adda)(src, 400);
1345
- 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);
1346
- // The order here *might* matter - I've seen mobile safari always start with loading the 400px version when it was reversed
1347
- return {
1348
- srcset: srcset,
1349
- src: fallback_src
1350
- };
1351
- });
1352
- // Work around https://github.com/solidjs/solid/issues/1828
1353
- const img = new Image(); // Need to use new Image or browser might not start loading image before it's in the DOM
1354
- 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 <-
1355
- ]);
1356
-
1357
- const [hasSetSize, setHasSetSize] = $5vyXB$solidjs.createSignal(false);
1358
- const [hasDecoded, setHasDecoded] = $5vyXB$solidjs.createSignal(false);
1359
- const productCardIndexAccessor = $129b9b9c010039d0$export$e3faf4d95300054f();
1360
- 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
1361
- const listingContext = $84798aaa863a4909$export$8d0c4fdbb05a2f2e();
1362
- const isPrioritisedImage = $5vyXB$solidjs.createMemo(() => productCardIndexAccessor?.() < 8);
1363
- const shouldActuallyEnableLazyLoading = $5vyXB$solidjs.createMemo(() => {
1364
- const {
1365
- loading: loading
1366
- } = props;
1367
- if (loading === "force-lazy") return true;
1368
- return loading === "lazy" && !isPrioritisedImage();
1369
- });
1370
- const modifiedOtherAttributes = $5vyXB$solidjs.mergeProps(otherAttributes, {
1371
- get loading() {
1372
- return shouldActuallyEnableLazyLoading() ? "lazy" : undefined;
1373
- }
1374
- });
1375
- // 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
1376
- // Happened on singular, they have some weird observer (+we also have one but ours is at least 3x more efficient)
1377
- const executeWhenIdleBatched = (fn, isSizesUpdate) => {
1378
- if (typeof requestIdleCallback !== "function") return setTimeout(fn); // Old browsers don't get optimisation
1379
- 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)
1380
- // 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)
1381
- const existingStack = listingContext?.[$19950faaac026e09$var$onIdleFunctionsSymbol];
1382
- if (existingStack) return existingStack.add(fn);
1383
- const newStack = new Set([fn]);
1384
- if (listingContext) listingContext[$19950faaac026e09$var$onIdleFunctionsSymbol] = newStack;
1385
- const processStackWhenIdle = () => $3ea8e0af95b5b7d2$export$2972b890694ced75($5vyXB$depictaiutilishared.catchify(deadline => {
1386
- const start = performance.now();
1387
- const thirdDeadlineTime = deadline.timeRemaining() / 3; // observers coming after this take up 2-3x the time so don't use all of it
1388
- for (const fn of newStack) {
1389
- newStack.delete(fn);
1390
- fn();
1391
- const timeTaken = performance.now() - start;
1392
- if ((!deadline.timeRemaining() || timeTaken > thirdDeadlineTime) && newStack.size) {
1393
- // There's still work to be done but no time, so schedule another idle callback
1394
- processStackWhenIdle();
1395
- return;
1396
- }
1397
- }
1398
- // Stack is empty
1399
- if (listingContext) delete listingContext[$19950faaac026e09$var$onIdleFunctionsSymbol];
1400
- }), {
1401
- timeout: 15000
1402
- } // 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
1403
- );
1404
-
1405
- processStackWhenIdle();
1406
- };
1407
- let sizeSetFastPath = false;
1408
- let hasDecodedFastPath = false;
1409
- let timeoutSet = false;
1410
- let gotCleanedUp = false;
1411
- let srcJustChanged = true;
1412
- img.classList.add("s-responsive-image");
1413
- if (listingContext) {
1414
- let prevValue;
1415
- const aspectRatios = listingContext[$19950faaac026e09$export$f8945274f08a3105] ||= new Set();
1416
- const [, setMostPrevalentAspectRatio] = listingContext[$19950faaac026e09$export$6066eb417ed2e9f7] ||= $5vyXB$solidjs.createSignal();
1417
- img.addEventListener("load", $5vyXB$depictaiutilishared.catchify(() => {
1418
- if (props.keyRatioUpdating) {
1419
- if (!srcJustChanged) return;
1420
- srcJustChanged = false;
1421
- }
1422
- // 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
1423
- const aspectRatio_ = img.naturalWidth / img.naturalHeight;
1424
- if (prevValue) aspectRatios.delete(prevValue);
1425
- const newValue = !isNaN(aspectRatio_) ? {
1426
- aspectRatio_: aspectRatio_
1427
- } : undefined;
1428
- if (newValue) aspectRatios.add(newValue);
1429
- prevValue = newValue;
1430
- // Do all calculations resulting of an update directly, for performance
1431
- const asArray = [...aspectRatios].map(({
1432
- aspectRatio_: aspectRatio_
1433
- }) => aspectRatio_);
1434
- const mostPrevalentAspectRatio = $5vyXB$depictaiutilishared.findMostFrequentItem(asArray);
1435
- setMostPrevalentAspectRatio(mostPrevalentAspectRatio);
1436
- }));
1437
- $5vyXB$solidjs.onCleanup(() => prevValue && aspectRatios.delete(prevValue));
1438
- }
1439
- $5vyXB$solidjs.onCleanup(() => gotCleanedUp = true);
1440
- $5vyXB$solidjsweb.spread(img, $5vyXB$solidjs.mergeProps(modifiedOtherAttributes), false, true);
1441
- $5vyXB$solidjs.createRenderEffect(() => {
1442
- props.src;
1443
- srcJustChanged = true;
1444
- });
1445
- $5vyXB$solidjs.createEffect(() => {
1446
- if (!props.size()) return; // wait until we have a size, run every time the size changes
1447
- if (timeoutSet) return;
1448
- const handler = $5vyXB$depictaiutilishared.catchify(() => {
1449
- if (gotCleanedUp) return;
1450
- img.sizes = sizePX(); // use latest available value of props.size
1451
- if (!sizeSetFastPath) {
1452
- setHasSetSize(true);
1453
- sizeSetFastPath = true;
1454
- }
1455
- timeoutSet = false;
1456
- });
1457
- // Throttle the updating of sizes to avoid unnecessary image re-fetches during resize
1458
- // And also because we first set src after sizes has been set, wait with loading and decoding images until browser is idle
1459
- // This greatly improves performance when loading (more) products
1460
- // See https://depictaiworkspace.slack.com/archives/C05NJ0K3WRL/p1698220617663139
1461
- timeoutSet = true; // Important to set timeoutSet before the call to executeWhenIdleBatched since if this is an important image executeWhenIdleBatched will execute fn immediately
1462
- executeWhenIdleBatched(handler, true);
1425
+ const update_children_count = () => (0, $5vyXB$solidjsweb.isServer) ? 20 : set_children_count(container_element.children.length);
1426
+ const col_styling = $5vyXB$solidjs.createMemo(() => $5vyXB$depictaiutilishared.n_col_styling_with_dist(selector_beginning, props.grid_spacing, props.cols_at_size, props.layout, props.override_vertical_spacing));
1427
+ const default_currently_visible_signal = $5vyXB$solidjs.createSignal($5vyXB$solidjs.untrack(() => rows_or_empty_object().start_rows ?? 1)); // Keep this signal here, so it doesn't change when rows_or_empty_object and I think it's to be expected that the "internal default signal" stays the same
1428
+ const rows_visible_signal = $5vyXB$solidjs.createMemo(() => rows_or_empty_object().currently_visible || default_currently_visible_signal);
1429
+ const get_rows_visible = $5vyXB$solidjs.createMemo(() => rows_visible_signal()[0]());
1430
+ const set_rows_visible = $5vyXB$solidjs.createMemo(() => rows_visible_signal()[1]);
1431
+ const view_more_button_class = "m" + $5vyXB$solidjs.createUniqueId();
1432
+ const view_less_button_class = "l" + $5vyXB$solidjs.createUniqueId(); // https://github.com/solidjs/solid-docs/issues/263#issuecomment-1622388079
1433
+ const view_more_button_container = $5vyXB$solidjs.createMemo(() => have_a_view_more_button() && $5vyXB$solidjsweb.ssr($f48d0fbb00835aaa$var$_tmpl$, $5vyXB$solidjsweb.ssrHydrationKey(), `load-more-container ${$5vyXB$solidjsweb.escape(view_more_button_class, true)}`, $5vyXB$solidjsweb.escape(rows_or_empty_object().button)));
1434
+ // We need to have duplicate buttons because which ones is shown depends on the number of rows visible and therefore on the viewport size and therefore on the css media queries
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)));
1436
+ const [force_style_update, set_force_style_update] = $5vyXB$solidjs.createSignal("");
1437
+ $5vyXB$solidjs.createComputed(() => {
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);
1463
1442
  });
1464
- 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
1465
- $5vyXB$solidjs.createEffect(() => {
1466
- 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
1467
- Object.assign(img, src_options());
1468
- // Add to DOM once decoded to not require/block any paints before image has completed loading and avoid showing broken image symbol
1469
- // We can do this because there has to be a container around us giving us a size
1470
- // No need to listen if we're already in the DOM
1471
- if (hasDecodedFastPath) return;
1472
- if (shouldActuallyEnableLazyLoading()) {
1473
- // For lazy loading there's no decoding to wait for as it only occurs when the image is visible
1474
- // Make sure src is set before we put the image into the DOM though so no broken image symbol is shown
1475
- setHasDecoded(true);
1476
- 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);
1477
1449
  return;
1478
1450
  }
1479
- 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"
1480
- .then(async () => {
1481
- // Also wait with inserting image (i.e. paint) until browser is idle
1482
- await new Promise(r => executeWhenIdleBatched(r, false));
1483
- if (gotCleanedUp) return;
1484
- setHasDecoded(true);
1485
- hasDecodedFastPath = true;
1486
- });
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
+ }));
1487
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
+ })];
1488
1557
  return $5vyXB$solidjsweb.createComponent((0, $5vyXB$solidjs.Show), {
1489
1558
  get when() {
1490
- return hasDecoded();
1559
+ return is_showing_something();
1491
1560
  },
1492
- children: img
1561
+ get fallback() {
1562
+ return NoResultsFallback_?.();
1563
+ },
1564
+ children: slider
1493
1565
  });
1494
1566
  }
1495
- function $19950faaac026e09$var$make_srcset(url, resolutions, customGenerateImageUrl_) {
1496
- return resolutions.map(width => `${(customGenerateImageUrl_ || $19950faaac026e09$export$1d6267828870adda)(url, width)} ${width}w`).join(", ");
1497
- }
1498
- function $19950faaac026e09$export$1d6267828870adda(url, width) {
1499
- // 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)
1500
- // 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)
1501
- // That way we can just to string concatenation which is insanely fast
1502
- return url + "&width=" + encodeURIComponent(width);
1503
- }
1504
- const $a33065cfed827fc0$var$backupSizeSignal = /*@__PURE__*/$5vyXB$solidjs.createSignal();
1505
- const $a33065cfed827fc0$export$d7b7ab832c20e2f4 = /*@__PURE__*/Symbol("ShopifyContainedImage");
1506
- function $a33065cfed827fc0$export$e4b984597b71e989(props) {
1507
- const context = $84798aaa863a4909$export$8d0c4fdbb05a2f2e();
1508
- if (context && !context[$a33065cfed827fc0$export$d7b7ab832c20e2f4])
1509
- // create a signal that's the same for all items in this listing
1510
- context[$a33065cfed827fc0$export$d7b7ab832c20e2f4] = $5vyXB$solidjs.createSignal();
1511
- const [currentImageSize, setCurrentImageSize] = context?.[$a33065cfed827fc0$export$d7b7ab832c20e2f4] || $a33065cfed827fc0$var$backupSizeSignal; // use global fallback signal (might lead to blurry images) if no context is available
1512
- const [mostPrevalentAspectRatio] = context ?
1513
- // 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
1514
- context[(0, $19950faaac026e09$export$6066eb417ed2e9f7)] ||= $5vyXB$solidjs.createSignal() : [];
1515
- const container = $93304d59a9747aa6$export$94026ee33dbabc26({
1516
- // Write getters manually instead of using JSX, so we can do more complex logic in the aspectRatio getter without increasing bundle size
1517
- get class() {
1518
- return props.class;
1519
- },
1520
- get aspectRatio() {
1521
- if (props.autoAdjustAspectRatio) {
1522
- const targetRatio = mostPrevalentAspectRatio?.();
1523
- 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;
1524
1576
  }
1525
- return props.aspectRatio;
1526
- }
1527
- });
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
+ };
1528
1585
  const owner = $5vyXB$solidjs.getOwner();
1529
- let createdSizeAccessor = false;
1530
- let wasCleanedUp = false;
1531
- $5vyXB$solidjs.createEffect(() => {
1532
- if (currentImageSize() || wasCleanedUp) return; // We get into the effect when onCleanup is called if we don't have wasCleanedUp
1533
- // ensure we always have a size accessor
1534
- // 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
1535
- createdSizeAccessor = true;
1536
- setCurrentImageSize(() => $5vyXB$solidjs.runWithOwner(owner, () => $19950faaac026e09$export$e6fffe67d4cdd848(container)));
1537
- });
1538
- $5vyXB$solidjs.onCleanup(() => {
1539
- wasCleanedUp = true; // important to set this before the function call below and always, so the dead effects don't create dead size accessors
1540
- if (!createdSizeAccessor) return;
1541
- $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
1542
- });
1543
-
1544
- $5vyXB$solidjsweb.insert(container, $5vyXB$solidjsweb.createComponent((0, $19950faaac026e09$export$6e5611bc7e57e477), $5vyXB$solidjsweb.mergeProps({
1545
- get size() {
1546
- return $5vyXB$solidjs.createMemo(() => currentImageSize()?.() || 0);
1547
- },
1548
- get src() {
1549
- return props.src;
1550
- }
1551
- }, () => props.imgProps, {
1552
- get style() {
1553
- return props.imgProps?.style;
1554
- }
1555
- })));
1556
- return container;
1557
- }
1558
- function $d212a67662c5cf38$export$9d4a4b669b1929ab(props) {
1559
- return $5vyXB$solidjsweb.createComponent((0, $a33065cfed827fc0$export$e4b984597b71e989), $5vyXB$solidjsweb.mergeProps(props, {
1560
- get imgProps() {
1561
- return {
1562
- ...props.imgProps,
1563
- customUrls: (url, width // Apparently don't have to encode url for CF's service
1564
- ) => {
1565
- if (url?.startsWith?.("https://cdn.shopify.com"))
1566
- // 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,
1567
- // 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.
1568
- return $19950faaac026e09$export$1d6267828870adda(url, width);
1569
- // 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)
1570
- return `https://app.depict.ai/cdn-cgi/image/width=${width},format=auto/${url}`;
1571
- }
1572
- };
1573
- }
1574
- }));
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();
1575
1602
  }
1576
1603
  function $d659702496cb72ea$export$a71e92cfbb498adc(props) {
1577
1604
  return $5vyXB$solidjs.createMemo(() => {
@@ -12362,10 +12389,9 @@ function $32c662f618f5d80d$export$780a853d15174484({
12362
12389
  href: link
12363
12390
  }, {
12364
12391
  get children() {
12365
- return $5vyXB$solidjsweb.createComponent((0, $19950faaac026e09$export$6e5611bc7e57e477), {
12366
- get size() {
12367
- return $5vyXB$solidjs.createMemo(() => wrapperSize()?.() || 0);
12368
- },
12392
+ return $5vyXB$solidjsweb.createComponent((0, $d212a67662c5cf38$export$140423fa4bfb6d63), {
12393
+ size: () => wrapperSize()?.[0]?.() || 0,
12394
+ sizeHeight: () => wrapperSize()?.[1]?.() || 0,
12369
12395
  src: mediaUrl,
12370
12396
  "class": "d-standard-content"
12371
12397
  });