@depict-ai/ui 2.1.4 → 2.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/latest/index.js CHANGED
@@ -1,12 +1,12 @@
1
- import { add_to_version_info as $9HbP8$add_to_version_info, base64_encode_unicode as $9HbP8$base64_encode_unicode, base64_decode_unicode as $9HbP8$base64_decode_unicode, dlog as $9HbP8$dlog, queueMacroTask as $9HbP8$queueMacroTask, catchify as $9HbP8$catchify, is_safari as $9HbP8$is_safari, observer as $9HbP8$observer, Amazing_Slider as $9HbP8$Amazing_Slider, slider_snap_css as $9HbP8$slider_snap_css, slider_fading_factory as $9HbP8$slider_fading_factory, slider_fractional_factory as $9HbP8$slider_fractional_factory, camelCasifyObject as $9HbP8$camelCasifyObject, make_random_classname as $9HbP8$make_random_classname, n_col_styling_with_dist as $9HbP8$n_col_styling_with_dist, layout_get_visible_recs_without_partial_rows as $9HbP8$layout_get_visible_recs_without_partial_rows, layout_get_total_rec_amount_for_row as $9HbP8$layout_get_total_rec_amount_for_row, layout_media_query_header as $9HbP8$layout_media_query_header, report as $9HbP8$report, useExpandingContainer as $9HbP8$useExpandingContainer, standard_price_format as $9HbP8$standard_price_format, hex_to_rgb as $9HbP8$hex_to_rgb, relative_luminance_from_rgb as $9HbP8$relative_luminance_from_rgb, fetch_recs as $9HbP8$fetch_recs, snakeCasifyObject as $9HbP8$snakeCasifyObject, instant_exec_on_suspect_history_change as $9HbP8$instant_exec_on_suspect_history_change, base_url as $9HbP8$base_url, get_depict_id as $9HbP8$get_depict_id, get_user_id as $9HbP8$get_user_id, get_session_id as $9HbP8$get_session_id, sort_obj as $9HbP8$sort_obj, fetch_retry as $9HbP8$fetch_retry, add_version_query_params as $9HbP8$add_version_query_params, dwarn as $9HbP8$dwarn, make_url_with_query_params as $9HbP8$make_url_with_query_params, edit_current_page_meta_tags as $9HbP8$edit_current_page_meta_tags, javascript_media_query as $9HbP8$javascript_media_query, use_href_accessor as $9HbP8$use_href_accessor, is_debug as $9HbP8$is_debug, make_asyncIterable_exiter as $9HbP8$make_asyncIterable_exiter, href_change_ipns as $9HbP8$href_change_ipns, ContainedImage as $9HbP8$ContainedImage, buildThresholdList as $9HbP8$buildThresholdList, deparallelize_no_drop as $9HbP8$deparallelize_no_drop, ListenableSet as $9HbP8$ListenableSet, insert_surfaces as $9HbP8$insert_surfaces } from "@depict-ai/utilishared/latest";
2
- import { createComponent as $9HbP8$createComponent, template as $9HbP8$template, getNextElement as $9HbP8$getNextElement, effect as $9HbP8$effect, style as $9HbP8$style, spread as $9HbP8$spread, mergeProps as $9HbP8$mergeProps, runHydrationEvents as $9HbP8$runHydrationEvents, insert as $9HbP8$insert, setAttribute as $9HbP8$setAttribute, isServer as $9HbP8$isServer, addEventListener as $9HbP8$addEventListener, className as $9HbP8$className, memo as $9HbP8$memo, delegateEvents as $9HbP8$delegateEvents, classList as $9HbP8$classList, getNextMarker as $9HbP8$getNextMarker, Dynamic as $9HbP8$Dynamic, use as $9HbP8$use, setProperty as $9HbP8$setProperty } from "solid-js/web";
3
- import { createSignal as $9HbP8$createSignal, getOwner as $9HbP8$getOwner, createEffect as $9HbP8$createEffect, runWithOwner as $9HbP8$runWithOwner, onCleanup as $9HbP8$onCleanup, createMemo as $9HbP8$createMemo, createContext as $9HbP8$createContext, useContext as $9HbP8$useContext, createResource as $9HbP8$createResource, Suspense as $9HbP8$Suspense, Show as $9HbP8$Show, untrack as $9HbP8$untrack, createRenderEffect as $9HbP8$createRenderEffect, Index as $9HbP8$Index, createRoot as $9HbP8$createRoot, For as $9HbP8$For, createUniqueId as $9HbP8$createUniqueId, createComputed as $9HbP8$createComputed, ErrorBoundary as $9HbP8$ErrorBoundary, on as $9HbP8$on, batch as $9HbP8$batch, createReaction as $9HbP8$createReaction, mapArray as $9HbP8$mapArray, mergeProps as $9HbP8$mergeProps1 } from "solid-js";
1
+ import { add_to_version_info as $9HbP8$add_to_version_info, base64_encode_unicode as $9HbP8$base64_encode_unicode, base64_decode_unicode as $9HbP8$base64_decode_unicode, dlog as $9HbP8$dlog, queueMacroTask as $9HbP8$queueMacroTask, catchify as $9HbP8$catchify, is_safari as $9HbP8$is_safari, observer as $9HbP8$observer, dwarn as $9HbP8$dwarn, Amazing_Slider as $9HbP8$Amazing_Slider, slider_snap_css as $9HbP8$slider_snap_css, slider_fading_factory as $9HbP8$slider_fading_factory, slider_fractional_factory as $9HbP8$slider_fractional_factory, camelCasifyObject as $9HbP8$camelCasifyObject, make_random_classname as $9HbP8$make_random_classname, n_col_styling_with_dist as $9HbP8$n_col_styling_with_dist, layout_get_visible_recs_without_partial_rows as $9HbP8$layout_get_visible_recs_without_partial_rows, layout_get_total_rec_amount_for_row as $9HbP8$layout_get_total_rec_amount_for_row, layout_media_query_header as $9HbP8$layout_media_query_header, report as $9HbP8$report, useExpandingContainer as $9HbP8$useExpandingContainer, standard_price_format as $9HbP8$standard_price_format, hex_to_rgb as $9HbP8$hex_to_rgb, relative_luminance_from_rgb as $9HbP8$relative_luminance_from_rgb, fetch_recs as $9HbP8$fetch_recs, snakeCasifyObject as $9HbP8$snakeCasifyObject, instant_exec_on_suspect_history_change as $9HbP8$instant_exec_on_suspect_history_change, base_url as $9HbP8$base_url, get_depict_id as $9HbP8$get_depict_id, get_user_id as $9HbP8$get_user_id, get_session_id as $9HbP8$get_session_id, sort_obj as $9HbP8$sort_obj, fetch_retry as $9HbP8$fetch_retry, add_version_query_params as $9HbP8$add_version_query_params, make_url_with_query_params as $9HbP8$make_url_with_query_params, edit_current_page_meta_tags as $9HbP8$edit_current_page_meta_tags, javascript_media_query as $9HbP8$javascript_media_query, use_href_accessor as $9HbP8$use_href_accessor, is_debug as $9HbP8$is_debug, make_asyncIterable_exiter as $9HbP8$make_asyncIterable_exiter, href_change_ipns as $9HbP8$href_change_ipns, ContainedImage as $9HbP8$ContainedImage, buildThresholdList as $9HbP8$buildThresholdList, deparallelize_no_drop as $9HbP8$deparallelize_no_drop, ListenableSet as $9HbP8$ListenableSet, insert_surfaces as $9HbP8$insert_surfaces } from "@depict-ai/utilishared/latest";
2
+ import { createComponent as $9HbP8$createComponent, insert as $9HbP8$insert, template as $9HbP8$template, getNextElement as $9HbP8$getNextElement, effect as $9HbP8$effect, style as $9HbP8$style, spread as $9HbP8$spread, setAttribute as $9HbP8$setAttribute, mergeProps as $9HbP8$mergeProps1, isServer as $9HbP8$isServer, runHydrationEvents as $9HbP8$runHydrationEvents, addEventListener as $9HbP8$addEventListener, className as $9HbP8$className, memo as $9HbP8$memo, delegateEvents as $9HbP8$delegateEvents, classList as $9HbP8$classList, getNextMarker as $9HbP8$getNextMarker, Dynamic as $9HbP8$Dynamic, use as $9HbP8$use, setProperty as $9HbP8$setProperty } from "solid-js/web";
3
+ import { createSignal as $9HbP8$createSignal, getOwner as $9HbP8$getOwner, createEffect as $9HbP8$createEffect, runWithOwner as $9HbP8$runWithOwner, onCleanup as $9HbP8$onCleanup, createMemo as $9HbP8$createMemo, createContext as $9HbP8$createContext, useContext as $9HbP8$useContext, mergeProps as $9HbP8$mergeProps, Show as $9HbP8$Show, createResource as $9HbP8$createResource, Suspense as $9HbP8$Suspense, untrack as $9HbP8$untrack, createRenderEffect as $9HbP8$createRenderEffect, Index as $9HbP8$Index, createRoot as $9HbP8$createRoot, For as $9HbP8$For, createUniqueId as $9HbP8$createUniqueId, createComputed as $9HbP8$createComputed, ErrorBoundary as $9HbP8$ErrorBoundary, on as $9HbP8$on, batch as $9HbP8$batch, createReaction as $9HbP8$createReaction, mapArray as $9HbP8$mapArray } from "solid-js";
4
4
  import { createStore as $9HbP8$createStore, reconcile as $9HbP8$reconcile } from "solid-js/store";
