@depict-ai/ui 4.0.0 → 4.0.2
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/ES10/index.cjs +89 -27
- package/ES10/index.d.ts +26 -24
- package/ES10/index.js +93 -31
- package/latest/index.cjs +86 -27
- package/latest/index.d.ts +26 -24
- package/latest/index.js +90 -31
- package/package.json +3 -3
- package/server/ES10/index.cjs +89 -27
- package/server/ES10/index.d.ts +26 -24
- package/server/ES10/index.js +93 -31
- package/server/latest/index.cjs +86 -27
- package/server/latest/index.d.ts +26 -24
- package/server/latest/index.js +90 -31
package/server/latest/index.cjs
CHANGED
|
@@ -86,7 +86,7 @@ $parcel$export(module.exports, "defaultCategoryTitlePlugin", () => $a3280f0aad99
|
|
|
86
86
|
$parcel$export(module.exports, "version", () => $b757f75811f3261f$export$83d89fbfd8236492);
|
|
87
87
|
$parcel$export(module.exports, "SearchField", () => $c0a0659cf97e8eb2$export$316f6f283ae64765);
|
|
88
88
|
/*! Depict.ai search and product listing SDK */
|
|
89
|
-
const $b757f75811f3261f$export$83d89fbfd8236492 = "4.0.
|
|
89
|
+
const $b757f75811f3261f$export$83d89fbfd8236492 = "4.0.2";
|
|
90
90
|
function $53df95e470b2f8d2$export$e417c49320921907(dependency, fetcher) {
|
|
91
91
|
const [promiseOfCurrentFetcherRun, setPromiseOfCurrentFetcherRun] = $5vyXB$solidjs.createSignal();
|
|
92
92
|
const deparallelizedFetcher = $5vyXB$depictaiutilishared.deparallelize_no_drop(async dependencyValue => {
|
|
@@ -1864,6 +1864,7 @@ function $19950faaac026e09$export$e6fffe67d4cdd848(whatToWatch) {
|
|
|
1864
1864
|
return size;
|
|
1865
1865
|
}
|
|
1866
1866
|
const $19950faaac026e09$var$onIdleFunctionsSymbol = /*@__PURE__*/Symbol("onIdleFunctions");
|
|
1867
|
+
const $19950faaac026e09$export$f8945274f08a3105 = /*@__PURE__*/Symbol("listingContextAspectRatios");
|
|
1867
1868
|
function $19950faaac026e09$export$6e5611bc7e57e477(props) {
|
|
1868
1869
|
// Enable reactive props
|
|
1869
1870
|
const otherOptions = $5vyXB$solidjs.createMemo(() => {
|
|
@@ -1928,6 +1929,21 @@ function $19950faaac026e09$export$6e5611bc7e57e477(props) {
|
|
|
1928
1929
|
let timeoutSet = false;
|
|
1929
1930
|
let gotCleanedUp = false;
|
|
1930
1931
|
img.classList.add("s-responsive-image");
|
|
1932
|
+
if (listingContext) {
|
|
1933
|
+
let prevValue;
|
|
1934
|
+
const aspectRatios = listingContext[$19950faaac026e09$export$f8945274f08a3105] ||= new (0, $5vyXB$depictaiutilishared.ListenableSet)();
|
|
1935
|
+
img.addEventListener("load", $5vyXB$depictaiutilishared.catchify(() => {
|
|
1936
|
+
// Save our aspect ratio whenever it changes, so that we can base the containers on the most dominant aspect ratio, used in SearchModalV2
|
|
1937
|
+
const aspectRatio_ = img.naturalWidth / img.naturalHeight;
|
|
1938
|
+
if (prevValue) aspectRatios.delete(prevValue);
|
|
1939
|
+
const newValue = !isNaN(aspectRatio_) ? {
|
|
1940
|
+
aspectRatio_: aspectRatio_
|
|
1941
|
+
} : undefined;
|
|
1942
|
+
if (newValue) aspectRatios.add(newValue);
|
|
1943
|
+
prevValue = newValue;
|
|
1944
|
+
}));
|
|
1945
|
+
$5vyXB$solidjs.onCleanup(() => prevValue && aspectRatios.delete(prevValue));
|
|
1946
|
+
}
|
|
1931
1947
|
$5vyXB$solidjs.onCleanup(() => gotCleanedUp = true);
|
|
1932
1948
|
$5vyXB$solidjsweb.spread(img, $5vyXB$solidjs.mergeProps(otherOptions), false, true);
|
|
1933
1949
|
$5vyXB$solidjs.createEffect(() => {
|
|
@@ -1995,9 +2011,28 @@ function $a33065cfed827fc0$export$e4b984597b71e989(props) {
|
|
|
1995
2011
|
// create a signal that's the same for all items in this listing
|
|
1996
2012
|
context[$a33065cfed827fc0$export$d7b7ab832c20e2f4] = $5vyXB$solidjs.createSignal();
|
|
1997
2013
|
const [currentImageSize, setCurrentImageSize] = context?.[$a33065cfed827fc0$export$d7b7ab832c20e2f4] || $a33065cfed827fc0$var$backupSizeSignal; // use global fallback signal (might lead to blurry images) if no context is available
|
|
2014
|
+
const aspectRatiosSet = context ?
|
|
2015
|
+
// If the context exists we have to create the set here as getting it here would be too late when it's created by ShopifyResponsiveImg below
|
|
2016
|
+
context[(0, $19950faaac026e09$export$f8945274f08a3105)] ||= new (0, $5vyXB$depictaiutilishared.ListenableSet)() : undefined;
|
|
2017
|
+
const [aspectRatios, setAspectRatios] = $5vyXB$solidjs.createSignal(aspectRatiosSet, {
|
|
2018
|
+
equals: false
|
|
2019
|
+
});
|
|
2020
|
+
const aspectRatioToUse = $5vyXB$solidjs.createMemo(() => {
|
|
2021
|
+
const aspectRatiosSet = aspectRatios(); // This signal "changes" to the same set every time the set changes, so we can use it as a dependency here
|
|
2022
|
+
useMostPrevalentAspectRatio: {
|
|
2023
|
+
if (!aspectRatiosSet || !props.autoAdjustAspectRatio) break useMostPrevalentAspectRatio;
|
|
2024
|
+
// Get the aspect ratio that most of the loaded images inside the ListingProvider we are, load
|
|
2025
|
+
const asArray = [...aspectRatiosSet].map(({
|
|
2026
|
+
aspectRatio_: aspectRatio_
|
|
2027
|
+
}) => aspectRatio_);
|
|
2028
|
+
const mostPrevalentAspectRatio = $5vyXB$depictaiutilishared.findMostFrequentItem(asArray);
|
|
2029
|
+
if (mostPrevalentAspectRatio) return `var(${(0, $6f604560873e4f69$export$8a2234b5b1a5ebd4)}, ${mostPrevalentAspectRatio})`;
|
|
2030
|
+
}
|
|
2031
|
+
return props.aspectRatio;
|
|
2032
|
+
});
|
|
1998
2033
|
const container = $5vyXB$solidjsweb.createComponent((0, $93304d59a9747aa6$export$94026ee33dbabc26), {
|
|
1999
2034
|
get aspectRatio() {
|
|
2000
|
-
return
|
|
2035
|
+
return aspectRatioToUse();
|
|
2001
2036
|
},
|
|
2002
2037
|
get ["class"]() {
|
|
2003
2038
|
return props.class;
|
|
@@ -2006,6 +2041,10 @@ function $a33065cfed827fc0$export$e4b984597b71e989(props) {
|
|
|
2006
2041
|
const owner = $5vyXB$solidjs.getOwner();
|
|
2007
2042
|
let createdSizeAccessor = false;
|
|
2008
2043
|
let wasCleanedUp = false;
|
|
2044
|
+
for (const event of ["add", "delete"]) {
|
|
2045
|
+
aspectRatiosSet?.addEventListener(event, () => setAspectRatios(aspectRatiosSet));
|
|
2046
|
+
$5vyXB$solidjs.onCleanup(() => aspectRatiosSet?.removeEventListener(event, () => setAspectRatios(aspectRatiosSet)));
|
|
2047
|
+
}
|
|
2009
2048
|
$5vyXB$solidjs.createEffect(() => {
|
|
2010
2049
|
if (currentImageSize() || wasCleanedUp) return; // We get into the effect when onCleanup is called if we don't have wasCleanedUp
|
|
2011
2050
|
// ensure we always have a size accessor
|
|
@@ -2835,7 +2874,8 @@ function $11597ae03e703a47$var$RawSearchModalV2({
|
|
|
2835
2874
|
get src() {
|
|
2836
2875
|
return props.src_;
|
|
2837
2876
|
},
|
|
2838
|
-
|
|
2877
|
+
autoAdjustAspectRatio: true,
|
|
2878
|
+
aspectRatio: 1
|
|
2839
2879
|
}),
|
|
2840
2880
|
...instant_results_options_
|
|
2841
2881
|
})));
|
|
@@ -3047,7 +3087,15 @@ async function $9abb0a35d4b60ed3$export$79b1565500412d9b(search_modal, modal_fn_
|
|
|
3047
3087
|
const actually_close = () => {
|
|
3048
3088
|
dispose();
|
|
3049
3089
|
on_dispose?.();
|
|
3050
|
-
|
|
3090
|
+
const {
|
|
3091
|
+
activeElement: activeElement
|
|
3092
|
+
} = document;
|
|
3093
|
+
modal_els.forEach(el => {
|
|
3094
|
+
if (el.contains(activeElement))
|
|
3095
|
+
// Fix page jumping to the bottom when closing modal with scape after animation in safari
|
|
3096
|
+
activeElement?.blur?.();
|
|
3097
|
+
el.remove();
|
|
3098
|
+
});
|
|
3051
3099
|
};
|
|
3052
3100
|
if (animation_started && +new Date() - animation_started > 1000)
|
|
3053
3101
|
// Animation broke, close it this time
|
|
@@ -10304,30 +10352,37 @@ function $5cbaffcb5602e671$export$44f738469d5570cf({
|
|
|
10304
10352
|
modalSearchFieldOuterWidth_: modalSearchFieldOuterWidth_
|
|
10305
10353
|
}) {
|
|
10306
10354
|
return $5vyXB$solidjs.createRoot(dispose => {
|
|
10355
|
+
const [innerWidthReactive, setInnerWidthReactive] = $5vyXB$solidjs.createSignal(innerWidth);
|
|
10356
|
+
const resizeObserver = new ResizeObserver(records => setInnerWidthReactive(records.at(-1).contentRect.width));
|
|
10357
|
+
const {
|
|
10358
|
+
left: left,
|
|
10359
|
+
top: top,
|
|
10360
|
+
width: width
|
|
10361
|
+
} = actualField_.getBoundingClientRect();
|
|
10307
10362
|
const fakeField = makeFakeField_();
|
|
10308
10363
|
const owner = $5vyXB$solidjs.getOwner();
|
|
10309
10364
|
const inModalFieldWidth = $5vyXB$solidjs.createMemo(
|
|
10310
10365
|
// Can't have `min(${modalSearchFieldOuterWidth_()}px, var(--field-max-width, 600px))` because the WAAPI doesn't support that, so we need ot calculate it in JS
|
|
10311
|
-
() => Math.min(modalSearchFieldOuterWidth_(), parseFloat(getComputedStyle(actualField_).getPropertyValue("--field-max-width") || "600"))
|
|
10366
|
+
() => Math.min(modalSearchFieldOuterWidth_(), parseFloat(getComputedStyle(actualField_).getPropertyValue("--field-max-width") || "600")));
|
|
10367
|
+
const inModalFieldWidthPx = $5vyXB$solidjs.createMemo(() => inModalFieldWidth() + "px");
|
|
10368
|
+
let disableResizePollingTimeout;
|
|
10369
|
+
resizeObserver.observe(document.documentElement);
|
|
10370
|
+
$5vyXB$solidjs.onCleanup(() => resizeObserver.disconnect());
|
|
10312
10371
|
actualField_.replaceWith(fakeField);
|
|
10313
10372
|
// Don't move the wrapped div since that would confuse run_in_root_or_auto_cleanup, but do actually move the field the user clicked around so that all selection stuff etc. is easier
|
|
10314
10373
|
const addedToBody = wrap_ ? $5vyXB$solidjsweb.ssr($5cbaffcb5602e671$var$_tmpl$, $5vyXB$solidjsweb.ssrHydrationKey(), $5vyXB$solidjsweb.escape(actualField_)) : actualField_;
|
|
10315
10374
|
document.body.append(addedToBody);
|
|
10316
|
-
const {
|
|
10317
|
-
left: left,
|
|
10318
|
-
top: top,
|
|
10319
|
-
width: width
|
|
10320
|
-
} = fakeField.getBoundingClientRect();
|
|
10321
10375
|
const zIndexOfFake = getComputedStyle(fakeField).zIndex;
|
|
10322
10376
|
Object.assign(addedToBody.style, {
|
|
10323
10377
|
position: "fixed",
|
|
10324
10378
|
top: top + "px",
|
|
10379
|
+
left: left + "px",
|
|
10325
10380
|
width: width + "px",
|
|
10326
10381
|
...(zIndexOfFake !== "auto" ? {
|
|
10327
10382
|
zIndex: +zIndexOfFake + 1
|
|
10328
10383
|
} : {})
|
|
10329
10384
|
});
|
|
10330
|
-
const pxOffCenter =
|
|
10385
|
+
const pxOffCenter = $5vyXB$solidjs.untrack(innerWidthReactive) / 2 - (left + width / 2);
|
|
10331
10386
|
const openDuration = pxOffCenter > 100 ? 250 : 125; // faster animations if little left-right movement
|
|
10332
10387
|
const closeDuration = pxOffCenter > 100 ? 150 : 100;
|
|
10333
10388
|
setPollAlignment_(true);
|
|
@@ -10346,24 +10401,30 @@ function $5cbaffcb5602e671$export$44f738469d5570cf({
|
|
|
10346
10401
|
// Wait until the ResizeObserver has delivered a value in case that the modal is small or has much padding so we know that we can't animate our fake field to be wider than that
|
|
10347
10402
|
addedToBody.animate([{
|
|
10348
10403
|
left: left + "px",
|
|
10349
|
-
transform: "translateX(0%)",
|
|
10350
10404
|
width: width + "px"
|
|
10351
10405
|
}, {
|
|
10352
|
-
left:
|
|
10353
|
-
|
|
10354
|
-
width: $5vyXB$solidjs.untrack(inModalFieldWidth)
|
|
10406
|
+
left: `${$5vyXB$solidjs.untrack(innerWidthReactive) / 2 - $5vyXB$solidjs.untrack(inModalFieldWidth) / 2}px`,
|
|
10407
|
+
width: $5vyXB$solidjs.untrack(inModalFieldWidthPx)
|
|
10355
10408
|
}], {
|
|
10356
10409
|
duration: openDuration,
|
|
10357
10410
|
easing: "ease-in"
|
|
10358
10411
|
}).finished.then(() => {
|
|
10359
10412
|
setPollAlignment_(false);
|
|
10360
|
-
$5vyXB$solidjs.runWithOwner(owner, () => $5vyXB$solidjs.createEffect(() =>
|
|
10361
|
-
|
|
10362
|
-
|
|
10363
|
-
|
|
10364
|
-
|
|
10365
|
-
|
|
10366
|
-
|
|
10413
|
+
$5vyXB$solidjs.runWithOwner(owner, () => $5vyXB$solidjs.createEffect(() => {
|
|
10414
|
+
// When animation has finished, still dynamically set the size of the search field behind in case the user resizes the window
|
|
10415
|
+
Object.assign(addedToBody.style, {
|
|
10416
|
+
// This is left: 50%, transform: translateX(-50) with extra steps but when using it safari and firefox glitch out like crazy
|
|
10417
|
+
left: `${innerWidthReactive() / 2 - inModalFieldWidth() / 2}px`,
|
|
10418
|
+
width: inModalFieldWidthPx()
|
|
10419
|
+
});
|
|
10420
|
+
// We might only have changed the left position which align_field doesn't know about, make it poll the position for a while
|
|
10421
|
+
setPollAlignment_(true);
|
|
10422
|
+
if (disableResizePollingTimeout) clearTimeout(disableResizePollingTimeout);
|
|
10423
|
+
disableResizePollingTimeout = setTimeout($5vyXB$depictaiutilishared.catchify(() => {
|
|
10424
|
+
setPollAlignment_(false);
|
|
10425
|
+
disableResizePollingTimeout = undefined;
|
|
10426
|
+
}), 1000);
|
|
10427
|
+
}));
|
|
10367
10428
|
});
|
|
10368
10429
|
return true;
|
|
10369
10430
|
}, false);
|
|
@@ -10406,13 +10467,11 @@ function $5cbaffcb5602e671$export$44f738469d5570cf({
|
|
|
10406
10467
|
transition: `opacity ${closeDuration}ms ease-out`
|
|
10407
10468
|
}));
|
|
10408
10469
|
await Promise.all([addedToBody.animate([{
|
|
10409
|
-
width: $5vyXB$solidjs.untrack(
|
|
10410
|
-
left:
|
|
10411
|
-
transform: "translateX(-50%)"
|
|
10470
|
+
width: $5vyXB$solidjs.untrack(inModalFieldWidthPx),
|
|
10471
|
+
left: `${$5vyXB$solidjs.untrack(innerWidthReactive) / 2 - $5vyXB$solidjs.untrack(inModalFieldWidth) / 2}px`
|
|
10412
10472
|
}, {
|
|
10413
10473
|
width: width + "px",
|
|
10414
|
-
left: left + "px"
|
|
10415
|
-
transform: "translateX(0%)"
|
|
10474
|
+
left: left + "px"
|
|
10416
10475
|
}], {
|
|
10417
10476
|
duration: closeDuration,
|
|
10418
10477
|
fill: "forwards",
|
package/server/latest/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { ProductListingRequestV3 } from "@depict-ai/types/api/ProductListingRequ
|
|
|
10
10
|
import { GetListingRequest } from "@depict-ai/types/api/GetListingRequest";
|
|
11
11
|
import { BaseSearchRequestV3 } from "@depict-ai/types/api/BaseSearchRequestV3";
|
|
12
12
|
import { SearchFilter as _SearchFilter2 } from "@depict-ai/types/api/SearchRequestV2";
|
|
13
|
-
export const version = "4.0.
|
|
13
|
+
export const version = "4.0.2";
|
|
14
14
|
export type ModalAlignmentSignals = {
|
|
15
15
|
body_: Signal<JSX.CSSProperties>;
|
|
16
16
|
field_: Signal<JSX.CSSProperties>;
|
|
@@ -407,6 +407,28 @@ export function ShopifyResponsiveImg(props: {
|
|
|
407
407
|
} & Omit<JSX.ImgHTMLAttributes<HTMLImageElement>, "srcset" | "src" | "sizes"> & {
|
|
408
408
|
src: string;
|
|
409
409
|
}): JSX.Element;
|
|
410
|
+
type ImagePlaceholderBaseOptions = {
|
|
411
|
+
style?: JSX.CSSProperties;
|
|
412
|
+
class?: string;
|
|
413
|
+
};
|
|
414
|
+
type ImagePlaceholderBlockOptions = {
|
|
415
|
+
width: string;
|
|
416
|
+
height: string;
|
|
417
|
+
};
|
|
418
|
+
type ImagePlaceholderImageOptions = {
|
|
419
|
+
aspectRatio: number | string;
|
|
420
|
+
};
|
|
421
|
+
/**
|
|
422
|
+
* A placeholder that can be used instead of an image or other block of content while it's loading.
|
|
423
|
+
* The placeholder has `display:block`, meaning it will create a new "row" in the layout for itself. Can be used either for images with a defined aspect ratio (ContainedImage) or blocks.
|
|
424
|
+
* @property aspectRatio if aspectRatio is defined the placeholder will be in "image mode" and fill out the available width and then adjust the height according to the aspectRatio
|
|
425
|
+
* @property width If width and height is set, the defined width and height will be used.
|
|
426
|
+
* @property height If width and height is set, the defined width and height will be used.
|
|
427
|
+
* @property class extra classes to add to the placeholder
|
|
428
|
+
* @property style extra styles to add to the placeholder
|
|
429
|
+
*/
|
|
430
|
+
export function ImagePlaceholder(props: ImagePlaceholderBaseOptions & (ImagePlaceholderBlockOptions | ImagePlaceholderImageOptions)): JSX.Element;
|
|
431
|
+
export function DefaultInstantCardPlaceholder(): HTMLDivElement;
|
|
410
432
|
export const shopifyContainedImageContextSymbol: unique symbol;
|
|
411
433
|
/**
|
|
412
434
|
* Abstraction built on top of ShopifyResponsiveImg. This is your one-stop-shop If you just need a responsive image.
|
|
@@ -417,11 +439,13 @@ export const shopifyContainedImageContextSymbol: unique symbol;
|
|
|
417
439
|
* @property aspectRatio aspect ratio of the image
|
|
418
440
|
* @property class extra class to add to the container
|
|
419
441
|
* @property alt alt text for the image
|
|
442
|
+
* @property autoAdjustAspectRatio whether to automatically adjust the aspect ratio of the image to the majority of the aspect ratios of loaded images in the current listing provider. Defaults to false. Can be overriden with css variable --image-aspect-ratio
|
|
420
443
|
* @property imgProps props to pass to ShopifyResponsiveImg to add to the <img> element
|
|
421
444
|
*/
|
|
422
445
|
export function ShopifyContainedImage(props: {
|
|
423
446
|
src: string;
|
|
424
447
|
aspectRatio: number | string;
|
|
448
|
+
autoAdjustAspectRatio?: boolean;
|
|
425
449
|
class?: string;
|
|
426
450
|
imgProps?: Omit<Parameters<typeof ShopifyResponsiveImg>[0], "size" | "src">;
|
|
427
451
|
}): HTMLDivElement;
|
|
@@ -489,28 +513,6 @@ interface Styles {
|
|
|
489
513
|
[selector: string]: JSX.CSSProperties;
|
|
490
514
|
}
|
|
491
515
|
export const styles_to_valid_css_string: (styles: Styles) => string;
|
|
492
|
-
type ImagePlaceholderBaseOptions = {
|
|
493
|
-
style?: JSX.CSSProperties;
|
|
494
|
-
class?: string;
|
|
495
|
-
};
|
|
496
|
-
type ImagePlaceholderBlockOptions = {
|
|
497
|
-
width: string;
|
|
498
|
-
height: string;
|
|
499
|
-
};
|
|
500
|
-
type ImagePlaceholderImageOptions = {
|
|
501
|
-
aspectRatio: number | string;
|
|
502
|
-
};
|
|
503
|
-
/**
|
|
504
|
-
* A placeholder that can be used instead of an image or other block of content while it's loading.
|
|
505
|
-
* The placeholder has `display:block`, meaning it will create a new "row" in the layout for itself. Can be used either for images with a defined aspect ratio (ContainedImage) or blocks.
|
|
506
|
-
* @property aspectRatio if aspectRatio is defined the placeholder will be in "image mode" and fill out the available width and then adjust the height according to the aspectRatio
|
|
507
|
-
* @property width If width and height is set, the defined width and height will be used.
|
|
508
|
-
* @property height If width and height is set, the defined width and height will be used.
|
|
509
|
-
* @property class extra classes to add to the placeholder
|
|
510
|
-
* @property style extra styles to add to the placeholder
|
|
511
|
-
*/
|
|
512
|
-
export function ImagePlaceholder(props: ImagePlaceholderBaseOptions & (ImagePlaceholderBlockOptions | ImagePlaceholderImageOptions)): JSX.Element;
|
|
513
|
-
export function DefaultInstantCardPlaceholder(): HTMLDivElement;
|
|
514
516
|
/**
|
|
515
517
|
* Second generation search modal - the solid component that gets added to <body> when the search modal is opened
|
|
516
518
|
*/
|
|
@@ -642,7 +644,7 @@ export type BaseSearchProviderConfig<InputDisplay extends Display, PossibleTrans
|
|
|
642
644
|
*/
|
|
643
645
|
enableContentSearch?: boolean;
|
|
644
646
|
/**
|
|
645
|
-
* The search modal component to use. You can switch between the classic and the new search modal. Provide one of the components here that you can import from the same package as the one you're using to see this message.
|
|
647
|
+
* The search modal component to use. You can switch between the classic and the new search modal. Provide one of the components here that you can import from the same package as the one you're using to see this message (`SearchModalV2` or `ClassicSearchModal`).
|
|
646
648
|
* You also need to reflect the choice in SCSS, example:
|
|
647
649
|
* ```scss
|
|
648
650
|
* @use "@depict-ai/js-ui" as plp-styling with (
|
package/server/latest/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { add_to_version_info as $i7OB2$add_to_version_info, deparallelize_no_drop as $i7OB2$deparallelize_no_drop, catchify as $i7OB2$catchify, make_random_classname as $i7OB2$make_random_classname, ContainedImage as $i7OB2$ContainedImage, standard_price_format as $i7OB2$standard_price_format, javascript_media_query as $i7OB2$javascript_media_query, dlog as $i7OB2$dlog, camelCasifyObject as $i7OB2$camelCasifyObject, make_asyncIterable_exiter as $i7OB2$make_asyncIterable_exiter, href_change_ipns as $i7OB2$href_change_ipns, observer as $i7OB2$observer, report as $i7OB2$report, base64_encode_unicode as $i7OB2$base64_encode_unicode, base64_decode_unicode as $i7OB2$base64_decode_unicode, queueMacroTask as $i7OB2$queueMacroTask, dwarn as $i7OB2$dwarn, slider_fading_factory as $i7OB2$slider_fading_factory, Amazing_Slider as $i7OB2$Amazing_Slider, slider_snap_css as $i7OB2$slider_snap_css, n_col_styling_with_dist as $i7OB2$n_col_styling_with_dist, layout_get_visible_recs_without_partial_rows as $i7OB2$layout_get_visible_recs_without_partial_rows, layout_get_total_rec_amount_for_row as $i7OB2$layout_get_total_rec_amount_for_row, layout_media_query_header as $i7OB2$layout_media_query_header, use_href_accessor as $i7OB2$use_href_accessor, get_session_id as $i7OB2$get_session_id, add_version_query_params as $i7OB2$add_version_query_params, base_url as $i7OB2$base_url, instant_exec_on_suspect_history_change as $i7OB2$instant_exec_on_suspect_history_change, slider_fractional_factory as $i7OB2$slider_fractional_factory, useExpandingContainer as $i7OB2$useExpandingContainer, hex_to_rgb as $i7OB2$hex_to_rgb, relative_luminance_from_rgb as $i7OB2$relative_luminance_from_rgb, snakeCasifyObject as $i7OB2$snakeCasifyObject, fetch_retry as $i7OB2$fetch_retry, sort_obj as $i7OB2$sort_obj, make_url_with_query_params as $i7OB2$make_url_with_query_params,
|
|
1
|
+
import { add_to_version_info as $i7OB2$add_to_version_info, deparallelize_no_drop as $i7OB2$deparallelize_no_drop, catchify as $i7OB2$catchify, make_random_classname as $i7OB2$make_random_classname, ContainedImage as $i7OB2$ContainedImage, standard_price_format as $i7OB2$standard_price_format, javascript_media_query as $i7OB2$javascript_media_query, dlog as $i7OB2$dlog, camelCasifyObject as $i7OB2$camelCasifyObject, make_asyncIterable_exiter as $i7OB2$make_asyncIterable_exiter, href_change_ipns as $i7OB2$href_change_ipns, observer as $i7OB2$observer, report as $i7OB2$report, base64_encode_unicode as $i7OB2$base64_encode_unicode, base64_decode_unicode as $i7OB2$base64_decode_unicode, ListenableSet as $i7OB2$ListenableSet, findMostFrequentItem as $i7OB2$findMostFrequentItem, queueMacroTask as $i7OB2$queueMacroTask, dwarn as $i7OB2$dwarn, slider_fading_factory as $i7OB2$slider_fading_factory, Amazing_Slider as $i7OB2$Amazing_Slider, slider_snap_css as $i7OB2$slider_snap_css, n_col_styling_with_dist as $i7OB2$n_col_styling_with_dist, layout_get_visible_recs_without_partial_rows as $i7OB2$layout_get_visible_recs_without_partial_rows, layout_get_total_rec_amount_for_row as $i7OB2$layout_get_total_rec_amount_for_row, layout_media_query_header as $i7OB2$layout_media_query_header, use_href_accessor as $i7OB2$use_href_accessor, get_session_id as $i7OB2$get_session_id, add_version_query_params as $i7OB2$add_version_query_params, base_url as $i7OB2$base_url, instant_exec_on_suspect_history_change as $i7OB2$instant_exec_on_suspect_history_change, slider_fractional_factory as $i7OB2$slider_fractional_factory, useExpandingContainer as $i7OB2$useExpandingContainer, hex_to_rgb as $i7OB2$hex_to_rgb, relative_luminance_from_rgb as $i7OB2$relative_luminance_from_rgb, snakeCasifyObject as $i7OB2$snakeCasifyObject, fetch_retry as $i7OB2$fetch_retry, sort_obj as $i7OB2$sort_obj, make_url_with_query_params as $i7OB2$make_url_with_query_params, insert_surfaces as $i7OB2$insert_surfaces } from "@depict-ai/utilishared/latest";
|
|
2
2
|
import { createSignal as $i7OB2$createSignal, createResource as $i7OB2$createResource, createEffect as $i7OB2$createEffect, untrack as $i7OB2$untrack, createMemo as $i7OB2$createMemo, onCleanup as $i7OB2$onCleanup, Show as $i7OB2$Show, createComputed as $i7OB2$createComputed, For as $i7OB2$For, getOwner as $i7OB2$getOwner, runWithOwner as $i7OB2$runWithOwner, on as $i7OB2$on, Index as $i7OB2$Index, batch as $i7OB2$batch, ErrorBoundary as $i7OB2$ErrorBoundary, createContext as $i7OB2$createContext, useContext as $i7OB2$useContext, mergeProps as $i7OB2$mergeProps1, createUniqueId as $i7OB2$createUniqueId, createRenderEffect as $i7OB2$createRenderEffect, createSelector as $i7OB2$createSelector, children as $i7OB2$children, splitProps as $i7OB2$splitProps, createRoot as $i7OB2$createRoot, Suspense as $i7OB2$Suspense, createReaction as $i7OB2$createReaction, mapArray as $i7OB2$mapArray } from "solid-js";
|
|
3
3
|
import { ssr as $i7OB2$ssr, ssrHydrationKey as $i7OB2$ssrHydrationKey, escape as $i7OB2$escape, createComponent as $i7OB2$createComponent, ssrAttribute as $i7OB2$ssrAttribute, ssrClassList as $i7OB2$ssrClassList, ssrStyle as $i7OB2$ssrStyle, ssrElement as $i7OB2$ssrElement, mergeProps as $i7OB2$mergeProps, insert as $i7OB2$insert, spread as $i7OB2$spread, isServer as $i7OB2$isServer, Dynamic as $i7OB2$Dynamic } from "solid-js/web";
|
|
4
|
-
import { ListenableSet as $i7OB2$
|
|
4
|
+
import { ListenableSet as $i7OB2$ListenableSet1, catchify as $i7OB2$catchify1, use_href_accessor as $i7OB2$use_href_accessor1, report as $i7OB2$report1 } from "@depict-ai/utilishared/latest";
|
|
5
5
|
import { createStore as $i7OB2$createStore, reconcile as $i7OB2$reconcile } from "solid-js/store";
|
|
6
6
|
|
|
7
7
|
/*! Depict.ai search and product listing SDK */
|
|
8
8
|
import { register_es_version } from "../../multi_import_deduplicator.mjs";
|
|
9
9
|
register_es_version("ui", "latest");
|
|
10
|
-
const $ec291e0010116877$export$83d89fbfd8236492 = "4.0.
|
|
10
|
+
const $ec291e0010116877$export$83d89fbfd8236492 = "4.0.2";
|
|
11
11
|
function $136f1d4d6c7ba6ac$export$e417c49320921907(dependency, fetcher) {
|
|
12
12
|
const [promiseOfCurrentFetcherRun, setPromiseOfCurrentFetcherRun] = $i7OB2$createSignal();
|
|
13
13
|
const deparallelizedFetcher = $i7OB2$deparallelize_no_drop(async dependencyValue => {
|
|
@@ -1785,6 +1785,7 @@ function $e8ffe11ed01df0fe$export$e6fffe67d4cdd848(whatToWatch) {
|
|
|
1785
1785
|
return size;
|
|
1786
1786
|
}
|
|
1787
1787
|
const $e8ffe11ed01df0fe$var$onIdleFunctionsSymbol = /*@__PURE__*/Symbol("onIdleFunctions");
|
|
1788
|
+
const $e8ffe11ed01df0fe$export$f8945274f08a3105 = /*@__PURE__*/Symbol("listingContextAspectRatios");
|
|
1788
1789
|
function $e8ffe11ed01df0fe$export$6e5611bc7e57e477(props) {
|
|
1789
1790
|
// Enable reactive props
|
|
1790
1791
|
const otherOptions = $i7OB2$createMemo(() => {
|
|
@@ -1849,6 +1850,21 @@ function $e8ffe11ed01df0fe$export$6e5611bc7e57e477(props) {
|
|
|
1849
1850
|
let timeoutSet = false;
|
|
1850
1851
|
let gotCleanedUp = false;
|
|
1851
1852
|
img.classList.add("s-responsive-image");
|
|
1853
|
+
if (listingContext) {
|
|
1854
|
+
let prevValue;
|
|
1855
|
+
const aspectRatios = listingContext[$e8ffe11ed01df0fe$export$f8945274f08a3105] ||= new (0, $i7OB2$ListenableSet)();
|
|
1856
|
+
img.addEventListener("load", $i7OB2$catchify(() => {
|
|
1857
|
+
// Save our aspect ratio whenever it changes, so that we can base the containers on the most dominant aspect ratio, used in SearchModalV2
|
|
1858
|
+
const aspectRatio_ = img.naturalWidth / img.naturalHeight;
|
|
1859
|
+
if (prevValue) aspectRatios.delete(prevValue);
|
|
1860
|
+
const newValue = !isNaN(aspectRatio_) ? {
|
|
1861
|
+
aspectRatio_: aspectRatio_
|
|
1862
|
+
} : undefined;
|
|
1863
|
+
if (newValue) aspectRatios.add(newValue);
|
|
1864
|
+
prevValue = newValue;
|
|
1865
|
+
}));
|
|
1866
|
+
$i7OB2$onCleanup(() => prevValue && aspectRatios.delete(prevValue));
|
|
1867
|
+
}
|
|
1852
1868
|
$i7OB2$onCleanup(() => gotCleanedUp = true);
|
|
1853
1869
|
$i7OB2$spread(img, $i7OB2$mergeProps1(otherOptions), false, true);
|
|
1854
1870
|
$i7OB2$createEffect(() => {
|
|
@@ -1916,9 +1932,28 @@ function $660070e2a394b3c3$export$e4b984597b71e989(props) {
|
|
|
1916
1932
|
// create a signal that's the same for all items in this listing
|
|
1917
1933
|
context[$660070e2a394b3c3$export$d7b7ab832c20e2f4] = $i7OB2$createSignal();
|
|
1918
1934
|
const [currentImageSize, setCurrentImageSize] = context?.[$660070e2a394b3c3$export$d7b7ab832c20e2f4] || $660070e2a394b3c3$var$backupSizeSignal; // use global fallback signal (might lead to blurry images) if no context is available
|
|
1935
|
+
const aspectRatiosSet = context ?
|
|
1936
|
+
// If the context exists we have to create the set here as getting it here would be too late when it's created by ShopifyResponsiveImg below
|
|
1937
|
+
context[(0, $e8ffe11ed01df0fe$export$f8945274f08a3105)] ||= new (0, $i7OB2$ListenableSet)() : undefined;
|
|
1938
|
+
const [aspectRatios, setAspectRatios] = $i7OB2$createSignal(aspectRatiosSet, {
|
|
1939
|
+
equals: false
|
|
1940
|
+
});
|
|
1941
|
+
const aspectRatioToUse = $i7OB2$createMemo(() => {
|
|
1942
|
+
const aspectRatiosSet = aspectRatios(); // This signal "changes" to the same set every time the set changes, so we can use it as a dependency here
|
|
1943
|
+
useMostPrevalentAspectRatio: {
|
|
1944
|
+
if (!aspectRatiosSet || !props.autoAdjustAspectRatio) break useMostPrevalentAspectRatio;
|
|
1945
|
+
// Get the aspect ratio that most of the loaded images inside the ListingProvider we are, load
|
|
1946
|
+
const asArray = [...aspectRatiosSet].map(({
|
|
1947
|
+
aspectRatio_: aspectRatio_
|
|
1948
|
+
}) => aspectRatio_);
|
|
1949
|
+
const mostPrevalentAspectRatio = $i7OB2$findMostFrequentItem(asArray);
|
|
1950
|
+
if (mostPrevalentAspectRatio) return `var(${(0, $bb15dfb548a7666e$export$8a2234b5b1a5ebd4)}, ${mostPrevalentAspectRatio})`;
|
|
1951
|
+
}
|
|
1952
|
+
return props.aspectRatio;
|
|
1953
|
+
});
|
|
1919
1954
|
const container = $i7OB2$createComponent((0, $f18d425032111270$export$94026ee33dbabc26), {
|
|
1920
1955
|
get aspectRatio() {
|
|
1921
|
-
return
|
|
1956
|
+
return aspectRatioToUse();
|
|
1922
1957
|
},
|
|
1923
1958
|
get ["class"]() {
|
|
1924
1959
|
return props.class;
|
|
@@ -1927,6 +1962,10 @@ function $660070e2a394b3c3$export$e4b984597b71e989(props) {
|
|
|
1927
1962
|
const owner = $i7OB2$getOwner();
|
|
1928
1963
|
let createdSizeAccessor = false;
|
|
1929
1964
|
let wasCleanedUp = false;
|
|
1965
|
+
for (const event of ["add", "delete"]) {
|
|
1966
|
+
aspectRatiosSet?.addEventListener(event, () => setAspectRatios(aspectRatiosSet));
|
|
1967
|
+
$i7OB2$onCleanup(() => aspectRatiosSet?.removeEventListener(event, () => setAspectRatios(aspectRatiosSet)));
|
|
1968
|
+
}
|
|
1930
1969
|
$i7OB2$createEffect(() => {
|
|
1931
1970
|
if (currentImageSize() || wasCleanedUp) return; // We get into the effect when onCleanup is called if we don't have wasCleanedUp
|
|
1932
1971
|
// ensure we always have a size accessor
|
|
@@ -2756,7 +2795,8 @@ function $500a16dd18ee5a71$var$RawSearchModalV2({
|
|
|
2756
2795
|
get src() {
|
|
2757
2796
|
return props.src_;
|
|
2758
2797
|
},
|
|
2759
|
-
|
|
2798
|
+
autoAdjustAspectRatio: true,
|
|
2799
|
+
aspectRatio: 1
|
|
2760
2800
|
}),
|
|
2761
2801
|
...instant_results_options_
|
|
2762
2802
|
})));
|
|
@@ -2831,7 +2871,7 @@ const $024fbc0a2d796fad$var$TabsContext = /*@__PURE__*/$i7OB2$createContext();
|
|
|
2831
2871
|
const $024fbc0a2d796fad$var$useTabs = () => $i7OB2$useContext($024fbc0a2d796fad$var$TabsContext);
|
|
2832
2872
|
function $024fbc0a2d796fad$export$b2539bed5023c21c(props) {
|
|
2833
2873
|
return $i7OB2$createComponent($024fbc0a2d796fad$var$TabsContext.Provider, {
|
|
2834
|
-
value: new (0, $i7OB2$
|
|
2874
|
+
value: new (0, $i7OB2$ListenableSet1)(),
|
|
2835
2875
|
get children() {
|
|
2836
2876
|
return $i7OB2$createComponent($024fbc0a2d796fad$var$ActualTabs, $i7OB2$mergeProps(props, {
|
|
2837
2877
|
get children() {
|
|
@@ -2968,7 +3008,15 @@ async function $194bd6b8e4c59830$export$79b1565500412d9b(search_modal, modal_fn_
|
|
|
2968
3008
|
const actually_close = () => {
|
|
2969
3009
|
dispose();
|
|
2970
3010
|
on_dispose?.();
|
|
2971
|
-
|
|
3011
|
+
const {
|
|
3012
|
+
activeElement: activeElement
|
|
3013
|
+
} = document;
|
|
3014
|
+
modal_els.forEach(el => {
|
|
3015
|
+
if (el.contains(activeElement))
|
|
3016
|
+
// Fix page jumping to the bottom when closing modal with scape after animation in safari
|
|
3017
|
+
activeElement?.blur?.();
|
|
3018
|
+
el.remove();
|
|
3019
|
+
});
|
|
2972
3020
|
};
|
|
2973
3021
|
if (animation_started && +new Date() - animation_started > 1000)
|
|
2974
3022
|
// Animation broke, close it this time
|
|
@@ -10147,7 +10195,7 @@ function $49de9d31aeea1b5e$export$6d0c9c22f6652669({
|
|
|
10147
10195
|
number_: num_results,
|
|
10148
10196
|
i18n_: i18n_
|
|
10149
10197
|
});
|
|
10150
|
-
const queries_without_content_results_ = new (0, $i7OB2$
|
|
10198
|
+
const queries_without_content_results_ = new (0, $i7OB2$ListenableSet)();
|
|
10151
10199
|
const [check_query, set_check_query] = $i7OB2$createSignal(false);
|
|
10152
10200
|
const placeholders_enabled = $i7OB2$createMemo(() => {
|
|
10153
10201
|
// don't show placeholders when the user toggles filters
|
|
@@ -10225,30 +10273,37 @@ function $0e562a5b247b1fc2$export$44f738469d5570cf({
|
|
|
10225
10273
|
modalSearchFieldOuterWidth_: modalSearchFieldOuterWidth_
|
|
10226
10274
|
}) {
|
|
10227
10275
|
return $i7OB2$createRoot(dispose => {
|
|
10276
|
+
const [innerWidthReactive, setInnerWidthReactive] = $i7OB2$createSignal(innerWidth);
|
|
10277
|
+
const resizeObserver = new ResizeObserver(records => setInnerWidthReactive(records.at(-1).contentRect.width));
|
|
10278
|
+
const {
|
|
10279
|
+
left: left,
|
|
10280
|
+
top: top,
|
|
10281
|
+
width: width
|
|
10282
|
+
} = actualField_.getBoundingClientRect();
|
|
10228
10283
|
const fakeField = makeFakeField_();
|
|
10229
10284
|
const owner = $i7OB2$getOwner();
|
|
10230
10285
|
const inModalFieldWidth = $i7OB2$createMemo(
|
|
10231
10286
|
// Can't have `min(${modalSearchFieldOuterWidth_()}px, var(--field-max-width, 600px))` because the WAAPI doesn't support that, so we need ot calculate it in JS
|
|
10232
|
-
() => Math.min(modalSearchFieldOuterWidth_(), parseFloat(getComputedStyle(actualField_).getPropertyValue("--field-max-width") || "600"))
|
|
10287
|
+
() => Math.min(modalSearchFieldOuterWidth_(), parseFloat(getComputedStyle(actualField_).getPropertyValue("--field-max-width") || "600")));
|
|
10288
|
+
const inModalFieldWidthPx = $i7OB2$createMemo(() => inModalFieldWidth() + "px");
|
|
10289
|
+
let disableResizePollingTimeout;
|
|
10290
|
+
resizeObserver.observe(document.documentElement);
|
|
10291
|
+
$i7OB2$onCleanup(() => resizeObserver.disconnect());
|
|
10233
10292
|
actualField_.replaceWith(fakeField);
|
|
10234
10293
|
// Don't move the wrapped div since that would confuse run_in_root_or_auto_cleanup, but do actually move the field the user clicked around so that all selection stuff etc. is easier
|
|
10235
10294
|
const addedToBody = wrap_ ? $i7OB2$ssr($0e562a5b247b1fc2$var$_tmpl$, $i7OB2$ssrHydrationKey(), $i7OB2$escape(actualField_)) : actualField_;
|
|
10236
10295
|
document.body.append(addedToBody);
|
|
10237
|
-
const {
|
|
10238
|
-
left: left,
|
|
10239
|
-
top: top,
|
|
10240
|
-
width: width
|
|
10241
|
-
} = fakeField.getBoundingClientRect();
|
|
10242
10296
|
const zIndexOfFake = getComputedStyle(fakeField).zIndex;
|
|
10243
10297
|
Object.assign(addedToBody.style, {
|
|
10244
10298
|
position: "fixed",
|
|
10245
10299
|
top: top + "px",
|
|
10300
|
+
left: left + "px",
|
|
10246
10301
|
width: width + "px",
|
|
10247
10302
|
...(zIndexOfFake !== "auto" ? {
|
|
10248
10303
|
zIndex: +zIndexOfFake + 1
|
|
10249
10304
|
} : {})
|
|
10250
10305
|
});
|
|
10251
|
-
const pxOffCenter =
|
|
10306
|
+
const pxOffCenter = $i7OB2$untrack(innerWidthReactive) / 2 - (left + width / 2);
|
|
10252
10307
|
const openDuration = pxOffCenter > 100 ? 250 : 125; // faster animations if little left-right movement
|
|
10253
10308
|
const closeDuration = pxOffCenter > 100 ? 150 : 100;
|
|
10254
10309
|
setPollAlignment_(true);
|
|
@@ -10267,24 +10322,30 @@ function $0e562a5b247b1fc2$export$44f738469d5570cf({
|
|
|
10267
10322
|
// Wait until the ResizeObserver has delivered a value in case that the modal is small or has much padding so we know that we can't animate our fake field to be wider than that
|
|
10268
10323
|
addedToBody.animate([{
|
|
10269
10324
|
left: left + "px",
|
|
10270
|
-
transform: "translateX(0%)",
|
|
10271
10325
|
width: width + "px"
|
|
10272
10326
|
}, {
|
|
10273
|
-
left:
|
|
10274
|
-
|
|
10275
|
-
width: $i7OB2$untrack(inModalFieldWidth)
|
|
10327
|
+
left: `${$i7OB2$untrack(innerWidthReactive) / 2 - $i7OB2$untrack(inModalFieldWidth) / 2}px`,
|
|
10328
|
+
width: $i7OB2$untrack(inModalFieldWidthPx)
|
|
10276
10329
|
}], {
|
|
10277
10330
|
duration: openDuration,
|
|
10278
10331
|
easing: "ease-in"
|
|
10279
10332
|
}).finished.then(() => {
|
|
10280
10333
|
setPollAlignment_(false);
|
|
10281
|
-
$i7OB2$runWithOwner(owner, () => $i7OB2$createEffect(() =>
|
|
10282
|
-
|
|
10283
|
-
|
|
10284
|
-
|
|
10285
|
-
|
|
10286
|
-
|
|
10287
|
-
|
|
10334
|
+
$i7OB2$runWithOwner(owner, () => $i7OB2$createEffect(() => {
|
|
10335
|
+
// When animation has finished, still dynamically set the size of the search field behind in case the user resizes the window
|
|
10336
|
+
Object.assign(addedToBody.style, {
|
|
10337
|
+
// This is left: 50%, transform: translateX(-50) with extra steps but when using it safari and firefox glitch out like crazy
|
|
10338
|
+
left: `${innerWidthReactive() / 2 - inModalFieldWidth() / 2}px`,
|
|
10339
|
+
width: inModalFieldWidthPx()
|
|
10340
|
+
});
|
|
10341
|
+
// We might only have changed the left position which align_field doesn't know about, make it poll the position for a while
|
|
10342
|
+
setPollAlignment_(true);
|
|
10343
|
+
if (disableResizePollingTimeout) clearTimeout(disableResizePollingTimeout);
|
|
10344
|
+
disableResizePollingTimeout = setTimeout($i7OB2$catchify(() => {
|
|
10345
|
+
setPollAlignment_(false);
|
|
10346
|
+
disableResizePollingTimeout = undefined;
|
|
10347
|
+
}), 1000);
|
|
10348
|
+
}));
|
|
10288
10349
|
});
|
|
10289
10350
|
return true;
|
|
10290
10351
|
}, false);
|
|
@@ -10327,13 +10388,11 @@ function $0e562a5b247b1fc2$export$44f738469d5570cf({
|
|
|
10327
10388
|
transition: `opacity ${closeDuration}ms ease-out`
|
|
10328
10389
|
}));
|
|
10329
10390
|
await Promise.all([addedToBody.animate([{
|
|
10330
|
-
width: $i7OB2$untrack(
|
|
10331
|
-
left:
|
|
10332
|
-
transform: "translateX(-50%)"
|
|
10391
|
+
width: $i7OB2$untrack(inModalFieldWidthPx),
|
|
10392
|
+
left: `${$i7OB2$untrack(innerWidthReactive) / 2 - $i7OB2$untrack(inModalFieldWidth) / 2}px`
|
|
10333
10393
|
}, {
|
|
10334
10394
|
width: width + "px",
|
|
10335
|
-
left: left + "px"
|
|
10336
|
-
transform: "translateX(0%)"
|
|
10395
|
+
left: left + "px"
|
|
10337
10396
|
}], {
|
|
10338
10397
|
duration: closeDuration,
|
|
10339
10398
|
fill: "forwards",
|