@timmbr/ui 1.8.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Breadcrumb/Breadcrumb.d.ts +9 -0
- package/dist/components/Breadcrumb/Breadcrumb.d.ts.map +1 -0
- package/dist/components/Breadcrumb/Breadcrumb.js +32 -0
- package/dist/components/Breadcrumb/Breadcrumb.styles.d.ts +8 -0
- package/dist/components/Breadcrumb/Breadcrumb.styles.d.ts.map +1 -0
- package/dist/components/Breadcrumb/Breadcrumb.styles.js +20 -0
- package/dist/components/Breadcrumb/Breadcrumb.types.d.ts +27 -0
- package/dist/components/Breadcrumb/Breadcrumb.types.d.ts.map +1 -0
- package/dist/components/Breadcrumb/index.d.ts +4 -0
- package/dist/components/Breadcrumb/index.d.ts.map +1 -0
- package/dist/components/Chip/Chip.d.ts.map +1 -1
- package/dist/components/Chip/Chip.js +13 -3
- package/dist/components/Chip/Chip.types.d.ts +5 -0
- package/dist/components/Chip/Chip.types.d.ts.map +1 -1
- package/dist/components/Drawer/Drawer.d.ts.map +1 -1
- package/dist/components/Drawer/Drawer.js +4 -4
- package/dist/components/Drawer/Drawer.styles.d.ts +1 -0
- package/dist/components/Drawer/Drawer.styles.d.ts.map +1 -1
- package/dist/components/Drawer/Drawer.styles.js +7 -1
- package/dist/components/Drawer/Drawer.types.d.ts +2 -0
- package/dist/components/Drawer/Drawer.types.d.ts.map +1 -1
- package/dist/components/FilterChips/FilterChips.d.ts +8 -0
- package/dist/components/FilterChips/FilterChips.d.ts.map +1 -0
- package/dist/components/FilterChips/FilterChips.js +39 -0
- package/dist/components/FilterChips/FilterChips.types.d.ts +17 -0
- package/dist/components/FilterChips/FilterChips.types.d.ts.map +1 -0
- package/dist/components/FilterChips/index.d.ts +3 -0
- package/dist/components/FilterChips/index.d.ts.map +1 -0
- package/dist/components/FilterDrawer/FilterDrawer.d.ts +12 -0
- package/dist/components/FilterDrawer/FilterDrawer.d.ts.map +1 -0
- package/dist/components/FilterDrawer/FilterDrawer.js +157 -0
- package/dist/components/FilterDrawer/FilterDrawer.styles.d.ts +12 -0
- package/dist/components/FilterDrawer/FilterDrawer.styles.d.ts.map +1 -0
- package/dist/components/FilterDrawer/FilterDrawer.styles.js +30 -0
- package/dist/components/FilterDrawer/FilterDrawer.types.d.ts +28 -0
- package/dist/components/FilterDrawer/FilterDrawer.types.d.ts.map +1 -0
- package/dist/components/FilterDrawer/index.d.ts +4 -0
- package/dist/components/FilterDrawer/index.d.ts.map +1 -0
- package/dist/components/FilterPanel/FilterPanel.d.ts +33 -0
- package/dist/components/FilterPanel/FilterPanel.d.ts.map +1 -0
- package/dist/components/FilterPanel/FilterPanel.js +239 -0
- package/dist/components/FilterPanel/FilterPanel.styles.d.ts +16 -0
- package/dist/components/FilterPanel/FilterPanel.styles.d.ts.map +1 -0
- package/dist/components/FilterPanel/FilterPanel.styles.js +31 -0
- package/dist/components/FilterPanel/FilterPanel.types.d.ts +80 -0
- package/dist/components/FilterPanel/FilterPanel.types.d.ts.map +1 -0
- package/dist/components/FilterPanel/FilterPanel.types.js +3 -0
- package/dist/components/FilterPanel/index.d.ts +4 -0
- package/dist/components/FilterPanel/index.d.ts.map +1 -0
- package/dist/components/ImageUpload/ImageUpload.styles.d.ts +3 -3
- package/dist/components/MediaCard/MediaCard.d.ts.map +1 -1
- package/dist/components/MediaCard/MediaCard.js +3 -1
- package/dist/components/NavHeader/NavHeader.styles.d.ts +7 -0
- package/dist/components/NavHeader/NavHeader.styles.d.ts.map +1 -1
- package/dist/components/NavHeader/NavHeader.styles.js +20 -2
- package/dist/components/NavHeader/NavHeader.types.d.ts +49 -1
- package/dist/components/NavHeader/NavHeader.types.d.ts.map +1 -1
- package/dist/components/NavHeader/index.d.ts +3 -2
- package/dist/components/NavHeader/index.d.ts.map +1 -1
- package/dist/components/NavHeader/subcomponents/NavMobileSearchDrawer.d.ts.map +1 -1
- package/dist/components/NavHeader/subcomponents/NavMobileSearchDrawer.js +15 -33
- package/dist/components/NavHeader/subcomponents/NavSearch.d.ts.map +1 -1
- package/dist/components/NavHeader/subcomponents/NavSearch.js +37 -83
- package/dist/components/NavHeader/subcomponents/NavSearchPanel.d.ts +63 -0
- package/dist/components/NavHeader/subcomponents/NavSearchPanel.d.ts.map +1 -0
- package/dist/components/NavHeader/subcomponents/NavSearchPanel.js +289 -0
- package/dist/components/NavMenuColumns/NavMenuColumns.d.ts +8 -1
- package/dist/components/NavMenuColumns/NavMenuColumns.d.ts.map +1 -1
- package/dist/components/NavMenuColumns/NavMenuColumns.js +27 -1
- package/dist/components/NavMenuColumns/NavMenuColumns.styles.js +1 -1
- package/dist/components/NavMenuColumns/NavMenuColumns.types.d.ts +18 -0
- package/dist/components/NavMenuColumns/NavMenuColumns.types.d.ts.map +1 -1
- package/dist/components/OptionPicker/OptionPicker.d.ts +10 -0
- package/dist/components/OptionPicker/OptionPicker.d.ts.map +1 -0
- package/dist/components/OptionPicker/OptionPicker.js +116 -0
- package/dist/components/OptionPicker/OptionPicker.styles.d.ts +20 -0
- package/dist/components/OptionPicker/OptionPicker.styles.d.ts.map +1 -0
- package/dist/components/OptionPicker/OptionPicker.styles.js +60 -0
- package/dist/components/OptionPicker/OptionPicker.types.d.ts +39 -0
- package/dist/components/OptionPicker/OptionPicker.types.d.ts.map +1 -0
- package/dist/components/OptionPicker/index.d.ts +4 -0
- package/dist/components/OptionPicker/index.d.ts.map +1 -0
- package/dist/components/Price/Price.styles.d.ts.map +1 -1
- package/dist/components/Price/Price.styles.js +3 -2
- package/dist/components/ProductGallery/ProductGallery.d.ts +10 -0
- package/dist/components/ProductGallery/ProductGallery.d.ts.map +1 -0
- package/dist/components/ProductGallery/ProductGallery.js +306 -0
- package/dist/components/ProductGallery/ProductGallery.styles.d.ts +32 -0
- package/dist/components/ProductGallery/ProductGallery.styles.d.ts.map +1 -0
- package/dist/components/ProductGallery/ProductGallery.styles.js +86 -0
- package/dist/components/ProductGallery/ProductGallery.types.d.ts +55 -0
- package/dist/components/ProductGallery/ProductGallery.types.d.ts.map +1 -0
- package/dist/components/ProductGallery/ProductGalleryLightbox.d.ts +20 -0
- package/dist/components/ProductGallery/ProductGalleryLightbox.d.ts.map +1 -0
- package/dist/components/ProductGallery/ProductGalleryLightbox.js +210 -0
- package/dist/components/ProductGallery/index.d.ts +4 -0
- package/dist/components/ProductGallery/index.d.ts.map +1 -0
- package/dist/components/QuantityStepper/QuantityStepper.d.ts +8 -0
- package/dist/components/QuantityStepper/QuantityStepper.d.ts.map +1 -0
- package/dist/components/QuantityStepper/QuantityStepper.js +65 -0
- package/dist/components/QuantityStepper/QuantityStepper.styles.d.ts +8 -0
- package/dist/components/QuantityStepper/QuantityStepper.styles.d.ts.map +1 -0
- package/dist/components/QuantityStepper/QuantityStepper.styles.js +24 -0
- package/dist/components/QuantityStepper/QuantityStepper.types.d.ts +20 -0
- package/dist/components/QuantityStepper/QuantityStepper.types.d.ts.map +1 -0
- package/dist/components/QuantityStepper/index.d.ts +4 -0
- package/dist/components/QuantityStepper/index.d.ts.map +1 -0
- package/dist/components/RangeSlider/RangeSlider.d.ts.map +1 -1
- package/dist/components/RangeSlider/RangeSlider.js +5 -3
- package/dist/components/RangeSlider/RangeSlider.types.d.ts +7 -0
- package/dist/components/RangeSlider/RangeSlider.types.d.ts.map +1 -1
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Select/Select.js +14 -1
- package/dist/components/Select/Select.types.d.ts +4 -0
- package/dist/components/Select/Select.types.d.ts.map +1 -1
- package/dist/components/Snackbar/Snackbar.d.ts +9 -0
- package/dist/components/Snackbar/Snackbar.d.ts.map +1 -0
- package/dist/components/Snackbar/Snackbar.js +108 -0
- package/dist/components/Snackbar/Snackbar.styles.d.ts +17 -0
- package/dist/components/Snackbar/Snackbar.styles.d.ts.map +1 -0
- package/dist/components/Snackbar/Snackbar.styles.js +37 -0
- package/dist/components/Snackbar/Snackbar.types.d.ts +36 -0
- package/dist/components/Snackbar/Snackbar.types.d.ts.map +1 -0
- package/dist/components/Snackbar/SnackbarHost.d.ts +4 -0
- package/dist/components/Snackbar/SnackbarHost.d.ts.map +1 -0
- package/dist/components/Snackbar/SnackbarHost.js +24 -0
- package/dist/components/Snackbar/index.d.ts +6 -0
- package/dist/components/Snackbar/index.d.ts.map +1 -0
- package/dist/components/Snackbar/snackbarStore.d.ts +42 -0
- package/dist/components/Snackbar/snackbarStore.d.ts.map +1 -0
- package/dist/components/Snackbar/snackbarStore.js +87 -0
- package/dist/components/StockMeter/StockMeter.d.ts +8 -0
- package/dist/components/StockMeter/StockMeter.d.ts.map +1 -0
- package/dist/components/StockMeter/StockMeter.js +19 -0
- package/dist/components/StockMeter/StockMeter.styles.d.ts +4 -0
- package/dist/components/StockMeter/StockMeter.styles.d.ts.map +1 -0
- package/dist/components/StockMeter/StockMeter.styles.js +7 -0
- package/dist/components/StockMeter/StockMeter.types.d.ts +10 -0
- package/dist/components/StockMeter/StockMeter.types.d.ts.map +1 -0
- package/dist/components/StockMeter/index.d.ts +4 -0
- package/dist/components/StockMeter/index.d.ts.map +1 -0
- package/dist/components/Swatch/Swatch.d.ts +11 -0
- package/dist/components/Swatch/Swatch.d.ts.map +1 -0
- package/dist/components/Swatch/Swatch.js +40 -0
- package/dist/components/Swatch/Swatch.styles.d.ts +8 -0
- package/dist/components/Swatch/Swatch.styles.d.ts.map +1 -0
- package/dist/components/Swatch/Swatch.styles.js +26 -0
- package/dist/components/Swatch/Swatch.types.d.ts +11 -0
- package/dist/components/Swatch/Swatch.types.d.ts.map +1 -0
- package/dist/components/Swatch/index.d.ts +4 -0
- package/dist/components/Swatch/index.d.ts.map +1 -0
- package/dist/components/Toast/Toast.d.ts.map +1 -1
- package/dist/components/Toast/Toast.js +49 -42
- package/dist/components/Toast/Toast.types.d.ts +7 -0
- package/dist/components/Toast/Toast.types.d.ts.map +1 -1
- package/dist/components/Toast/ToastContainer.d.ts.map +1 -1
- package/dist/components/Toast/ToastContainer.js +5 -0
- package/dist/components/Toast/toastStore.d.ts +11 -0
- package/dist/components/Toast/toastStore.d.ts.map +1 -1
- package/dist/components/Toast/toastStore.js +70 -30
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -2
- package/dist/providers/TimmbrConfigProvider.d.ts.map +1 -1
- package/dist/providers/TimmbrConfigProvider.js +5 -9
- package/package.json +6 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OptionPicker.types.d.ts","sourceRoot":"","sources":["../../../src/components/OptionPicker/OptionPicker.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,cAAc,GAAG,aAAa,CAAC;AAE7E,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0FAA0F;IAC1F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IAC/F,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;OAGG;IACH,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;IACtC,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/OptionPicker/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Price.styles.d.ts","sourceRoot":"","sources":["../../../src/components/Price/Price.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAElE,eAAO,MAAM,aAAa;;8EASxB,CAAC;AAEH,eAAO,MAAM,mBAAmB;;8EAS9B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;8EAS/B,CAAC;AAEH,eAAO,MAAM,qBAAqB;;
|
|
1
|
+
{"version":3,"file":"Price.styles.d.ts","sourceRoot":"","sources":["../../../src/components/Price/Price.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAElE,eAAO,MAAM,aAAa;;8EASxB,CAAC;AAEH,eAAO,MAAM,mBAAmB;;8EAS9B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;8EAS/B,CAAC;AAEH,eAAO,MAAM,qBAAqB;;8EAUhC,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC"}
|
|
@@ -4,7 +4,7 @@ const priceVariants = cva("inline-flex flex-wrap items-baseline font-sans text-f
|
|
|
4
4
|
variants: {
|
|
5
5
|
size: {
|
|
6
6
|
sm: "gap-x-1.5",
|
|
7
|
-
md: "gap-x-1",
|
|
7
|
+
md: "gap-x-1.5",
|
|
8
8
|
lg: "gap-x-2"
|
|
9
9
|
}
|
|
10
10
|
},
|
|
@@ -34,7 +34,8 @@ const priceDiscountVariants = cva("font-semibold text-success", {
|
|
|
34
34
|
variants: {
|
|
35
35
|
size: {
|
|
36
36
|
sm: "text-body-3",
|
|
37
|
-
|
|
37
|
+
// No own margin: the row gap spaces it, and it starts flush left when it wraps.
|
|
38
|
+
md: "text-body-2",
|
|
38
39
|
lg: "text-body-1"
|
|
39
40
|
}
|
|
40
41
|
},
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { ProductGalleryProps } from './ProductGallery.types';
|
|
3
|
+
/**
|
|
4
|
+
* Product images: a main image you can swipe (scroll-snap) or step with arrows, a thumbnail row
|
|
5
|
+
* (visible on phones too: easier to aim than dots), and a fullscreen zoomable viewer when the main
|
|
6
|
+
* image is clicked. The first image is marked high priority (it's usually the page's LCP), the
|
|
7
|
+
* rest load lazily; the frame keeps its aspect ratio, so nothing shifts while images load.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ProductGallery: React.ForwardRefExoticComponent<ProductGalleryProps & React.RefAttributes<HTMLDivElement>>;
|
|
10
|
+
//# sourceMappingURL=ProductGallery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProductGallery.d.ts","sourceRoot":"","sources":["../../../src/components/ProductGallery/ProductGallery.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAmB/B,OAAO,KAAK,EAAE,mBAAmB,EAAoD,MAAM,wBAAwB,CAAC;AAoBpH;;;;;GAKG;AACH,eAAO,MAAM,cAAc,4FAkS1B,CAAC"}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { ChevronLeft, ChevronRight } from '@timmbr/icons';
|
|
5
|
+
import { useControllableState } from '@timmbr/hooks';
|
|
6
|
+
import { cn } from '@timmbr/utils';
|
|
7
|
+
import { productGalleryFrameVariants, productGallerySlideVariants, productGalleryTrackVariants, productGalleryArrowVariants, productGalleryCounterVariants, productGalleryLensVariants, productGalleryZoomPaneVariants, productGalleryStageVariants, productGalleryThumbVariants, productGalleryThumbListVariants, productGalleryThumbsVariants, productGalleryVariants } from './ProductGallery.styles.js';
|
|
8
|
+
import { ProductGalleryLightbox } from './ProductGalleryLightbox.js';
|
|
9
|
+
|
|
10
|
+
const SCROLL_SETTLE_MS = 120;
|
|
11
|
+
const defaultRenderImage = (image, { priority, className }) => /* @__PURE__ */ jsx(
|
|
12
|
+
"img",
|
|
13
|
+
{
|
|
14
|
+
src: image.src,
|
|
15
|
+
alt: image.alt,
|
|
16
|
+
loading: priority ? "eager" : "lazy",
|
|
17
|
+
fetchPriority: priority ? "high" : void 0,
|
|
18
|
+
decoding: "async",
|
|
19
|
+
draggable: false,
|
|
20
|
+
className: cn("absolute inset-0 size-full object-cover", className)
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
const prefersReducedMotion = () => typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
24
|
+
const ProductGallery = React.forwardRef(
|
|
25
|
+
({
|
|
26
|
+
images,
|
|
27
|
+
index: indexProp,
|
|
28
|
+
defaultIndex = 0,
|
|
29
|
+
onIndexChange,
|
|
30
|
+
renderImage = defaultRenderImage,
|
|
31
|
+
aspectRatio = "4 / 3",
|
|
32
|
+
sizes = "(min-width: 1024px) 50vw, 100vw",
|
|
33
|
+
thumbnails = "bottom",
|
|
34
|
+
hoverZoom = true,
|
|
35
|
+
zoomScale = 2.5,
|
|
36
|
+
labels: labelsProp,
|
|
37
|
+
className,
|
|
38
|
+
...props
|
|
39
|
+
}, ref) => {
|
|
40
|
+
const [zoom, setZoom] = React.useState(null);
|
|
41
|
+
const canHoverZoom = React.useRef(false);
|
|
42
|
+
React.useEffect(() => {
|
|
43
|
+
canHoverZoom.current = !!window.matchMedia?.("(hover: hover) and (pointer: fine) and (min-width: 1024px)").matches;
|
|
44
|
+
}, []);
|
|
45
|
+
const total = images.length;
|
|
46
|
+
const [rawIndex, setIndex] = useControllableState({
|
|
47
|
+
value: indexProp,
|
|
48
|
+
defaultValue: defaultIndex,
|
|
49
|
+
onChange: onIndexChange
|
|
50
|
+
});
|
|
51
|
+
const index = Math.min(Math.max(rawIndex, 0), Math.max(total - 1, 0));
|
|
52
|
+
const [lightboxOpen, setLightboxOpen] = React.useState(false);
|
|
53
|
+
const trackRef = React.useRef(null);
|
|
54
|
+
const thumbRefs = React.useRef([]);
|
|
55
|
+
const slideRefs = React.useRef([]);
|
|
56
|
+
const settleTimer = React.useRef(void 0);
|
|
57
|
+
const [settleCount, setSettleCount] = React.useState(0);
|
|
58
|
+
const labels = {
|
|
59
|
+
gallery: "Product images",
|
|
60
|
+
previous: "Previous image",
|
|
61
|
+
next: "Next image",
|
|
62
|
+
position: (i, n) => `${i + 1} of ${n}`,
|
|
63
|
+
openFullscreen: (i, n) => `Open image ${i + 1} of ${n} in full screen`,
|
|
64
|
+
thumbnail: (i, n) => `Show image ${i + 1} of ${n}`,
|
|
65
|
+
close: "Close",
|
|
66
|
+
zoomIn: "Zoom in",
|
|
67
|
+
zoomOut: "Zoom out",
|
|
68
|
+
...labelsProp
|
|
69
|
+
};
|
|
70
|
+
React.useEffect(() => {
|
|
71
|
+
const track = trackRef.current;
|
|
72
|
+
if (!track || track.clientWidth === 0) return;
|
|
73
|
+
const target = index * track.clientWidth;
|
|
74
|
+
if (Math.abs(track.scrollLeft - target) > 2) {
|
|
75
|
+
track.scrollTo({ left: target, behavior: prefersReducedMotion() ? "auto" : "smooth" });
|
|
76
|
+
}
|
|
77
|
+
thumbRefs.current[index]?.scrollIntoView?.({ block: "nearest", inline: "nearest" });
|
|
78
|
+
}, [index, settleCount]);
|
|
79
|
+
React.useEffect(() => () => clearTimeout(settleTimer.current), []);
|
|
80
|
+
const onScroll = () => {
|
|
81
|
+
clearTimeout(settleTimer.current);
|
|
82
|
+
settleTimer.current = setTimeout(() => {
|
|
83
|
+
const track = trackRef.current;
|
|
84
|
+
if (!track || track.clientWidth === 0) return;
|
|
85
|
+
const settled = Math.round(track.scrollLeft / track.clientWidth);
|
|
86
|
+
if (settled !== index && settled >= 0 && settled < total) {
|
|
87
|
+
setIndex(settled);
|
|
88
|
+
setSettleCount((count) => count + 1);
|
|
89
|
+
}
|
|
90
|
+
}, SCROLL_SETTLE_MS);
|
|
91
|
+
};
|
|
92
|
+
const go = (delta) => {
|
|
93
|
+
const next = index + delta;
|
|
94
|
+
if (next >= 0 && next < total) setIndex(next);
|
|
95
|
+
};
|
|
96
|
+
const onZoomMove = (event) => {
|
|
97
|
+
if (!hoverZoom || event.pointerType !== "mouse" || !canHoverZoom.current || lightboxOpen) return;
|
|
98
|
+
const box = event.currentTarget.getBoundingClientRect();
|
|
99
|
+
const clamp = (n) => Math.min(Math.max(n, 0), 1);
|
|
100
|
+
setZoom({
|
|
101
|
+
x: clamp((event.clientX - box.left) / box.width),
|
|
102
|
+
y: clamp((event.clientY - box.top) / box.height)
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
const lens = 100 / zoomScale;
|
|
106
|
+
const lensLeft = zoom ? Math.min(Math.max(zoom.x * 100 - lens / 2, 0), 100 - lens) : 0;
|
|
107
|
+
const lensTop = zoom ? Math.min(Math.max(zoom.y * 100 - lens / 2, 0), 100 - lens) : 0;
|
|
108
|
+
const onKeyDown = (event) => {
|
|
109
|
+
if (lightboxOpen) return;
|
|
110
|
+
if (event.key === "ArrowRight") {
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
go(1);
|
|
113
|
+
} else if (event.key === "ArrowLeft") {
|
|
114
|
+
event.preventDefault();
|
|
115
|
+
go(-1);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
if (total === 0) {
|
|
119
|
+
return /* @__PURE__ */ jsx(
|
|
120
|
+
"div",
|
|
121
|
+
{
|
|
122
|
+
ref,
|
|
123
|
+
className: cn(productGalleryFrameVariants(), className),
|
|
124
|
+
style: { aspectRatio },
|
|
125
|
+
"data-slot": "product-gallery",
|
|
126
|
+
...props
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
return /* @__PURE__ */ jsxs(
|
|
131
|
+
"div",
|
|
132
|
+
{
|
|
133
|
+
ref,
|
|
134
|
+
role: "region",
|
|
135
|
+
"aria-roledescription": "carousel",
|
|
136
|
+
"aria-label": labels.gallery,
|
|
137
|
+
className: cn(productGalleryVariants({ thumbnails }), className),
|
|
138
|
+
onKeyDown,
|
|
139
|
+
"data-slot": "product-gallery",
|
|
140
|
+
...props,
|
|
141
|
+
children: [
|
|
142
|
+
/* @__PURE__ */ jsxs("div", { className: productGalleryStageVariants(), children: [
|
|
143
|
+
/* @__PURE__ */ jsxs(
|
|
144
|
+
"div",
|
|
145
|
+
{
|
|
146
|
+
className: productGalleryFrameVariants(),
|
|
147
|
+
style: { aspectRatio },
|
|
148
|
+
onPointerMove: onZoomMove,
|
|
149
|
+
onPointerLeave: () => setZoom(null),
|
|
150
|
+
children: [
|
|
151
|
+
/* @__PURE__ */ jsx(
|
|
152
|
+
"div",
|
|
153
|
+
{
|
|
154
|
+
ref: trackRef,
|
|
155
|
+
className: productGalleryTrackVariants(),
|
|
156
|
+
onScroll,
|
|
157
|
+
"data-slot": "product-gallery-track",
|
|
158
|
+
children: images.map((image, i) => /* @__PURE__ */ jsx(
|
|
159
|
+
"div",
|
|
160
|
+
{
|
|
161
|
+
role: "group",
|
|
162
|
+
"aria-roledescription": "slide",
|
|
163
|
+
"aria-label": labels.position(i, total),
|
|
164
|
+
"aria-hidden": i === index ? void 0 : true,
|
|
165
|
+
className: "relative size-full shrink-0 snap-center snap-always",
|
|
166
|
+
"data-slot": "product-gallery-slide",
|
|
167
|
+
children: /* @__PURE__ */ jsx(
|
|
168
|
+
"button",
|
|
169
|
+
{
|
|
170
|
+
ref: (node) => {
|
|
171
|
+
slideRefs.current[i] = node;
|
|
172
|
+
},
|
|
173
|
+
type: "button",
|
|
174
|
+
"aria-label": labels.openFullscreen(i, total),
|
|
175
|
+
tabIndex: i === index ? 0 : -1,
|
|
176
|
+
className: productGallerySlideVariants(),
|
|
177
|
+
onClick: () => {
|
|
178
|
+
setIndex(i);
|
|
179
|
+
setLightboxOpen(true);
|
|
180
|
+
},
|
|
181
|
+
children: renderImage(image, { priority: i === 0, sizes, slot: "main", className: "object-cover" })
|
|
182
|
+
}
|
|
183
|
+
)
|
|
184
|
+
},
|
|
185
|
+
`${image.src}-${i}`
|
|
186
|
+
))
|
|
187
|
+
}
|
|
188
|
+
),
|
|
189
|
+
total > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
190
|
+
/* @__PURE__ */ jsx(
|
|
191
|
+
"button",
|
|
192
|
+
{
|
|
193
|
+
type: "button",
|
|
194
|
+
"aria-label": labels.previous,
|
|
195
|
+
className: productGalleryArrowVariants({ side: "left" }),
|
|
196
|
+
disabled: index === 0,
|
|
197
|
+
onClick: () => go(-1),
|
|
198
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { "aria-hidden": "true", className: "size-5" })
|
|
199
|
+
}
|
|
200
|
+
),
|
|
201
|
+
/* @__PURE__ */ jsx(
|
|
202
|
+
"button",
|
|
203
|
+
{
|
|
204
|
+
type: "button",
|
|
205
|
+
"aria-label": labels.next,
|
|
206
|
+
className: productGalleryArrowVariants({ side: "right" }),
|
|
207
|
+
disabled: index >= total - 1,
|
|
208
|
+
onClick: () => go(1),
|
|
209
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true", className: "size-5" })
|
|
210
|
+
}
|
|
211
|
+
),
|
|
212
|
+
/* @__PURE__ */ jsxs("span", { className: productGalleryCounterVariants(), "aria-hidden": "true", children: [
|
|
213
|
+
index + 1,
|
|
214
|
+
" / ",
|
|
215
|
+
total
|
|
216
|
+
] })
|
|
217
|
+
] }),
|
|
218
|
+
zoom && /* @__PURE__ */ jsx(
|
|
219
|
+
"span",
|
|
220
|
+
{
|
|
221
|
+
"aria-hidden": "true",
|
|
222
|
+
className: productGalleryLensVariants(),
|
|
223
|
+
style: { left: `${lensLeft}%`, top: `${lensTop}%`, width: `${lens}%`, height: `${lens}%` },
|
|
224
|
+
"data-slot": "product-gallery-lens"
|
|
225
|
+
}
|
|
226
|
+
)
|
|
227
|
+
]
|
|
228
|
+
}
|
|
229
|
+
),
|
|
230
|
+
zoom && images[index] && /* @__PURE__ */ jsx(
|
|
231
|
+
"div",
|
|
232
|
+
{
|
|
233
|
+
"aria-hidden": "true",
|
|
234
|
+
className: productGalleryZoomPaneVariants(),
|
|
235
|
+
style: { aspectRatio },
|
|
236
|
+
"data-slot": "product-gallery-zoom",
|
|
237
|
+
children: /* @__PURE__ */ jsx(
|
|
238
|
+
"div",
|
|
239
|
+
{
|
|
240
|
+
className: "absolute left-0 top-0",
|
|
241
|
+
style: {
|
|
242
|
+
width: `${zoomScale * 100}%`,
|
|
243
|
+
height: `${zoomScale * 100}%`,
|
|
244
|
+
transform: `translate(${-lensLeft}%, ${-lensTop}%)`
|
|
245
|
+
},
|
|
246
|
+
children: /* @__PURE__ */ jsx(
|
|
247
|
+
"img",
|
|
248
|
+
{
|
|
249
|
+
src: images[index].src,
|
|
250
|
+
alt: "",
|
|
251
|
+
decoding: "async",
|
|
252
|
+
draggable: false,
|
|
253
|
+
className: "size-full max-w-none object-cover"
|
|
254
|
+
}
|
|
255
|
+
)
|
|
256
|
+
}
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
)
|
|
260
|
+
] }),
|
|
261
|
+
total > 1 && /* @__PURE__ */ jsx("div", { className: productGalleryThumbsVariants({ thumbnails }), "data-slot": "product-gallery-thumbs", children: /* @__PURE__ */ jsx("div", { className: productGalleryThumbListVariants({ thumbnails }), children: images.map((image, i) => /* @__PURE__ */ jsx(
|
|
262
|
+
"button",
|
|
263
|
+
{
|
|
264
|
+
ref: (node) => {
|
|
265
|
+
thumbRefs.current[i] = node;
|
|
266
|
+
},
|
|
267
|
+
type: "button",
|
|
268
|
+
"aria-label": labels.thumbnail(i, total),
|
|
269
|
+
"aria-current": i === index ? "true" : void 0,
|
|
270
|
+
className: productGalleryThumbVariants({ active: i === index, thumbnails }),
|
|
271
|
+
onClick: () => setIndex(i),
|
|
272
|
+
children: renderImage(image, {
|
|
273
|
+
priority: false,
|
|
274
|
+
sizes: thumbnails === "left" ? "(min-width: 1024px) 72px, 22vw" : "(min-width: 1024px) 12vw, 22vw",
|
|
275
|
+
slot: "thumbnail",
|
|
276
|
+
className: "object-cover"
|
|
277
|
+
})
|
|
278
|
+
},
|
|
279
|
+
`${image.src}-${i}`
|
|
280
|
+
)) }) }),
|
|
281
|
+
/* @__PURE__ */ jsx(
|
|
282
|
+
ProductGalleryLightbox,
|
|
283
|
+
{
|
|
284
|
+
open: lightboxOpen,
|
|
285
|
+
onOpenChange: setLightboxOpen,
|
|
286
|
+
images,
|
|
287
|
+
index,
|
|
288
|
+
onIndexChange: setIndex,
|
|
289
|
+
renderImage,
|
|
290
|
+
labels,
|
|
291
|
+
onCloseAutoFocus: (event) => {
|
|
292
|
+
const slide = slideRefs.current[index];
|
|
293
|
+
if (!slide) return;
|
|
294
|
+
event.preventDefault();
|
|
295
|
+
slide.focus({ preventScroll: true });
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
)
|
|
299
|
+
]
|
|
300
|
+
}
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
ProductGallery.displayName = "ProductGallery";
|
|
305
|
+
|
|
306
|
+
export { ProductGallery };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare const productGalleryVariants: (props?: ({
|
|
2
|
+
thumbnails?: "left" | "bottom" | null | undefined;
|
|
3
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
4
|
+
/** Holds the frame and, beside it, the hover zoom pane. */
|
|
5
|
+
export declare const productGalleryStageVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
6
|
+
/** Main image frame: a scroll-snap track (swipe on touch, arrows on desktop). */
|
|
7
|
+
export declare const productGalleryFrameVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
8
|
+
export declare const productGalleryTrackVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
9
|
+
/** The button filling a slide (opens the fullscreen viewer). */
|
|
10
|
+
export declare const productGallerySlideVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
11
|
+
/** Figma: 40px translucent circles with a light shadow. */
|
|
12
|
+
export declare const productGalleryArrowVariants: (props?: ({
|
|
13
|
+
side?: "left" | "right" | null | undefined;
|
|
14
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
15
|
+
export declare const productGalleryCounterVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
16
|
+
export declare const productGalleryThumbsVariants: (props?: ({
|
|
17
|
+
thumbnails?: "left" | "bottom" | null | undefined;
|
|
18
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
19
|
+
export declare const productGalleryThumbListVariants: (props?: ({
|
|
20
|
+
thumbnails?: "left" | "bottom" | null | undefined;
|
|
21
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
22
|
+
export declare const productGalleryThumbVariants: (props?: ({
|
|
23
|
+
thumbnails?: "left" | "bottom" | null | undefined;
|
|
24
|
+
active?: boolean | null | undefined;
|
|
25
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
26
|
+
/** The square that follows the pointer over the image (what the zoom pane magnifies). */
|
|
27
|
+
export declare const productGalleryLensVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
28
|
+
/** Desktop hover zoom: a pane beside the image, over the content next to it. */
|
|
29
|
+
export declare const productGalleryZoomPaneVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
30
|
+
export declare const productGalleryLightboxVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
31
|
+
export declare const productGalleryLightboxButtonVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
32
|
+
//# sourceMappingURL=ProductGallery.styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProductGallery.styles.d.ts","sourceRoot":"","sources":["../../../src/components/ProductGallery/ProductGallery.styles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,sBAAsB;;8EASjC,CAAC;AAEH,2DAA2D;AAC3D,eAAO,MAAM,2BAA2B,oFAA0B,CAAC;AAEnE,iFAAiF;AACjF,eAAO,MAAM,2BAA2B,oFAAyD,CAAC;AAElG,eAAO,MAAM,2BAA2B,oFAEvC,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,2BAA2B,oFAEvC,CAAC;AAEF,2DAA2D;AAC3D,eAAO,MAAM,2BAA2B;;8EAUvC,CAAC;AAEF,eAAO,MAAM,6BAA6B,oFAEzC,CAAC;AAEF,eAAO,MAAM,4BAA4B;;8EASvC,CAAC;AAEH,eAAO,MAAM,+BAA+B;;8EAW3C,CAAC;AAEF,eAAO,MAAM,2BAA2B;;;8EAevC,CAAC;AAEF,yFAAyF;AACzF,eAAO,MAAM,0BAA0B,oFAEtC,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,8BAA8B,oFAE1C,CAAC;AAEF,eAAO,MAAM,8BAA8B,oFAE1C,CAAC;AAEF,eAAO,MAAM,oCAAoC,oFAEhD,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { cva } from 'class-variance-authority';
|
|
2
|
+
|
|
3
|
+
const productGalleryVariants = cva("flex min-w-0 flex-col gap-3 font-sans", {
|
|
4
|
+
variants: {
|
|
5
|
+
/** `left`: a vertical thumbnail column beside the image from lg up (a row below it on phones). */
|
|
6
|
+
thumbnails: {
|
|
7
|
+
bottom: "lg:gap-6",
|
|
8
|
+
left: "lg:grid lg:grid-cols-[4.5rem_minmax(0,1fr)] lg:gap-4"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
defaultVariants: { thumbnails: "bottom" }
|
|
12
|
+
});
|
|
13
|
+
const productGalleryStageVariants = cva("relative min-w-0");
|
|
14
|
+
const productGalleryFrameVariants = cva("relative overflow-hidden rounded-sm bg-grey-100");
|
|
15
|
+
const productGalleryTrackVariants = cva(
|
|
16
|
+
"flex size-full snap-x snap-mandatory overflow-x-auto overscroll-x-contain [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
|
|
17
|
+
);
|
|
18
|
+
const productGallerySlideVariants = cva(
|
|
19
|
+
"relative block size-full cursor-zoom-in focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
|
|
20
|
+
);
|
|
21
|
+
const productGalleryArrowVariants = cva(
|
|
22
|
+
"absolute top-1/2 z-10 hidden size-10 -translate-y-1/2 items-center justify-center rounded-full bg-grey-50/70 text-grey-950 shadow-sm backdrop-blur-sm transition-colors hover:bg-grey-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-0 md:flex",
|
|
23
|
+
{
|
|
24
|
+
variants: {
|
|
25
|
+
side: {
|
|
26
|
+
left: "left-3",
|
|
27
|
+
right: "right-3"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
const productGalleryCounterVariants = cva(
|
|
33
|
+
"pointer-events-none absolute bottom-3 left-3 rounded-full bg-grey-950/70 px-2.5 py-1 text-caption font-semibold text-grey-50 tabular-nums md:hidden"
|
|
34
|
+
);
|
|
35
|
+
const productGalleryThumbsVariants = cva("relative", {
|
|
36
|
+
variants: {
|
|
37
|
+
thumbnails: {
|
|
38
|
+
bottom: "",
|
|
39
|
+
// The column takes the frame's height (its row) and scrolls inside it.
|
|
40
|
+
left: "lg:order-first"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
defaultVariants: { thumbnails: "bottom" }
|
|
44
|
+
});
|
|
45
|
+
const productGalleryThumbListVariants = cva(
|
|
46
|
+
"flex snap-x gap-2 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
47
|
+
{
|
|
48
|
+
variants: {
|
|
49
|
+
thumbnails: {
|
|
50
|
+
bottom: "lg:gap-3",
|
|
51
|
+
left: "lg:absolute lg:inset-0 lg:snap-y lg:flex-col lg:gap-3 lg:overflow-y-auto lg:overflow-x-visible lg:p-0.5"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
defaultVariants: { thumbnails: "bottom" }
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
const productGalleryThumbVariants = cva(
|
|
58
|
+
"relative aspect-square w-[calc((100%-1.5rem)/4.5)] shrink-0 snap-start overflow-hidden rounded-sm bg-grey-100 transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
59
|
+
{
|
|
60
|
+
variants: {
|
|
61
|
+
thumbnails: {
|
|
62
|
+
bottom: "lg:w-[calc((100%-2.25rem)/4)]",
|
|
63
|
+
left: "lg:w-full"
|
|
64
|
+
},
|
|
65
|
+
active: {
|
|
66
|
+
true: "border-2 border-primary",
|
|
67
|
+
false: "border border-grey-200 opacity-85 hover:border-grey-400 hover:opacity-100"
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
defaultVariants: { active: false, thumbnails: "bottom" }
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
const productGalleryLensVariants = cva(
|
|
74
|
+
"pointer-events-none absolute z-10 border border-grey-50/80 bg-grey-50/25 shadow-sm"
|
|
75
|
+
);
|
|
76
|
+
const productGalleryZoomPaneVariants = cva(
|
|
77
|
+
"pointer-events-none absolute left-[calc(100%+1.5rem)] top-0 z-30 hidden h-full overflow-hidden rounded-sm border border-grey-200 bg-grey-100 shadow-xl lg:block"
|
|
78
|
+
);
|
|
79
|
+
const productGalleryLightboxVariants = cva(
|
|
80
|
+
"fixed inset-0 z-[10000] flex flex-col bg-grey-1000/95 text-grey-50 focus:outline-none"
|
|
81
|
+
);
|
|
82
|
+
const productGalleryLightboxButtonVariants = cva(
|
|
83
|
+
"flex size-11 items-center justify-center rounded-full bg-grey-50/10 text-grey-50 transition-colors hover:bg-grey-50/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-grey-50 disabled:pointer-events-none disabled:opacity-30"
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
export { productGalleryArrowVariants, productGalleryCounterVariants, productGalleryFrameVariants, productGalleryLensVariants, productGalleryLightboxButtonVariants, productGalleryLightboxVariants, productGallerySlideVariants, productGalleryStageVariants, productGalleryThumbListVariants, productGalleryThumbVariants, productGalleryThumbsVariants, productGalleryTrackVariants, productGalleryVariants, productGalleryZoomPaneVariants };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
export interface ProductGalleryImage {
|
|
3
|
+
src: string;
|
|
4
|
+
alt: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ProductGalleryRenderOptions {
|
|
7
|
+
/** True for the first main image: load it eagerly with high priority (it's usually the LCP). */
|
|
8
|
+
priority: boolean;
|
|
9
|
+
/** `sizes` for a responsive image. */
|
|
10
|
+
sizes: string;
|
|
11
|
+
/** Where the image is drawn; each needs a different `sizes`. */
|
|
12
|
+
slot: 'main' | 'thumbnail' | 'lightbox';
|
|
13
|
+
className: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ProductGalleryLabels {
|
|
16
|
+
/** Accessible name of the gallery. */
|
|
17
|
+
gallery?: string;
|
|
18
|
+
previous?: string;
|
|
19
|
+
next?: string;
|
|
20
|
+
/** e.g. "2 of 5" (slides and the visible counter). */
|
|
21
|
+
position?: (index: number, total: number) => string;
|
|
22
|
+
/** Button name over the main image. */
|
|
23
|
+
openFullscreen?: (index: number, total: number) => string;
|
|
24
|
+
thumbnail?: (index: number, total: number) => string;
|
|
25
|
+
close?: string;
|
|
26
|
+
zoomIn?: string;
|
|
27
|
+
zoomOut?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ProductGalleryProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
|
|
30
|
+
images: ProductGalleryImage[];
|
|
31
|
+
/** Controlled index of the shown image. */
|
|
32
|
+
index?: number;
|
|
33
|
+
defaultIndex?: number;
|
|
34
|
+
onIndexChange?: (index: number) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Draws an image filling its box (e.g. Next.js `<Image fill>`). Defaults to a plain <img> with
|
|
37
|
+
* object-fit cover (contain in the lightbox).
|
|
38
|
+
*/
|
|
39
|
+
renderImage?: (image: ProductGalleryImage, options: ProductGalleryRenderOptions) => React.ReactNode;
|
|
40
|
+
/** CSS aspect ratio of the main image. Defaults to "4 / 3". */
|
|
41
|
+
aspectRatio?: string;
|
|
42
|
+
/** `sizes` of the main image. Defaults to "(min-width: 1024px) 50vw, 100vw". */
|
|
43
|
+
sizes?: string;
|
|
44
|
+
/** Thumbnails below the image, or in a column on its left from lg up. Defaults to "bottom". */
|
|
45
|
+
thumbnails?: 'bottom' | 'left';
|
|
46
|
+
/**
|
|
47
|
+
* Desktop (mouse) hover zoom: a lens over the image and a magnified pane beside it. The pane
|
|
48
|
+
* draws `src` at full size, so use a high-resolution source. Defaults to true.
|
|
49
|
+
*/
|
|
50
|
+
hoverZoom?: boolean;
|
|
51
|
+
/** Magnification of the hover zoom. Defaults to 2.5. */
|
|
52
|
+
zoomScale?: number;
|
|
53
|
+
labels?: ProductGalleryLabels;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=ProductGallery.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProductGallery.types.d.ts","sourceRoot":"","sources":["../../../src/components/ProductGallery/ProductGallery.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,2BAA2B;IAC1C,gGAAgG;IAChG,QAAQ,EAAE,OAAO,CAAC;IAClB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACpD,uCAAuC;IACvC,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1D,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IACjG,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,2BAA2B,KAAK,KAAK,CAAC,SAAS,CAAC;IACpG,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+FAA+F;IAC/F,UAAU,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC/B;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,oBAAoB,CAAC;CAC/B"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { ProductGalleryImage, ProductGalleryLabels, ProductGalleryProps } from './ProductGallery.types';
|
|
3
|
+
export interface ProductGalleryLightboxProps {
|
|
4
|
+
open: boolean;
|
|
5
|
+
onOpenChange: (open: boolean) => void;
|
|
6
|
+
images: ProductGalleryImage[];
|
|
7
|
+
index: number;
|
|
8
|
+
onIndexChange: (index: number) => void;
|
|
9
|
+
renderImage: NonNullable<ProductGalleryProps['renderImage']>;
|
|
10
|
+
labels: Required<Pick<ProductGalleryLabels, 'previous' | 'next' | 'position' | 'close' | 'zoomIn' | 'zoomOut'>> & ProductGalleryLabels;
|
|
11
|
+
/** Where focus goes on close (the dialog has no trigger, so the gallery points it at the current slide). */
|
|
12
|
+
onCloseAutoFocus?: (event: Event) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Fullscreen viewer: swipe (touch), arrow keys and the side buttons (tablet and up) move between
|
|
16
|
+
* images; double-click / double-tap, the wheel and two-finger pinch zoom (up to 3×), and dragging
|
|
17
|
+
* pans a zoomed image. Pointer events only, no gesture library.
|
|
18
|
+
*/
|
|
19
|
+
export declare function ProductGalleryLightbox({ open, onOpenChange, images, index, onIndexChange, renderImage, labels, onCloseAutoFocus, }: ProductGalleryLightboxProps): React.JSX.Element;
|
|
20
|
+
//# sourceMappingURL=ProductGalleryLightbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProductGalleryLightbox.d.ts","sourceRoot":"","sources":["../../../src/components/ProductGallery/ProductGalleryLightbox.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAgB7G,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,EAAE,WAAW,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC,CAAC;IAC7D,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,oBAAoB,EAAE,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC,GAC7G,oBAAoB,CAAC;IACvB,4GAA4G;IAC5G,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC3C;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,KAAK,EACL,aAAa,EACb,WAAW,EACX,MAAM,EACN,gBAAgB,GACjB,EAAE,2BAA2B,qBA0M7B"}
|