5
5
 
6
6
  /*! Depict.ai search and product listing SDK */
7
7
  import { register_es_version } from "../multi_import_deduplicator.mjs";
8
8
  register_es_version("ui", "latest");
9
- const $ec291e0010116877$export$83d89fbfd8236492 = "2.1.4";
9
+ const $ec291e0010116877$export$83d89fbfd8236492 = "2.1.6";
10
10
  const $4147651646da990a$var$fallback_operator = "in";
11
11
  const $4147651646da990a$var$fallback_token = "";
12
12
  const $4147651646da990a$var$legacy_filter_prefix = "filter_";
@@ -201,7 +201,6 @@ function $f18d425032111270$export$94026ee33dbabc26(props) {
201
201
  return _el$;
202
202
  })();
203
203
  }
204
- const $e8ffe11ed01df0fe$var$_tmpl$ = /*#__PURE__*/$9HbP8$template(`<img>`);
205
204
  function $e8ffe11ed01df0fe$export$e6fffe67d4cdd848(whatToWatch) {
206
205
  const [size, setSize] = $9HbP8$createSignal(0);
207
206
  const resizeObserver = new ResizeObserver($9HbP8$catchify(records => {
@@ -226,6 +225,7 @@ function $e8ffe11ed01df0fe$export$e6fffe67d4cdd848(whatToWatch) {
226
225
  });
227
226
  return size;
228
227
  }
228
+ const $e8ffe11ed01df0fe$var$onIdleFunctionsSymbol = /*@__PURE__*/Symbol("onIdleFunctions");
229
229
  function $e8ffe11ed01df0fe$export$6e5611bc7e57e477(props) {
230
230
  // Enable reactive props
231
231
  const otherOptions = $9HbP8$createMemo(() => {
@@ -248,16 +248,95 @@ function $e8ffe11ed01df0fe$export$6e5611bc7e57e477(props) {
248
248
  srcset: srcset
249
249
  };
250
250
  });
251
- return (() => {
252
- const _el$ = $9HbP8$getNextElement($e8ffe11ed01df0fe$var$_tmpl$);
253
- $9HbP8$spread(_el$, $9HbP8$mergeProps(otherOptions, src_options, {
254
- get sizes() {
255
- return props.size() + "px";
251
+ // Work around https://github.com/solidjs/solid/issues/1828
252
+ const img = new Image(); // Need to use new Image or browser might not start loading image before it's in the DOM
253
+ const [hasSetSize, setHasSetSize] = $9HbP8$createSignal(false);
254
+ const [hasDecoded, setHasDecoded] = $9HbP8$createSignal(false);
255
+ const sizePX = $9HbP8$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
256
+ const listingContext = $011607bdf658f807$export$8d0c4fdbb05a2f2e();
257
+ // 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
258
+ // Happened on singular, they have some weird observer (+we also have one but ours is at least 3x more efficient)
259
+ const executeWhenIdleBatched = fn => {
260
+ if (typeof requestIdleCallback !== "function") setTimeout(fn); // Old browsers don't get optimisation
261
+ const existingStack = listingContext?.[$e8ffe11ed01df0fe$var$onIdleFunctionsSymbol];
262
+ if (existingStack) return existingStack.add(fn);
263
+ const newStack = new Set([fn]);
264
+ if (listingContext) listingContext[$e8ffe11ed01df0fe$var$onIdleFunctionsSymbol] = newStack;
265
+ const processStackWhenIdle = () => requestIdleCallback(deadline => {
266
+ const start = performance.now();
267
+ const thirdDeadlineTime = deadline.timeRemaining() / 3; // observers coming after this take up 2-3x the time so don't use all of it
268
+ for (const fn of newStack) {
269
+ newStack.delete(fn);
270
+ fn();
271
+ const timeTaken = performance.now() - start;
272
+ if ((!deadline.timeRemaining() || timeTaken > thirdDeadlineTime) && newStack.size) {
273
+ // There's still work to be done but no time, so schedule another idle callback
274
+ processStackWhenIdle();
275
+ return;
276
+ }
256
277
  }
257
- }), false, false);
258
- $9HbP8$runHydrationEvents();
259
- return _el$;
260
- })();
278
+ // Stack is empty
279
+ if (listingContext) delete listingContext[$e8ffe11ed01df0fe$var$onIdleFunctionsSymbol];
280
+ }, {
281
+ timeout: 15000
282
+ } // 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
283
+ );
284
+
285
+ processStackWhenIdle();
286
+ };
287
+ let sizeSetFastPath = false;
288
+ let hasDecodedFastPath = false;
289
+ let timeoutSet = false;
290
+ let gotCleanedUp = false;
291
+ $9HbP8$onCleanup(() => gotCleanedUp = true);
292
+ $9HbP8$spread(img, $9HbP8$mergeProps(otherOptions), false, true);
293
+ $9HbP8$createEffect(() => {
294
+ if (!props.size()) return; // wait until we have a size
295
+ if (timeoutSet) return;
296
+ const handler = $9HbP8$catchify(() => {
297
+ if (gotCleanedUp) return;
298
+ img.sizes = sizePX(); // use latest available value of props.size
299
+ if (!sizeSetFastPath) {
300
+ setHasSetSize(true);
301
+ sizeSetFastPath = true;
302
+ }
303
+ timeoutSet = false;
304
+ });
305
+ // Throttle the updating of sizes to avoid unnecessary image re-fetches during resize
306
+ // And also because we first set src after sizes has been set, wait with loading and decoding images until browser is idle
307
+ // This greatly improves performance when loading (more) products
308
+ // See https://depictaiworkspace.slack.com/archives/C05NJ0K3WRL/p1698220617663139
309
+ executeWhenIdleBatched(handler);
310
+ timeoutSet = true;
311
+ });
312
+ $9HbP8$createEffect(() => {
313
+ if (!props.size() || !hasSetSize()) return; // If size isn't known or set, don't assign src yet since it would cause the most low res image to load
314
+ Object.assign(img, src_options());
315
+ // Add to DOM once decoded to not require/block any paints before image has completed loading and avoid showing broken image symbol
316
+ // We can do this because there has to be a container around us giving us a size
317
+ // No need to listen if we're already in the DOM
318
+ if (hasDecodedFastPath) return;
319
+ if (props.loading === "lazy") {
320
+ // For lazy loading there's no decoding to wait for as it only occurs when the image is visible
321
+ // Make sure src is set before we put the image into the DOM though so no broken image symbol is shown
322
+ setHasDecoded(true);
323
+ hasDecodedFastPath = true;
324
+ }
325
+ img.decode().catch(e => $9HbP8$dwarn("Failed to decode image", e, img)) // Display the image also if loading failed so webdev can debug and doesn't get "no image"
326
+ .then(async () => {
327
+ // Also wait with inserting image (i.e. paint) until browser is idle
328
+ await new Promise(r => executeWhenIdleBatched(r));
329
+ if (gotCleanedUp) return;
330
+ setHasDecoded(true);
331
+ hasDecodedFastPath = true;
332
+ });
333
+ });
334
+ return $9HbP8$createComponent((0, $9HbP8$Show), {
335
+ get when() {
336
+ return hasDecoded();
337
+ },
338
+ children: img
339
+ });
261
340
  }
262
341
  function $e8ffe11ed01df0fe$var$make_srcset(url, resolutions) {
263
342
  return resolutions.map(width => `${$e8ffe11ed01df0fe$var$generateImageUrl(url, width)} ${width}w`).join(", ");
@@ -295,7 +374,7 @@ function $660070e2a394b3c3$export$e4b984597b71e989(props) {
295
374
  $9HbP8$queueMacroTask(() => setCurrentImageSize(undefined)); // 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
296
375
  });
297
376
 
298
- container.append($9HbP8$createComponent((0, $e8ffe11ed01df0fe$export$6e5611bc7e57e477), {
377
+ $9HbP8$insert(container, $9HbP8$createComponent((0, $e8ffe11ed01df0fe$export$6e5611bc7e57e477), {
299
378
  style: "width: 100%; height: 100%; object-fit: contain; position: absolute; inset: 0;",
300
379
  get size() {
301
380
  return $9HbP8$createMemo(() => currentImageSize()?.() || 0);
@@ -698,7 +777,7 @@ function $c8d5ff4524619fcd$export$d21e32dfedac04be(props) {
698
777
  const container_class = "x" + $9HbP8$createUniqueId();
699
778
  const container_element_ = (() => {
700
779
  const _el$ = $9HbP8$getNextElement($c8d5ff4524619fcd$var$_tmpl$);
701
- $9HbP8$spread(_el$, $9HbP8$mergeProps(() => props.element_attributes, {
780
+ $9HbP8$spread(_el$, $9HbP8$mergeProps1(() => props.element_attributes, {
702
781
  "classList": {
703
782
  [container_class]: true
704
783
  }
@@ -846,7 +925,7 @@ function $c4492d24952ed731$export$d41d19e89346fa2({
846
925
  } = slider;
847
926
  const Layout = props => $c8d5ff4524619fcd$export$445d8d3f5f706a40(props, insert_here, true);
848
927
  // Do like this, so we don't have to call mergeProps ourselves
849
- $9HbP8$createComponent(Layout, $9HbP8$mergeProps({
928
+ $9HbP8$createComponent(Layout, $9HbP8$mergeProps1({
850
929
  rows: "all",
851
930
  layout: "slider"
852
931
  }, layout_options_));
@@ -972,7 +1051,7 @@ function $3da8afe3ed57cf34$export$7da560f849543dff({
972
1051
  _el$4 = _el$3.nextSibling,
973
1052
  [_el$5, _co$2] = $9HbP8$getNextMarker(_el$4.nextSibling);
974
1053
  $9HbP8$insert(_el$, (0, $a458486f22b22f63$export$a2cc176055f8f08), _el$3, _co$);
975
- $9HbP8$insert(_el$, $9HbP8$createComponent((0, $c8d5ff4524619fcd$export$d21e32dfedac04be), $9HbP8$mergeProps({
1054
+ $9HbP8$insert(_el$, $9HbP8$createComponent((0, $c8d5ff4524619fcd$export$d21e32dfedac04be), $9HbP8$mergeProps1({
976
1055
  get rows() {
977
1056
  return rows_object_();
978
1057
  },
@@ -1369,7 +1448,7 @@ const $19976a74d273070d$var$_tmpl$ = /*#__PURE__*/$9HbP8$template(`<svg><path d=
1369
1448
  function $19976a74d273070d$export$3b621d86b1566b2(props = {}) {
1370
1449
  return (() => {
1371
1450
  const _el$ = $9HbP8$getNextElement($19976a74d273070d$var$_tmpl$);
1372
- $9HbP8$spread(_el$, $9HbP8$mergeProps(props, {
1451
+ $9HbP8$spread(_el$, $9HbP8$mergeProps1(props, {
1373
1452
  "xmlns": "http://www.w3.org/2000/svg",
1374
1453
  "width": "21.064",
1375
1454
  "height": "21.047",
@@ -1750,7 +1829,7 @@ const $f8a56ba74eedd0c6$var$_tmpl$ = /*#__PURE__*/$9HbP8$template(`<svg><path d=
1750
1829
  function $f8a56ba74eedd0c6$export$f21ab0717a89c77f(props) {
1751
1830
  return (() => {
1752
1831
  const _el$ = $9HbP8$getNextElement($f8a56ba74eedd0c6$var$_tmpl$);
1753
- $9HbP8$spread(_el$, $9HbP8$mergeProps(props, {
1832
+ $9HbP8$spread(_el$, $9HbP8$mergeProps1(props, {
1754
1833
  "xmlns": "http://www.w3.org/2000/svg",
1755
1834
  "width": "11",
1756
1835
  "height": "12"
@@ -2883,7 +2962,7 @@ const $93716a9ad0dea854$export$414f6a19d38e655c = ({
2883
2962
  [_el$6, _co$] = $9HbP8$getNextMarker(_el$5.nextSibling),
2884
2963
  _el$7 = _el$6.nextSibling,
2885
2964
  [_el$8, _co$2] = $9HbP8$getNextMarker(_el$7.nextSibling);
2886
- $9HbP8$spread(_el$2, $9HbP8$mergeProps(attributes, {
2965
+ $9HbP8$spread(_el$2, $9HbP8$mergeProps1(attributes, {
2887
2966
  get disabled() {
2888
2967
  return $9HbP8$memo(() => value().count_ === 0)() && !is_selected();
2889
2968
  },
@@ -4646,7 +4725,7 @@ function $6dee9211e57ac31a$export$ab6b147eec64fea5(props) {
4646
4725
  const container_class = "x" + $9HbP8$createUniqueId();
4647
4726
  const container_element_ = (() => {
4648
4727
  const _el$ = $9HbP8$getNextElement($6dee9211e57ac31a$var$_tmpl$);
4649
- $9HbP8$spread(_el$, $9HbP8$mergeProps(() => props.element_attributes, {
4728
+ $9HbP8$spread(_el$, $9HbP8$mergeProps1(() => props.element_attributes, {
4650
4729
  "classList": {
4651
4730
  [container_class]: true
4652
4731
  }
@@ -4952,7 +5031,7 @@ function $e7a7eb102ddc0c79$var$wrap_blocks_in_div(rendered_content_blocks, max_s
4952
5031
  return _el$;
4953
5032
  }
4954
5033
  });
4955
- return $9HbP8$mergeProps1(block, {
5034
+ return $9HbP8$mergeProps(block, {
4956
5035
  // Create content divs for the blocks with as much fine-grained diffing as possible?
4957
5036
  content: () => {
4958
5037
  // Sneaky on-demand rendering, so we don't render more blocks than we can show: we have the rendered value here and don't return a function that renders because if our block would be moved around we'd be guaranteed to re-render
@@ -5641,7 +5720,7 @@ function $757dac7f7c6c5241$export$9bf11afa910f536e({
5641
5720
  get children() {
5642
5721
  return (() => {
5643
5722
  const _el$34 = $9HbP8$getNextElement($757dac7f7c6c5241$var$_tmpl$5);
5644
- $9HbP8$insert(_el$34, $9HbP8$createComponent((0, $fab07f52c9861732$export$3f1a388cc0d8fed7), $9HbP8$mergeProps(args_for_filtering_, {
5723
+ $9HbP8$insert(_el$34, $9HbP8$createComponent((0, $fab07f52c9861732$export$3f1a388cc0d8fed7), $9HbP8$mergeProps1(args_for_filtering_, {
5645
5724
  are_in_modal_: true
5646
5725
  })));
5647
5726
  return _el$34;
@@ -7850,7 +7929,7 @@ const $16f0ed5ea30d8d9c$var$_tmpl$ = /*#__PURE__*/$9HbP8$template(`<svg><path d=
7850
7929
  function $16f0ed5ea30d8d9c$export$82eafebb825fc23f(props = {}) {
7851
7930
  return (() => {
7852
7931
  const _el$ = $9HbP8$getNextElement($16f0ed5ea30d8d9c$var$_tmpl$);
7853
- $9HbP8$spread(_el$, $9HbP8$mergeProps(props, {
7932
+ $9HbP8$spread(_el$, $9HbP8$mergeProps1(props, {
7854
7933
  "xmlns": "http://www.w3.org/2000/svg",
7855
7934
  "width": "20",
7856
7935
  "height": "22"
@@ -8023,7 +8102,7 @@ function $172e1b898d457050$export$7de92c4c2205ebf3({
8023
8102
  [_el$6, _co$2] = $9HbP8$getNextMarker(_el$5.nextSibling);
8024
8103
  $9HbP8$insert(_el$2, () => i18n_.search_recs_title_());
8025
8104
  $9HbP8$insert(_el$, (0, $a458486f22b22f63$export$a2cc176055f8f08), _el$4, _co$);
8026
- $9HbP8$insert(_el$, $9HbP8$createComponent((0, $c8d5ff4524619fcd$export$d21e32dfedac04be), $9HbP8$mergeProps({
8105
+ $9HbP8$insert(_el$, $9HbP8$createComponent((0, $c8d5ff4524619fcd$export$d21e32dfedac04be), $9HbP8$mergeProps1({
8027
8106
  rows: rows_object,
8028
8107
  layout: "grid",
8029
8108
  element_attributes: {
@@ -9967,7 +10046,7 @@ function $b2bf2cdcff8142d8$export$f631859cab12b342({
9967
10046
  [_el$8, _co$] = $9HbP8$getNextMarker(_el$7.nextSibling),
9968
10047
  _el$9 = _el$8.nextSibling,
9969
10048
  [_el$10, _co$2] = $9HbP8$getNextMarker(_el$9.nextSibling);
9970
- $9HbP8$insert(_el$4, $9HbP8$createComponent(LinkIfPossible, $9HbP8$mergeProps(make_link_attributes, {
10049
+ $9HbP8$insert(_el$4, $9HbP8$createComponent(LinkIfPossible, $9HbP8$mergeProps1(make_link_attributes, {
9971
10050
  tabIndex: "-1",
9972
10051
  get children() {
9973
10052
  return $9HbP8$createComponent((0, $190927650b4840eb$export$605674723bcc715c), {
@@ -9976,7 +10055,7 @@ function $b2bf2cdcff8142d8$export$f631859cab12b342({
9976
10055
  });
9977
10056
  }
9978
10057
  })));
9979
- $9HbP8$insert(_el$5, $9HbP8$createComponent(LinkIfPossible, $9HbP8$mergeProps({
10058
+ $9HbP8$insert(_el$5, $9HbP8$createComponent(LinkIfPossible, $9HbP8$mergeProps1({
9980
10059
  "class": "content-title line-clamp"
9981
10060
  }, make_link_attributes, {
9982
10061
  get title() {
@@ -10120,7 +10199,7 @@ function $49de9d31aeea1b5e$export$6d0c9c22f6652669({
10120
10199
  },
10121
10200
  number_of_results_: num_results
10122
10201
  }), _el$3, _co$);
10123
- $9HbP8$insert(_el$, $9HbP8$createComponent((0, $c8d5ff4524619fcd$export$d21e32dfedac04be), $9HbP8$mergeProps({
10202
+ $9HbP8$insert(_el$, $9HbP8$createComponent((0, $c8d5ff4524619fcd$export$d21e32dfedac04be), $9HbP8$mergeProps1({
10124
10203
  layout: "grid",
10125
10204
  element_attributes: {
10126
10205
  class: "cards"
@@ -10280,7 +10359,7 @@ function $7097477c78a89208$export$a54ec244c8863715({
10280
10359
  });
10281
10360
  const [sort_and_filter_element_, set_sort_and_filter_element_] = $9HbP8$createSignal();
10282
10361
  const no_results_text_ = $9HbP8$createMemo(() => (search_results_()?.content_search_links?.length ? i18n_.no_products_ : i18n_.no_results_text_)());
10283
- const results_for = $9HbP8$createComponent((0, $f8c929beb82c512b$export$9dd50d35b9d94fdf), $9HbP8$mergeProps({
10362
+ const results_for = $9HbP8$createComponent((0, $f8c929beb82c512b$export$9dd50d35b9d94fdf), $9HbP8$mergeProps1({
10284
10363
  get type() {
10285
10364
  return (0, $f8c929beb82c512b$export$2452208c79fe93ea).products;
10286
10365
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@depict-ai/ui",
3
- "version": "2.1.4",
3
+ "version": "2.1.6",
4
4
  "description": "Base package containing the actual UI of Depict UI along with translations, with a not-simplified API. We recommend using @depict-ai/js-ui or @depict-ai/react-ui instead.",
5
5
  "packageManager": "yarn@3.2.2",
6
6
  "sass": "styles.scss",
@@ -76,7 +76,7 @@ $parcel$export(module.exports, "defaultColsAtSize", () => $33eed84f447aa0c0$expo
76
76
  $parcel$export(module.exports, "defaultCategoryTitlePlugin", () => $33eed84f447aa0c0$export$7bf543b9d9be2c22);
77
77
  $parcel$export(module.exports, "version", () => $aa1938dec50d6c12$export$83d89fbfd8236492);
78
78
  /*! Depict.ai search and product listing SDK */
79
- const $aa1938dec50d6c12$export$83d89fbfd8236492 = "2.1.4";
79
+ const $aa1938dec50d6c12$export$83d89fbfd8236492 = "2.1.6";
80
80
  const $a68b73fd7ba0853f$var$fallback_operator = "in";
81
81
  const $a68b73fd7ba0853f$var$fallback_token = "";
82
82
  const $a68b73fd7ba0853f$var$legacy_filter_prefix = "filter_";
@@ -299,6 +299,7 @@ function $858fdcf73148519f$export$e6fffe67d4cdd848(whatToWatch) {
299
299
  });
300
300
  return size;
301
301
  }
302
+ const $858fdcf73148519f$var$onIdleFunctionsSymbol = /*@__PURE__*/Symbol("onIdleFunctions");
302
303
  function $858fdcf73148519f$export$6e5611bc7e57e477(props) {
303
304
  // Enable reactive props
304
305
  const otherOptions = $3hooq$solidjs.createMemo(() => {
@@ -321,11 +322,95 @@ function $858fdcf73148519f$export$6e5611bc7e57e477(props) {
321
322
  srcset: srcset
322
323
  };
323
324
  });
324
- return $3hooq$solidjsweb.ssrElement("img", $3hooq$solidjsweb.mergeProps(otherOptions, src_options, {
325
- get sizes() {
326
- return props.size() + "px";
327
- }
328
- }), undefined, true);
325
+ // Work around https://github.com/solidjs/solid/issues/1828
326
+ const img = new Image(); // Need to use new Image or browser might not start loading image before it's in the DOM
327
+ const [hasSetSize, setHasSetSize] = $3hooq$solidjs.createSignal(false);
328
+ const [hasDecoded, setHasDecoded] = $3hooq$solidjs.createSignal(false);
329
+ const sizePX = $3hooq$solidjs.createMemo(() => "".concat(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
330
+ const listingContext = $d067f3a30f047b41$export$8d0c4fdbb05a2f2e();
331
+ // 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
332
+ // Happened on singular, they have some weird observer (+we also have one but ours is at least 3x more efficient)
333
+ const executeWhenIdleBatched = fn => {
334
+ if (typeof requestIdleCallback !== "function") setTimeout(fn); // Old browsers don't get optimisation
335
+ const existingStack = listingContext === null || listingContext === void 0 ? void 0 : listingContext[$858fdcf73148519f$var$onIdleFunctionsSymbol];
336
+ if (existingStack) return existingStack.add(fn);
337
+ const newStack = new Set([fn]);
338
+ if (listingContext) listingContext[$858fdcf73148519f$var$onIdleFunctionsSymbol] = newStack;
339
+ const processStackWhenIdle = () => requestIdleCallback(deadline => {
340
+ const start = performance.now();
341
+ const thirdDeadlineTime = deadline.timeRemaining() / 3; // observers coming after this take up 2-3x the time so don't use all of it
342
+ for (const fn of newStack) {
343
+ newStack.delete(fn);
344
+ fn();
345
+ const timeTaken = performance.now() - start;
346
+ if ((!deadline.timeRemaining() || timeTaken > thirdDeadlineTime) && newStack.size) {
347
+ // There's still work to be done but no time, so schedule another idle callback
348
+ processStackWhenIdle();
349
+ return;
350
+ }
351
+ }
352
+ // Stack is empty
353
+ if (listingContext) delete listingContext[$858fdcf73148519f$var$onIdleFunctionsSymbol];
354
+ }, {
355
+ timeout: 15000
356
+ } // 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
357
+ );
358
+
359
+ processStackWhenIdle();
360
+ };
361
+ let sizeSetFastPath = false;
362
+ let hasDecodedFastPath = false;
363
+ let timeoutSet = false;
364
+ let gotCleanedUp = false;
365
+ $3hooq$solidjs.onCleanup(() => gotCleanedUp = true);
366
+ $3hooq$solidjsweb.spread(img, $3hooq$solidjs.mergeProps(otherOptions), false, true);
367
+ $3hooq$solidjs.createEffect(() => {
368
+ if (!props.size()) return; // wait until we have a size
369
+ if (timeoutSet) return;
370
+ const handler = $3hooq$depictaiutilishared.catchify(() => {
371
+ if (gotCleanedUp) return;
372
+ img.sizes = sizePX(); // use latest available value of props.size
373
+ if (!sizeSetFastPath) {
374
+ setHasSetSize(true);
375
+ sizeSetFastPath = true;
376
+ }
377
+ timeoutSet = false;
378
+ });
379
+ // Throttle the updating of sizes to avoid unnecessary image re-fetches during resize
380
+ // And also because we first set src after sizes has been set, wait with loading and decoding images until browser is idle
381
+ // This greatly improves performance when loading (more) products
382
+ // See https://depictaiworkspace.slack.com/archives/C05NJ0K3WRL/p1698220617663139
383
+ executeWhenIdleBatched(handler);
384
+ timeoutSet = true;
385
+ });
386
+ $3hooq$solidjs.createEffect(() => {
387
+ if (!props.size() || !hasSetSize()) return; // If size isn't known or set, don't assign src yet since it would cause the most low res image to load
388
+ Object.assign(img, src_options());
389
+ // Add to DOM once decoded to not require/block any paints before image has completed loading and avoid showing broken image symbol
390
+ // We can do this because there has to be a container around us giving us a size
391
+ // No need to listen if we're already in the DOM
392
+ if (hasDecodedFastPath) return;
393
+ if (props.loading === "lazy") {
394
+ // For lazy loading there's no decoding to wait for as it only occurs when the image is visible
395
+ // Make sure src is set before we put the image into the DOM though so no broken image symbol is shown
396
+ setHasDecoded(true);
397
+ hasDecodedFastPath = true;
398
+ }
399
+ img.decode().catch(e => $3hooq$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"
400
+ .then(async () => {
401
+ // Also wait with inserting image (i.e. paint) until browser is idle
402
+ await new Promise(r => executeWhenIdleBatched(r));
403
+ if (gotCleanedUp) return;
404
+ setHasDecoded(true);
405
+ hasDecodedFastPath = true;
406
+ });
407
+ });
408
+ return $3hooq$solidjsweb.createComponent((0, $3hooq$solidjs.Show), {
409
+ get when() {
410
+ return hasDecoded();
411
+ },
412
+ children: img
413
+ });
329
414
  }
330
415
  function $858fdcf73148519f$var$make_srcset(url, resolutions) {
331
416
  return resolutions.map(width => "".concat($858fdcf73148519f$var$generateImageUrl(url, width), " ").concat(width, "w")).join(", ");
@@ -363,7 +448,7 @@ function $28535bb7671c63d1$export$e4b984597b71e989(props) {
363
448
  $3hooq$depictaiutilishared.queueMacroTask(() => setCurrentImageSize(undefined)); // 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
364
449
  });
365
450
 
366
- container.append($3hooq$solidjsweb.createComponent((0, $858fdcf73148519f$export$6e5611bc7e57e477), {
451
+ $3hooq$solidjsweb.insert(container, $3hooq$solidjsweb.createComponent((0, $858fdcf73148519f$export$6e5611bc7e57e477), {
367
452
  style: "width: 100%; height: 100%; object-fit: contain; position: absolute; inset: 0;",
368
453
  get size() {
369
454
  return $3hooq$solidjs.createMemo(() => {
@@ -7,7 +7,7 @@ import { CategorySuggestion, SearchSuggestionsResponse } from "@depict-ai/types/
7
7
  import { BaseSearchRequest } from "@depict-ai/types/api/BaseSearchRequest";
8
8
  import { SearchSuggestionsRequest } from "@depict-ai/types/api/SearchSuggestionsRequest";
9
9
  import { ProductListingRequestV2 } from "@depict-ai/types/api/ProductListingRequestV2";
10
- export const version = "2.1.4";
10
+ export const version = "2.1.6";
11
11
  /**
12
12
  * Use `javascript_media_query` but return a reactive accessor instead of taking a callback function
13
13
  */
@@ -152,17 +152,19 @@ export function ImageContainer(props: {
152
152
  export function makeSizeAccessor(whatToWatch: HTMLElement): Accessor<number>;
153
153
  /**
154
154
  * Automatically generate a srcset from the shopify CDN for an image and set the sizes attribute to the provided accessor.
155
+ * Will also delay loading and decoding of image until the browser is idle (with 5s timeout) to improve filtering/loading more performance.
155
156
  * This is used for our responsive images:
156
157
  * 1. The image must have a container with a fixed size (or aspect ratio) that is independent of the image. When aspectRatio is configured on the depict-cards element as data attribute, we will wrap the image in a ImageContainer for this. If it's false, the user has to provide this container themselves.
157
158
  * 2. We set a ResizeObserver on one of the currently visible images (see makeSizeAccessor)
158
159
  * 3. We set the size attribute of all the visible images to the size of the container we're observing. The point of this is that the sizes attribute is used to determine which image to load, and usually it's set by the user and depends on the relationship between image size and viewport size. By using a ResizeObserver, we can make sure the sizes attribute is always set to the correct value without it having to be configured. This will make so the browser always loads the correct image size for a crisp image but still fast load.
160
+ * You need to use insert(domNode, <ShopifyResponsiveImg size={sizeAccessor} src={src} />) if you want to insert the return value of this component into a DOM element manually, where you `import { insert } from "solid-js/web";` because we first want to insert the image once it has loaded.
159
161
  */
160
162
  export function ShopifyResponsiveImg(props: {
161
163
  resolutions?: number[];
162
164
  size: Accessor<number>;
163
165
  } & Omit<JSX.ImgHTMLAttributes<HTMLImageElement>, "srcset" | "src" | "sizes"> & {
164
166
  src: string;
165
- }): HTMLImageElement;
167
+ }): JSX.Element;
166
168
  export const shopifyContainedImageContextSymbol: unique symbol;
167
169
  /**
168
170
  * Abstraction built on top of ShopifyResponsiveImg. This is your one-stop-shop If you just need a responsive image.