@mantine/lightbox 9.5.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/LICENSE +21 -0
- package/README.md +21 -0
- package/cjs/Lightbox.cjs +56 -0
- package/cjs/Lightbox.cjs.map +1 -0
- package/cjs/Lightbox.module.cjs +30 -0
- package/cjs/Lightbox.module.cjs.map +1 -0
- package/cjs/LightboxCaption/LightboxCaption.cjs +30 -0
- package/cjs/LightboxCaption/LightboxCaption.cjs.map +1 -0
- package/cjs/LightboxCloseButton/LightboxCloseButton.cjs +32 -0
- package/cjs/LightboxCloseButton/LightboxCloseButton.cjs.map +1 -0
- package/cjs/LightboxNavigation/LightboxNavigation.cjs +105 -0
- package/cjs/LightboxNavigation/LightboxNavigation.cjs.map +1 -0
- package/cjs/LightboxProvider/LightboxProvider.cjs +29 -0
- package/cjs/LightboxProvider/LightboxProvider.cjs.map +1 -0
- package/cjs/LightboxRoot/LightboxRoot.cjs +407 -0
- package/cjs/LightboxRoot/LightboxRoot.cjs.map +1 -0
- package/cjs/LightboxSlide/ImageSlide.cjs +27 -0
- package/cjs/LightboxSlide/ImageSlide.cjs.map +1 -0
- package/cjs/LightboxSlide/LightboxSlide.cjs +55 -0
- package/cjs/LightboxSlide/LightboxSlide.cjs.map +1 -0
- package/cjs/LightboxSlide/VideoSlide.cjs +42 -0
- package/cjs/LightboxSlide/VideoSlide.cjs.map +1 -0
- package/cjs/LightboxSlides/LightboxSlides.cjs +56 -0
- package/cjs/LightboxSlides/LightboxSlides.cjs.map +1 -0
- package/cjs/LightboxThumbnails/LightboxThumbnails.cjs +74 -0
- package/cjs/LightboxThumbnails/LightboxThumbnails.cjs.map +1 -0
- package/cjs/LightboxToolbar/LightboxToolbar.cjs +80 -0
- package/cjs/LightboxToolbar/LightboxToolbar.cjs.map +1 -0
- package/cjs/LightboxToolbar/toolbar-items.cjs +156 -0
- package/cjs/LightboxToolbar/toolbar-items.cjs.map +1 -0
- package/cjs/_virtual/_rolldown/runtime.cjs +24 -0
- package/cjs/default-labels.cjs +20 -0
- package/cjs/default-labels.cjs.map +1 -0
- package/cjs/hooks/use-lightbox-keyboard.cjs +107 -0
- package/cjs/hooks/use-lightbox-keyboard.cjs.map +1 -0
- package/cjs/hooks/use-lightbox-lock-scroll.cjs +30 -0
- package/cjs/hooks/use-lightbox-lock-scroll.cjs.map +1 -0
- package/cjs/hooks/use-lightbox-swipe-close.cjs +38 -0
- package/cjs/hooks/use-lightbox-swipe-close.cjs.map +1 -0
- package/cjs/hooks/use-lightbox-zoom.cjs +257 -0
- package/cjs/hooks/use-lightbox-zoom.cjs.map +1 -0
- package/cjs/index.cjs +34 -0
- package/cjs/lightbox.context.cjs +8 -0
- package/cjs/lightbox.context.cjs.map +1 -0
- package/cjs/lightbox.store.cjs +90 -0
- package/cjs/lightbox.store.cjs.map +1 -0
- package/esm/Lightbox.mjs +56 -0
- package/esm/Lightbox.mjs.map +1 -0
- package/esm/Lightbox.module.mjs +30 -0
- package/esm/Lightbox.module.mjs.map +1 -0
- package/esm/LightboxCaption/LightboxCaption.mjs +30 -0
- package/esm/LightboxCaption/LightboxCaption.mjs.map +1 -0
- package/esm/LightboxCloseButton/LightboxCloseButton.mjs +32 -0
- package/esm/LightboxCloseButton/LightboxCloseButton.mjs.map +1 -0
- package/esm/LightboxNavigation/LightboxNavigation.mjs +105 -0
- package/esm/LightboxNavigation/LightboxNavigation.mjs.map +1 -0
- package/esm/LightboxProvider/LightboxProvider.mjs +29 -0
- package/esm/LightboxProvider/LightboxProvider.mjs.map +1 -0
- package/esm/LightboxRoot/LightboxRoot.mjs +404 -0
- package/esm/LightboxRoot/LightboxRoot.mjs.map +1 -0
- package/esm/LightboxSlide/ImageSlide.mjs +27 -0
- package/esm/LightboxSlide/ImageSlide.mjs.map +1 -0
- package/esm/LightboxSlide/LightboxSlide.mjs +55 -0
- package/esm/LightboxSlide/LightboxSlide.mjs.map +1 -0
- package/esm/LightboxSlide/VideoSlide.mjs +42 -0
- package/esm/LightboxSlide/VideoSlide.mjs.map +1 -0
- package/esm/LightboxSlides/LightboxSlides.mjs +56 -0
- package/esm/LightboxSlides/LightboxSlides.mjs.map +1 -0
- package/esm/LightboxThumbnails/LightboxThumbnails.mjs +72 -0
- package/esm/LightboxThumbnails/LightboxThumbnails.mjs.map +1 -0
- package/esm/LightboxToolbar/LightboxToolbar.mjs +80 -0
- package/esm/LightboxToolbar/LightboxToolbar.mjs.map +1 -0
- package/esm/LightboxToolbar/toolbar-items.mjs +153 -0
- package/esm/LightboxToolbar/toolbar-items.mjs.map +1 -0
- package/esm/default-labels.mjs +20 -0
- package/esm/default-labels.mjs.map +1 -0
- package/esm/hooks/use-lightbox-keyboard.mjs +107 -0
- package/esm/hooks/use-lightbox-keyboard.mjs.map +1 -0
- package/esm/hooks/use-lightbox-lock-scroll.mjs +30 -0
- package/esm/hooks/use-lightbox-lock-scroll.mjs.map +1 -0
- package/esm/hooks/use-lightbox-swipe-close.mjs +38 -0
- package/esm/hooks/use-lightbox-swipe-close.mjs.map +1 -0
- package/esm/hooks/use-lightbox-zoom.mjs +257 -0
- package/esm/hooks/use-lightbox-zoom.mjs.map +1 -0
- package/esm/index.mjs +14 -0
- package/esm/lightbox.context.mjs +8 -0
- package/esm/lightbox.context.mjs.map +1 -0
- package/esm/lightbox.store.mjs +79 -0
- package/esm/lightbox.store.mjs.map +1 -0
- package/lib/Lightbox.d.ts +63 -0
- package/lib/LightboxCaption/LightboxCaption.d.ts +18 -0
- package/lib/LightboxCloseButton/LightboxCloseButton.d.ts +16 -0
- package/lib/LightboxNavigation/LightboxNavigation.d.ts +16 -0
- package/lib/LightboxProvider/LightboxProvider.d.ts +19 -0
- package/lib/LightboxRoot/LightboxRoot.d.ts +88 -0
- package/lib/LightboxSlide/ImageSlide.d.ts +12 -0
- package/lib/LightboxSlide/LightboxSlide.d.ts +25 -0
- package/lib/LightboxSlide/VideoSlide.d.ts +12 -0
- package/lib/LightboxSlides/LightboxSlides.d.ts +20 -0
- package/lib/LightboxThumbnails/LightboxThumbnails.d.ts +16 -0
- package/lib/LightboxToolbar/LightboxToolbar.d.ts +19 -0
- package/lib/LightboxToolbar/toolbar-items.d.ts +5 -0
- package/lib/default-labels.d.ts +2 -0
- package/lib/hooks/use-lightbox-keyboard.d.ts +15 -0
- package/lib/hooks/use-lightbox-lock-scroll.d.ts +7 -0
- package/lib/hooks/use-lightbox-swipe-close.d.ts +10 -0
- package/lib/hooks/use-lightbox-zoom.d.ts +33 -0
- package/lib/index.d.mts +67 -0
- package/lib/index.d.ts +67 -0
- package/lib/lightbox.context.d.ts +36 -0
- package/lib/lightbox.store.d.ts +66 -0
- package/lib/lightbox.types.d.ts +131 -0
- package/lib/test-utils.d.ts +7 -0
- package/package.json +63 -0
- package/styles.css +262 -0
- package/styles.layer.css +263 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
let react = require("react");
|
|
3
|
+
//#region packages/@mantine/lightbox/src/hooks/use-lightbox-swipe-close.ts
|
|
4
|
+
const SWIPE_THRESHOLD = 100;
|
|
5
|
+
function useLightboxSwipeClose({ enabled, onClose, isZoomed }) {
|
|
6
|
+
const touchStart = (0, react.useRef)(null);
|
|
7
|
+
return {
|
|
8
|
+
handleTouchStart: (0, react.useCallback)((event) => {
|
|
9
|
+
if (!enabled || isZoomed) return;
|
|
10
|
+
if (event.touches.length !== 1) {
|
|
11
|
+
touchStart.current = null;
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
touchStart.current = {
|
|
15
|
+
x: event.touches[0].clientX,
|
|
16
|
+
y: event.touches[0].clientY
|
|
17
|
+
};
|
|
18
|
+
}, [enabled, isZoomed]),
|
|
19
|
+
handleTouchEnd: (0, react.useCallback)((event) => {
|
|
20
|
+
if (!enabled || isZoomed || !touchStart.current || event.changedTouches.length !== 1) {
|
|
21
|
+
touchStart.current = null;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const deltaY = event.changedTouches[0].clientY - touchStart.current.y;
|
|
25
|
+
const deltaX = Math.abs(event.changedTouches[0].clientX - touchStart.current.x);
|
|
26
|
+
if (deltaY > SWIPE_THRESHOLD && deltaX < deltaY) onClose();
|
|
27
|
+
touchStart.current = null;
|
|
28
|
+
}, [
|
|
29
|
+
enabled,
|
|
30
|
+
isZoomed,
|
|
31
|
+
onClose
|
|
32
|
+
])
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
exports.useLightboxSwipeClose = useLightboxSwipeClose;
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=use-lightbox-swipe-close.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-lightbox-swipe-close.cjs","names":["useRef","useCallback"],"sources":["../../src/hooks/use-lightbox-swipe-close.ts"],"sourcesContent":["import { useCallback, useRef } from 'react';\n\ninterface UseLightboxSwipeCloseInput {\n enabled: boolean;\n onClose: () => void;\n isZoomed: boolean;\n}\n\nconst SWIPE_THRESHOLD = 100;\n\nexport function useLightboxSwipeClose({ enabled, onClose, isZoomed }: UseLightboxSwipeCloseInput) {\n const touchStart = useRef<{ x: number; y: number } | null>(null);\n\n const handleTouchStart = useCallback(\n (event: React.TouchEvent) => {\n if (!enabled || isZoomed) {\n return;\n }\n if (event.touches.length !== 1) {\n touchStart.current = null;\n return;\n }\n touchStart.current = {\n x: event.touches[0].clientX,\n y: event.touches[0].clientY,\n };\n },\n [enabled, isZoomed]\n );\n\n const handleTouchEnd = useCallback(\n (event: React.TouchEvent) => {\n if (!enabled || isZoomed || !touchStart.current || event.changedTouches.length !== 1) {\n touchStart.current = null;\n return;\n }\n\n const deltaY = event.changedTouches[0].clientY - touchStart.current.y;\n const deltaX = Math.abs(event.changedTouches[0].clientX - touchStart.current.x);\n\n if (deltaY > SWIPE_THRESHOLD && deltaX < deltaY) {\n onClose();\n }\n\n touchStart.current = null;\n },\n [enabled, isZoomed, onClose]\n );\n\n return { handleTouchStart, handleTouchEnd };\n}\n"],"mappings":";;;AAQA,MAAM,kBAAkB;AAExB,SAAgB,sBAAsB,EAAE,SAAS,SAAS,YAAwC;CAChG,MAAM,cAAA,GAAaA,MAAAA,OAAAA,CAAwC,IAAI;CAsC/D,OAAO;EAAE,mBAAA,GApCgBC,MAAAA,YAAAA,EACtB,UAA4B;GAC3B,IAAI,CAAC,WAAW,UACd;GAEF,IAAI,MAAM,QAAQ,WAAW,GAAG;IAC9B,WAAW,UAAU;IACrB;GACF;GACA,WAAW,UAAU;IACnB,GAAG,MAAM,QAAQ,EAAE,CAAC;IACpB,GAAG,MAAM,QAAQ,EAAE,CAAC;GACtB;EACF,GACA,CAAC,SAAS,QAAQ,CAsBI;EAAG,iBAAA,GAnBJA,MAAAA,YAAAA,EACpB,UAA4B;GAC3B,IAAI,CAAC,WAAW,YAAY,CAAC,WAAW,WAAW,MAAM,eAAe,WAAW,GAAG;IACpF,WAAW,UAAU;IACrB;GACF;GAEA,MAAM,SAAS,MAAM,eAAe,EAAE,CAAC,UAAU,WAAW,QAAQ;GACpE,MAAM,SAAS,KAAK,IAAI,MAAM,eAAe,EAAE,CAAC,UAAU,WAAW,QAAQ,CAAC;GAE9E,IAAI,SAAS,mBAAmB,SAAS,QACvC,QAAQ;GAGV,WAAW,UAAU;EACvB,GACA;GAAC;GAAS;GAAU;EAAO,CAGW;CAAE;AAC5C"}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
let react = require("react");
|
|
3
|
+
//#region packages/@mantine/lightbox/src/hooks/use-lightbox-zoom.ts
|
|
4
|
+
const INITIAL_ZOOM_STATE = {
|
|
5
|
+
scale: 1,
|
|
6
|
+
translateX: 0,
|
|
7
|
+
translateY: 0,
|
|
8
|
+
isZoomed: false
|
|
9
|
+
};
|
|
10
|
+
function clampTranslate(state, image) {
|
|
11
|
+
if (!image) return state;
|
|
12
|
+
const maxX = image.offsetWidth * (state.scale - 1) / 2;
|
|
13
|
+
const maxY = image.offsetHeight * (state.scale - 1) / 2;
|
|
14
|
+
return {
|
|
15
|
+
...state,
|
|
16
|
+
translateX: Math.max(-maxX, Math.min(maxX, state.translateX)),
|
|
17
|
+
translateY: Math.max(-maxY, Math.min(maxY, state.translateY))
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function useLightboxZoom({ enabled, maxScale, currentIndex }) {
|
|
21
|
+
const [zoomState, setZoomState] = (0, react.useState)(INITIAL_ZOOM_STATE);
|
|
22
|
+
const [isDragging, setIsDragging] = (0, react.useState)(false);
|
|
23
|
+
const imageRef = (0, react.useRef)(null);
|
|
24
|
+
const isZoomedRef = (0, react.useRef)(false);
|
|
25
|
+
const didDrag = (0, react.useRef)(false);
|
|
26
|
+
const dragStart = (0, react.useRef)({
|
|
27
|
+
x: 0,
|
|
28
|
+
y: 0
|
|
29
|
+
});
|
|
30
|
+
const translateStart = (0, react.useRef)({
|
|
31
|
+
x: 0,
|
|
32
|
+
y: 0
|
|
33
|
+
});
|
|
34
|
+
const lastPinchDistance = (0, react.useRef)(null);
|
|
35
|
+
const lastPointerType = (0, react.useRef)("mouse");
|
|
36
|
+
const lastClickPointerType = (0, react.useRef)("mouse");
|
|
37
|
+
const [isAdjusting, setIsAdjusting] = (0, react.useState)(false);
|
|
38
|
+
const adjustTimeout = (0, react.useRef)(-1);
|
|
39
|
+
(0, react.useEffect)(() => {
|
|
40
|
+
isZoomedRef.current = zoomState.isZoomed;
|
|
41
|
+
}, [zoomState.isZoomed]);
|
|
42
|
+
const beginAdjust = (0, react.useCallback)(() => {
|
|
43
|
+
setIsAdjusting(true);
|
|
44
|
+
window.clearTimeout(adjustTimeout.current);
|
|
45
|
+
adjustTimeout.current = window.setTimeout(() => setIsAdjusting(false), 120);
|
|
46
|
+
}, []);
|
|
47
|
+
const beginAdjustRef = (0, react.useRef)(beginAdjust);
|
|
48
|
+
(0, react.useEffect)(() => {
|
|
49
|
+
beginAdjustRef.current = beginAdjust;
|
|
50
|
+
}, [beginAdjust]);
|
|
51
|
+
(0, react.useEffect)(() => () => window.clearTimeout(adjustTimeout.current), []);
|
|
52
|
+
const resetZoom = (0, react.useCallback)(() => {
|
|
53
|
+
setZoomState(INITIAL_ZOOM_STATE);
|
|
54
|
+
setIsDragging(false);
|
|
55
|
+
}, []);
|
|
56
|
+
const [prevIndex, setPrevIndex] = (0, react.useState)(currentIndex);
|
|
57
|
+
const [prevEnabled, setPrevEnabled] = (0, react.useState)(enabled);
|
|
58
|
+
if (currentIndex !== prevIndex || enabled !== prevEnabled) {
|
|
59
|
+
setPrevIndex(currentIndex);
|
|
60
|
+
setPrevEnabled(enabled);
|
|
61
|
+
if (currentIndex !== prevIndex || !enabled) {
|
|
62
|
+
setZoomState(INITIAL_ZOOM_STATE);
|
|
63
|
+
setIsDragging(false);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
(0, react.useEffect)(() => {
|
|
67
|
+
if (!enabled) {
|
|
68
|
+
lastPinchDistance.current = null;
|
|
69
|
+
didDrag.current = false;
|
|
70
|
+
}
|
|
71
|
+
}, [enabled]);
|
|
72
|
+
const toggleZoom = (0, react.useCallback)(() => {
|
|
73
|
+
if (!enabled) return;
|
|
74
|
+
setZoomState((prev) => prev.isZoomed ? INITIAL_ZOOM_STATE : {
|
|
75
|
+
scale: Math.min(2, maxScale),
|
|
76
|
+
translateX: 0,
|
|
77
|
+
translateY: 0,
|
|
78
|
+
isZoomed: true
|
|
79
|
+
});
|
|
80
|
+
}, [enabled, maxScale]);
|
|
81
|
+
const zoomAtPoint = (0, react.useCallback)((deltaScale, clientX, clientY) => {
|
|
82
|
+
setZoomState((prev) => {
|
|
83
|
+
const nextScale = Math.max(1, Math.min(maxScale, prev.scale + deltaScale));
|
|
84
|
+
if (nextScale === 1) return INITIAL_ZOOM_STATE;
|
|
85
|
+
const image = imageRef.current;
|
|
86
|
+
let translateX = prev.translateX;
|
|
87
|
+
let translateY = prev.translateY;
|
|
88
|
+
if (image && clientX !== void 0 && clientY !== void 0) {
|
|
89
|
+
const rect = image.getBoundingClientRect();
|
|
90
|
+
const scaleRatio = nextScale / prev.scale;
|
|
91
|
+
const offsetX = clientX - (rect.left + rect.width / 2) + prev.translateX;
|
|
92
|
+
const offsetY = clientY - (rect.top + rect.height / 2) + prev.translateY;
|
|
93
|
+
translateX = offsetX * (1 - scaleRatio) + prev.translateX * scaleRatio;
|
|
94
|
+
translateY = offsetY * (1 - scaleRatio) + prev.translateY * scaleRatio;
|
|
95
|
+
}
|
|
96
|
+
return clampTranslate({
|
|
97
|
+
scale: nextScale,
|
|
98
|
+
translateX,
|
|
99
|
+
translateY,
|
|
100
|
+
isZoomed: true
|
|
101
|
+
}, image);
|
|
102
|
+
});
|
|
103
|
+
}, [maxScale]);
|
|
104
|
+
const panZoom = (0, react.useCallback)((deltaX, deltaY) => {
|
|
105
|
+
if (!isZoomedRef.current) return false;
|
|
106
|
+
setZoomState((prev) => clampTranslate({
|
|
107
|
+
...prev,
|
|
108
|
+
translateX: prev.translateX + deltaX,
|
|
109
|
+
translateY: prev.translateY + deltaY
|
|
110
|
+
}, imageRef.current));
|
|
111
|
+
return true;
|
|
112
|
+
}, []);
|
|
113
|
+
const zoomAtPointRef = (0, react.useRef)(zoomAtPoint);
|
|
114
|
+
(0, react.useEffect)(() => {
|
|
115
|
+
zoomAtPointRef.current = zoomAtPoint;
|
|
116
|
+
}, [zoomAtPoint]);
|
|
117
|
+
const handleNativeWheel = (0, react.useRef)((event) => {
|
|
118
|
+
if (event.deltaY === 0) return;
|
|
119
|
+
event.preventDefault();
|
|
120
|
+
beginAdjustRef.current();
|
|
121
|
+
zoomAtPointRef.current(event.deltaY > 0 ? -.2 : .2, event.clientX, event.clientY);
|
|
122
|
+
});
|
|
123
|
+
const setImageRef = (0, react.useCallback)((node) => {
|
|
124
|
+
imageRef.current?.removeEventListener("wheel", handleNativeWheel.current);
|
|
125
|
+
imageRef.current = node;
|
|
126
|
+
node?.addEventListener("wheel", handleNativeWheel.current, { passive: false });
|
|
127
|
+
}, []);
|
|
128
|
+
const handlePointerDown = (0, react.useCallback)((event) => {
|
|
129
|
+
lastPointerType.current = event.pointerType;
|
|
130
|
+
if (!zoomState.isZoomed || !enabled) return;
|
|
131
|
+
setIsDragging(true);
|
|
132
|
+
didDrag.current = false;
|
|
133
|
+
dragStart.current = {
|
|
134
|
+
x: event.clientX,
|
|
135
|
+
y: event.clientY
|
|
136
|
+
};
|
|
137
|
+
translateStart.current = {
|
|
138
|
+
x: zoomState.translateX,
|
|
139
|
+
y: zoomState.translateY
|
|
140
|
+
};
|
|
141
|
+
const target = event.target;
|
|
142
|
+
if (typeof target?.setPointerCapture === "function") target.setPointerCapture(event.pointerId);
|
|
143
|
+
}, [
|
|
144
|
+
zoomState.isZoomed,
|
|
145
|
+
zoomState.translateX,
|
|
146
|
+
zoomState.translateY,
|
|
147
|
+
enabled
|
|
148
|
+
]);
|
|
149
|
+
const handlePointerMove = (0, react.useCallback)((event) => {
|
|
150
|
+
if (!isDragging || !enabled) return;
|
|
151
|
+
const dx = event.clientX - dragStart.current.x;
|
|
152
|
+
const dy = event.clientY - dragStart.current.y;
|
|
153
|
+
if (Math.abs(dx) > 3 || Math.abs(dy) > 3) didDrag.current = true;
|
|
154
|
+
setZoomState((prev) => clampTranslate({
|
|
155
|
+
...prev,
|
|
156
|
+
translateX: translateStart.current.x + dx,
|
|
157
|
+
translateY: translateStart.current.y + dy
|
|
158
|
+
}, imageRef.current));
|
|
159
|
+
}, [isDragging, enabled]);
|
|
160
|
+
const handlePointerUp = (0, react.useCallback)(() => {
|
|
161
|
+
setIsDragging(false);
|
|
162
|
+
}, []);
|
|
163
|
+
const handlePointerCancel = (0, react.useCallback)(() => {
|
|
164
|
+
setIsDragging(false);
|
|
165
|
+
didDrag.current = false;
|
|
166
|
+
lastPinchDistance.current = null;
|
|
167
|
+
}, []);
|
|
168
|
+
const handleTouchMove = (0, react.useCallback)((event) => {
|
|
169
|
+
if (!enabled || event.touches.length !== 2) {
|
|
170
|
+
lastPinchDistance.current = null;
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const touch1 = event.touches[0];
|
|
174
|
+
const touch2 = event.touches[1];
|
|
175
|
+
const distance = Math.hypot(touch1.clientX - touch2.clientX, touch1.clientY - touch2.clientY);
|
|
176
|
+
if (lastPinchDistance.current !== null) {
|
|
177
|
+
beginAdjust();
|
|
178
|
+
const delta = (distance - lastPinchDistance.current) * .01;
|
|
179
|
+
zoomAtPoint(delta, (touch1.clientX + touch2.clientX) / 2, (touch1.clientY + touch2.clientY) / 2);
|
|
180
|
+
}
|
|
181
|
+
lastPinchDistance.current = distance;
|
|
182
|
+
}, [
|
|
183
|
+
enabled,
|
|
184
|
+
zoomAtPoint,
|
|
185
|
+
beginAdjust
|
|
186
|
+
]);
|
|
187
|
+
const handleTouchEnd = (0, react.useCallback)(() => {
|
|
188
|
+
lastPinchDistance.current = null;
|
|
189
|
+
}, []);
|
|
190
|
+
const handleClick = (0, react.useCallback)((event) => {
|
|
191
|
+
if (!enabled || event.detail > 1) return;
|
|
192
|
+
if (didDrag.current) {
|
|
193
|
+
didDrag.current = false;
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const pointerType = lastPointerType.current;
|
|
197
|
+
lastPointerType.current = "mouse";
|
|
198
|
+
lastClickPointerType.current = pointerType;
|
|
199
|
+
if (pointerType === "touch") return;
|
|
200
|
+
toggleZoom();
|
|
201
|
+
}, [enabled, toggleZoom]);
|
|
202
|
+
const handleDoubleClick = (0, react.useCallback)(() => {
|
|
203
|
+
if (!enabled || lastClickPointerType.current !== "touch") return;
|
|
204
|
+
toggleZoom();
|
|
205
|
+
}, [enabled, toggleZoom]);
|
|
206
|
+
const getImageProps = (0, react.useCallback)(() => ({
|
|
207
|
+
ref: setImageRef,
|
|
208
|
+
style: { transform: `scale(${zoomState.scale}) translate(${zoomState.translateX / zoomState.scale}px, ${zoomState.translateY / zoomState.scale}px)` },
|
|
209
|
+
"data-zoom-enabled": enabled || void 0,
|
|
210
|
+
"data-zoomed": zoomState.isZoomed || void 0,
|
|
211
|
+
"data-dragging": isDragging || isAdjusting || void 0,
|
|
212
|
+
onPointerDown: handlePointerDown,
|
|
213
|
+
onPointerMove: handlePointerMove,
|
|
214
|
+
onPointerUp: handlePointerUp,
|
|
215
|
+
onPointerCancel: handlePointerCancel,
|
|
216
|
+
onLostPointerCapture: handlePointerUp,
|
|
217
|
+
onClick: handleClick,
|
|
218
|
+
onDoubleClick: handleDoubleClick,
|
|
219
|
+
onTouchMove: handleTouchMove,
|
|
220
|
+
onTouchEnd: handleTouchEnd
|
|
221
|
+
}), [
|
|
222
|
+
zoomState,
|
|
223
|
+
isDragging,
|
|
224
|
+
isAdjusting,
|
|
225
|
+
enabled,
|
|
226
|
+
setImageRef,
|
|
227
|
+
handlePointerDown,
|
|
228
|
+
handlePointerMove,
|
|
229
|
+
handlePointerUp,
|
|
230
|
+
handlePointerCancel,
|
|
231
|
+
handleClick,
|
|
232
|
+
handleDoubleClick,
|
|
233
|
+
handleTouchMove,
|
|
234
|
+
handleTouchEnd
|
|
235
|
+
]);
|
|
236
|
+
const publicZoomState = (0, react.useMemo)(() => ({
|
|
237
|
+
scale: zoomState.scale,
|
|
238
|
+
isZoomed: zoomState.isZoomed
|
|
239
|
+
}), [zoomState.scale, zoomState.isZoomed]);
|
|
240
|
+
return (0, react.useMemo)(() => ({
|
|
241
|
+
zoomState: publicZoomState,
|
|
242
|
+
toggleZoom,
|
|
243
|
+
resetZoom,
|
|
244
|
+
panZoom,
|
|
245
|
+
getImageProps
|
|
246
|
+
}), [
|
|
247
|
+
publicZoomState,
|
|
248
|
+
toggleZoom,
|
|
249
|
+
resetZoom,
|
|
250
|
+
panZoom,
|
|
251
|
+
getImageProps
|
|
252
|
+
]);
|
|
253
|
+
}
|
|
254
|
+
//#endregion
|
|
255
|
+
exports.useLightboxZoom = useLightboxZoom;
|
|
256
|
+
|
|
257
|
+
//# sourceMappingURL=use-lightbox-zoom.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-lightbox-zoom.cjs","names":["useState","useRef","useCallback","useMemo"],"sources":["../../src/hooks/use-lightbox-zoom.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\ninterface UseLightboxZoomInput {\n enabled: boolean;\n maxScale: number;\n currentIndex: number;\n}\n\ninterface ZoomState {\n scale: number;\n translateX: number;\n translateY: number;\n isZoomed: boolean;\n}\n\nconst INITIAL_ZOOM_STATE: ZoomState = {\n scale: 1,\n translateX: 0,\n translateY: 0,\n isZoomed: false,\n};\n\nfunction clampTranslate(state: ZoomState, image: HTMLImageElement | null): ZoomState {\n if (!image) {\n return state;\n }\n\n const maxX = (image.offsetWidth * (state.scale - 1)) / 2;\n const maxY = (image.offsetHeight * (state.scale - 1)) / 2;\n\n return {\n ...state,\n translateX: Math.max(-maxX, Math.min(maxX, state.translateX)),\n translateY: Math.max(-maxY, Math.min(maxY, state.translateY)),\n };\n}\n\nexport function useLightboxZoom({ enabled, maxScale, currentIndex }: UseLightboxZoomInput) {\n const [zoomState, setZoomState] = useState<ZoomState>(INITIAL_ZOOM_STATE);\n const [isDragging, setIsDragging] = useState(false);\n const imageRef = useRef<HTMLImageElement>(null);\n const isZoomedRef = useRef(false);\n const didDrag = useRef(false);\n const dragStart = useRef({ x: 0, y: 0 });\n const translateStart = useRef({ x: 0, y: 0 });\n const lastPinchDistance = useRef<number | null>(null);\n const lastPointerType = useRef<string>('mouse');\n const lastClickPointerType = useRef<string>('mouse');\n const [isAdjusting, setIsAdjusting] = useState(false);\n const adjustTimeout = useRef<number>(-1);\n\n useEffect(() => {\n isZoomedRef.current = zoomState.isZoomed;\n }, [zoomState.isZoomed]);\n\n const beginAdjust = useCallback(() => {\n setIsAdjusting(true);\n window.clearTimeout(adjustTimeout.current);\n adjustTimeout.current = window.setTimeout(() => setIsAdjusting(false), 120);\n }, []);\n\n const beginAdjustRef = useRef(beginAdjust);\n\n useEffect(() => {\n beginAdjustRef.current = beginAdjust;\n }, [beginAdjust]);\n\n useEffect(() => () => window.clearTimeout(adjustTimeout.current), []);\n\n const resetZoom = useCallback(() => {\n setZoomState(INITIAL_ZOOM_STATE);\n setIsDragging(false);\n }, []);\n\n const [prevIndex, setPrevIndex] = useState(currentIndex);\n const [prevEnabled, setPrevEnabled] = useState(enabled);\n\n // Reset during render rather than from an effect: the new slide is then painted at scale\n // 1 in the same commit instead of flashing the previous slide's zoom for one frame.\n //\n // Turning zoom off has to clear the state as well – the image loses its handlers, but a\n // lingering `isZoomed` keeps the carousel's `watchDrag` guard rejecting drags, so the\n // lightbox would silently stop being swipeable.\n if (currentIndex !== prevIndex || enabled !== prevEnabled) {\n setPrevIndex(currentIndex);\n setPrevEnabled(enabled);\n\n if (currentIndex !== prevIndex || !enabled) {\n setZoomState(INITIAL_ZOOM_STATE);\n setIsDragging(false);\n }\n }\n\n useEffect(() => {\n if (!enabled) {\n lastPinchDistance.current = null;\n didDrag.current = false;\n }\n }, [enabled]);\n\n const toggleZoom = useCallback(() => {\n if (!enabled) {\n return;\n }\n setZoomState((prev) =>\n prev.isZoomed\n ? INITIAL_ZOOM_STATE\n : { scale: Math.min(2, maxScale), translateX: 0, translateY: 0, isZoomed: true }\n );\n }, [enabled, maxScale]);\n\n const zoomAtPoint = useCallback(\n (deltaScale: number, clientX?: number, clientY?: number) => {\n setZoomState((prev) => {\n const nextScale = Math.max(1, Math.min(maxScale, prev.scale + deltaScale));\n if (nextScale === 1) {\n return INITIAL_ZOOM_STATE;\n }\n\n const image = imageRef.current;\n let translateX = prev.translateX;\n let translateY = prev.translateY;\n\n if (image && clientX !== undefined && clientY !== undefined) {\n const rect = image.getBoundingClientRect();\n const scaleRatio = nextScale / prev.scale;\n const offsetX = clientX - (rect.left + rect.width / 2) + prev.translateX;\n const offsetY = clientY - (rect.top + rect.height / 2) + prev.translateY;\n translateX = offsetX * (1 - scaleRatio) + prev.translateX * scaleRatio;\n translateY = offsetY * (1 - scaleRatio) + prev.translateY * scaleRatio;\n }\n\n return clampTranslate({ scale: nextScale, translateX, translateY, isZoomed: true }, image);\n });\n },\n [maxScale]\n );\n\n const panZoom = useCallback((deltaX: number, deltaY: number) => {\n if (!isZoomedRef.current) {\n return false;\n }\n setZoomState((prev) =>\n clampTranslate(\n { ...prev, translateX: prev.translateX + deltaX, translateY: prev.translateY + deltaY },\n imageRef.current\n )\n );\n return true;\n }, []);\n\n const zoomAtPointRef = useRef(zoomAtPoint);\n\n useEffect(() => {\n zoomAtPointRef.current = zoomAtPoint;\n }, [zoomAtPoint]);\n\n const handleNativeWheel = useRef((event: WheelEvent) => {\n // Horizontal trackpad gestures report deltaY === 0 – zooming on those would both\n // hijack the gesture and pick a direction at random.\n if (event.deltaY === 0) {\n return;\n }\n\n event.preventDefault();\n beginAdjustRef.current();\n zoomAtPointRef.current(event.deltaY > 0 ? -0.2 : 0.2, event.clientX, event.clientY);\n });\n\n const setImageRef = useCallback((node: HTMLImageElement | null) => {\n imageRef.current?.removeEventListener('wheel', handleNativeWheel.current);\n imageRef.current = node;\n node?.addEventListener('wheel', handleNativeWheel.current, { passive: false });\n }, []);\n\n const handlePointerDown = useCallback(\n (event: React.PointerEvent) => {\n lastPointerType.current = event.pointerType;\n\n if (!zoomState.isZoomed || !enabled) {\n return;\n }\n setIsDragging(true);\n didDrag.current = false;\n dragStart.current = { x: event.clientX, y: event.clientY };\n translateStart.current = { x: zoomState.translateX, y: zoomState.translateY };\n const target = event.target as HTMLElement;\n if (typeof target?.setPointerCapture === 'function') {\n target.setPointerCapture(event.pointerId);\n }\n },\n [zoomState.isZoomed, zoomState.translateX, zoomState.translateY, enabled]\n );\n\n const handlePointerMove = useCallback(\n (event: React.PointerEvent) => {\n if (!isDragging || !enabled) {\n return;\n }\n const dx = event.clientX - dragStart.current.x;\n const dy = event.clientY - dragStart.current.y;\n if (Math.abs(dx) > 3 || Math.abs(dy) > 3) {\n didDrag.current = true;\n }\n setZoomState((prev) =>\n clampTranslate(\n {\n ...prev,\n translateX: translateStart.current.x + dx,\n translateY: translateStart.current.y + dy,\n },\n imageRef.current\n )\n );\n },\n [isDragging, enabled]\n );\n\n const handlePointerUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n const handlePointerCancel = useCallback(() => {\n setIsDragging(false);\n didDrag.current = false;\n lastPinchDistance.current = null;\n }, []);\n\n const handleTouchMove = useCallback(\n (event: React.TouchEvent) => {\n if (!enabled || event.touches.length !== 2) {\n lastPinchDistance.current = null;\n return;\n }\n const touch1 = event.touches[0];\n const touch2 = event.touches[1];\n const distance = Math.hypot(touch1.clientX - touch2.clientX, touch1.clientY - touch2.clientY);\n\n if (lastPinchDistance.current !== null) {\n beginAdjust();\n const delta = (distance - lastPinchDistance.current) * 0.01;\n zoomAtPoint(\n delta,\n (touch1.clientX + touch2.clientX) / 2,\n (touch1.clientY + touch2.clientY) / 2\n );\n }\n lastPinchDistance.current = distance;\n },\n [enabled, zoomAtPoint, beginAdjust]\n );\n\n const handleTouchEnd = useCallback(() => {\n lastPinchDistance.current = null;\n }, []);\n\n const handleClick = useCallback(\n (event: React.MouseEvent) => {\n if (!enabled || event.detail > 1) {\n return;\n }\n if (didDrag.current) {\n didDrag.current = false;\n return;\n }\n\n // Touch taps are handled by the carousel (swipe) and by double-tap to zoom –\n // reacting to the synthetic click as well would fight with both. This checks the\n // input that produced the click rather than whether the device supports touch, so\n // a mouse still zooms on a touchscreen laptop. The recorded type is consumed here\n // so a later click without a preceding pointerdown is not treated as a touch.\n const pointerType = lastPointerType.current;\n lastPointerType.current = 'mouse';\n lastClickPointerType.current = pointerType;\n\n if (pointerType === 'touch') {\n return;\n }\n\n toggleZoom();\n },\n [enabled, toggleZoom]\n );\n\n const handleDoubleClick = useCallback(() => {\n if (!enabled || lastClickPointerType.current !== 'touch') {\n return;\n }\n\n toggleZoom();\n }, [enabled, toggleZoom]);\n\n const getImageProps = useCallback(\n () => ({\n ref: setImageRef,\n style: {\n transform: `scale(${zoomState.scale}) translate(${zoomState.translateX / zoomState.scale}px, ${zoomState.translateY / zoomState.scale}px)`,\n },\n 'data-zoom-enabled': enabled || undefined,\n 'data-zoomed': zoomState.isZoomed || undefined,\n 'data-dragging': isDragging || isAdjusting || undefined,\n onPointerDown: handlePointerDown,\n onPointerMove: handlePointerMove,\n onPointerUp: handlePointerUp,\n onPointerCancel: handlePointerCancel,\n onLostPointerCapture: handlePointerUp,\n onClick: handleClick,\n onDoubleClick: handleDoubleClick,\n onTouchMove: handleTouchMove,\n onTouchEnd: handleTouchEnd,\n }),\n [\n zoomState,\n isDragging,\n isAdjusting,\n enabled,\n setImageRef,\n handlePointerDown,\n handlePointerMove,\n handlePointerUp,\n handlePointerCancel,\n handleClick,\n handleDoubleClick,\n handleTouchMove,\n handleTouchEnd,\n ]\n );\n\n // Both objects are memoized: the lightbox context is built from them, and returning fresh\n // objects on every render would make that context change identity on every root render,\n // re-rendering every slide, thumbnail and custom render function along with it.\n const publicZoomState = useMemo(\n () => ({ scale: zoomState.scale, isZoomed: zoomState.isZoomed }),\n [zoomState.scale, zoomState.isZoomed]\n );\n\n return useMemo(\n () => ({\n zoomState: publicZoomState,\n toggleZoom,\n resetZoom,\n panZoom,\n getImageProps,\n }),\n [publicZoomState, toggleZoom, resetZoom, panZoom, getImageProps]\n );\n}\n"],"mappings":"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"}
|
package/cjs/index.cjs
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_lightbox_store = require("./lightbox.store.cjs");
|
|
3
|
+
const require_default_labels = require("./default-labels.cjs");
|
|
4
|
+
const require_LightboxCaption = require("./LightboxCaption/LightboxCaption.cjs");
|
|
5
|
+
const require_LightboxCloseButton = require("./LightboxCloseButton/LightboxCloseButton.cjs");
|
|
6
|
+
const require_LightboxNavigation = require("./LightboxNavigation/LightboxNavigation.cjs");
|
|
7
|
+
const require_LightboxProvider = require("./LightboxProvider/LightboxProvider.cjs");
|
|
8
|
+
const require_LightboxRoot = require("./LightboxRoot/LightboxRoot.cjs");
|
|
9
|
+
const require_LightboxSlide = require("./LightboxSlide/LightboxSlide.cjs");
|
|
10
|
+
const require_LightboxSlides = require("./LightboxSlides/LightboxSlides.cjs");
|
|
11
|
+
const require_LightboxThumbnails = require("./LightboxThumbnails/LightboxThumbnails.cjs");
|
|
12
|
+
const require_toolbar_items = require("./LightboxToolbar/toolbar-items.cjs");
|
|
13
|
+
const require_LightboxToolbar = require("./LightboxToolbar/LightboxToolbar.cjs");
|
|
14
|
+
const require_Lightbox = require("./Lightbox.cjs");
|
|
15
|
+
exports.DEFAULT_LABELS = require_default_labels.DEFAULT_LABELS;
|
|
16
|
+
exports.Lightbox = require_Lightbox.Lightbox;
|
|
17
|
+
exports.LightboxCaption = require_LightboxCaption.LightboxCaption;
|
|
18
|
+
exports.LightboxCloseButton = require_LightboxCloseButton.LightboxCloseButton;
|
|
19
|
+
exports.LightboxNavigation = require_LightboxNavigation.LightboxNavigation;
|
|
20
|
+
exports.LightboxProviderComponent = require_LightboxProvider.LightboxProviderComponent;
|
|
21
|
+
exports.LightboxRoot = require_LightboxRoot.LightboxRoot;
|
|
22
|
+
exports.LightboxSlide = require_LightboxSlide.LightboxSlide;
|
|
23
|
+
exports.LightboxSlides = require_LightboxSlides.LightboxSlides;
|
|
24
|
+
exports.LightboxThumbnails = require_LightboxThumbnails.LightboxThumbnails;
|
|
25
|
+
exports.LightboxToolbar = require_LightboxToolbar.LightboxToolbar;
|
|
26
|
+
exports.createCloseToolbarItem = require_toolbar_items.createCloseToolbarItem;
|
|
27
|
+
exports.createDownloadToolbarItem = require_toolbar_items.createDownloadToolbarItem;
|
|
28
|
+
exports.createFullscreenToolbarItem = require_toolbar_items.createFullscreenToolbarItem;
|
|
29
|
+
exports.createLightbox = require_lightbox_store.createLightbox;
|
|
30
|
+
exports.createLightboxStore = require_lightbox_store.createLightboxStore;
|
|
31
|
+
exports.createThumbnailsToolbarItem = require_toolbar_items.createThumbnailsToolbarItem;
|
|
32
|
+
exports.lightbox = require_lightbox_store.lightbox;
|
|
33
|
+
exports.lightboxStore = require_lightbox_store.lightboxStore;
|
|
34
|
+
exports.useLightboxStore = require_lightbox_store.useLightboxStore;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
//#region packages/@mantine/lightbox/src/lightbox.context.ts
|
|
3
|
+
const [LightboxContextProvider, useLightboxContext] = (0, require("@mantine/core").createSafeContext)("Lightbox component was not found in tree");
|
|
4
|
+
//#endregion
|
|
5
|
+
exports.LightboxContextProvider = LightboxContextProvider;
|
|
6
|
+
exports.useLightboxContext = useLightboxContext;
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=lightbox.context.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lightbox.context.cjs","names":["createSafeContext"],"sources":["../src/lightbox.context.ts"],"sourcesContent":["import type { EmblaCarouselType } from 'embla-carousel';\nimport { createSafeContext, GetStylesApi } from '@mantine/core';\nimport type { LightboxLabels, LightboxSlideData } from './lightbox.types';\nimport type { LightboxRootFactory } from './LightboxRoot/LightboxRoot';\n\nexport interface LightboxContextValue {\n getStyles: GetStylesApi<LightboxRootFactory>;\n labels: LightboxLabels;\n opened: boolean;\n slides: LightboxSlideData[];\n currentIndex: number;\n setIndex: (index: number) => void;\n next: () => void;\n prev: () => void;\n embla: EmblaCarouselType | null;\n emblaRef: React.RefCallback<HTMLDivElement> | null;\n withZoom: boolean;\n withThumbnails: boolean;\n withFullscreen: boolean;\n withDownload: boolean;\n thumbnailsVisible: boolean;\n toggleThumbnails: () => void;\n isFullscreen: boolean;\n toggleFullscreen: () => void;\n zoomState: { scale: number; isZoomed: boolean };\n toggleZoom: () => void;\n getImageZoomProps: () => Record<string, any>;\n onClose: () => void;\n loop: boolean;\n closeOnClickOutside: boolean;\n closeOnSwipeDown: boolean;\n transitionDuration: number;\n}\n\nexport const [LightboxContextProvider, useLightboxContext] =\n createSafeContext<LightboxContextValue>('Lightbox component was not found in tree');\n"],"mappings":";;AAkCA,MAAa,CAAC,yBAAyB,uBAAA,0BACrCA,CAAAA,CAAAA,kBAAAA,CAAwC,0CAA0C"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
let _mantine_store = require("@mantine/store");
|
|
3
|
+
//#region packages/@mantine/lightbox/src/lightbox.store.ts
|
|
4
|
+
/** Creates a new lightbox store, use to run multiple independent lightboxes */
|
|
5
|
+
const createLightboxStore = () => (0, _mantine_store.createStore)({
|
|
6
|
+
opened: false,
|
|
7
|
+
slides: [],
|
|
8
|
+
currentIndex: 0,
|
|
9
|
+
loop: false
|
|
10
|
+
});
|
|
11
|
+
/** Subscribes to the given lightbox store and returns its current state */
|
|
12
|
+
const useLightboxStore = (store) => (0, _mantine_store.useStore)(store);
|
|
13
|
+
function clampIndex(index, slidesCount) {
|
|
14
|
+
return Math.max(0, Math.min(Number.isFinite(index) ? Math.round(index) : 0, Math.max(0, slidesCount - 1)));
|
|
15
|
+
}
|
|
16
|
+
function updateLightboxStateAction(update, store) {
|
|
17
|
+
const state = store.getState();
|
|
18
|
+
store.setState({
|
|
19
|
+
...state,
|
|
20
|
+
...update(state)
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function openLightboxAction(payload, store) {
|
|
24
|
+
updateLightboxStateAction(() => ({
|
|
25
|
+
opened: true,
|
|
26
|
+
slides: payload.slides,
|
|
27
|
+
currentIndex: clampIndex(payload.startIndex ?? 0, payload.slides.length)
|
|
28
|
+
}), store);
|
|
29
|
+
}
|
|
30
|
+
function closeLightboxAction(store) {
|
|
31
|
+
updateLightboxStateAction(() => ({ opened: false }), store);
|
|
32
|
+
}
|
|
33
|
+
function nextLightboxAction(store) {
|
|
34
|
+
updateLightboxStateAction((state) => {
|
|
35
|
+
const nextIndex = state.currentIndex + 1;
|
|
36
|
+
if (nextIndex < state.slides.length) return { currentIndex: nextIndex };
|
|
37
|
+
return { currentIndex: state.loop && state.slides.length > 0 ? 0 : state.currentIndex };
|
|
38
|
+
}, store);
|
|
39
|
+
}
|
|
40
|
+
function prevLightboxAction(store) {
|
|
41
|
+
updateLightboxStateAction((state) => {
|
|
42
|
+
const prevIndex = state.currentIndex - 1;
|
|
43
|
+
if (prevIndex >= 0) return { currentIndex: prevIndex };
|
|
44
|
+
return { currentIndex: state.loop && state.slides.length > 0 ? state.slides.length - 1 : 0 };
|
|
45
|
+
}, store);
|
|
46
|
+
}
|
|
47
|
+
function setLightboxIndexAction(index, store) {
|
|
48
|
+
updateLightboxStateAction((state) => ({ currentIndex: clampIndex(index, state.slides.length) }), store);
|
|
49
|
+
}
|
|
50
|
+
const lightboxActions = {
|
|
51
|
+
open: openLightboxAction,
|
|
52
|
+
close: closeLightboxAction,
|
|
53
|
+
next: nextLightboxAction,
|
|
54
|
+
prev: prevLightboxAction,
|
|
55
|
+
setIndex: setLightboxIndexAction,
|
|
56
|
+
updateState: updateLightboxStateAction
|
|
57
|
+
};
|
|
58
|
+
/** Creates an isolated store and a set of actions bound to it, use to run multiple independent lightboxes */
|
|
59
|
+
function createLightbox() {
|
|
60
|
+
const store = createLightboxStore();
|
|
61
|
+
return [store, {
|
|
62
|
+
/** Opens the lightbox with the given slides, optionally at the given index */
|
|
63
|
+
open: (payload) => openLightboxAction(payload, store),
|
|
64
|
+
/** Closes the lightbox */
|
|
65
|
+
close: () => closeLightboxAction(store),
|
|
66
|
+
/** Navigates to the next slide */
|
|
67
|
+
next: () => nextLightboxAction(store),
|
|
68
|
+
/** Navigates to the previous slide */
|
|
69
|
+
prev: () => prevLightboxAction(store),
|
|
70
|
+
/** Sets the current slide index, the value is clamped to the slides range */
|
|
71
|
+
setIndex: (index) => setLightboxIndexAction(index, store)
|
|
72
|
+
}];
|
|
73
|
+
}
|
|
74
|
+
/** Default lightbox store (`lightboxStore`) and actions bound to it (`lightbox`), used by `Lightbox.Provider` and static `Lightbox.open/close/next/prev/setIndex` methods */
|
|
75
|
+
const [lightboxStore, lightbox] = createLightbox();
|
|
76
|
+
//#endregion
|
|
77
|
+
exports.closeLightboxAction = closeLightboxAction;
|
|
78
|
+
exports.createLightbox = createLightbox;
|
|
79
|
+
exports.createLightboxStore = createLightboxStore;
|
|
80
|
+
exports.lightbox = lightbox;
|
|
81
|
+
exports.lightboxActions = lightboxActions;
|
|
82
|
+
exports.lightboxStore = lightboxStore;
|
|
83
|
+
exports.nextLightboxAction = nextLightboxAction;
|
|
84
|
+
exports.openLightboxAction = openLightboxAction;
|
|
85
|
+
exports.prevLightboxAction = prevLightboxAction;
|
|
86
|
+
exports.setLightboxIndexAction = setLightboxIndexAction;
|
|
87
|
+
exports.updateLightboxStateAction = updateLightboxStateAction;
|
|
88
|
+
exports.useLightboxStore = useLightboxStore;
|
|
89
|
+
|
|
90
|
+
//# sourceMappingURL=lightbox.store.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lightbox.store.cjs","names":["createStore","useStore"],"sources":["../src/lightbox.store.ts"],"sourcesContent":["import { createStore, MantineStore, useStore } from '@mantine/store';\nimport type { LightboxSlideData } from './lightbox.types';\n\nexport interface LightboxState {\n /** Controls whether the lightbox is opened */\n opened: boolean;\n\n /** Array of slide data objects */\n slides: LightboxSlideData[];\n\n /** Index of the current slide */\n currentIndex: number;\n\n /** Determines whether `next` and `prev` actions wrap around, synced from the `loop` prop of `Lightbox.Provider` */\n loop: boolean;\n}\n\nexport type LightboxStore = MantineStore<LightboxState>;\n\n/** Creates a new lightbox store, use to run multiple independent lightboxes */\nexport const createLightboxStore = () =>\n createStore<LightboxState>({\n opened: false,\n slides: [],\n currentIndex: 0,\n loop: false,\n });\n\n/** Subscribes to the given lightbox store and returns its current state */\nexport const useLightboxStore = (store: LightboxStore) => useStore(store);\n\nfunction clampIndex(index: number, slidesCount: number) {\n const normalized = Number.isFinite(index) ? Math.round(index) : 0;\n return Math.max(0, Math.min(normalized, Math.max(0, slidesCount - 1)));\n}\n\nexport function updateLightboxStateAction(\n update: (state: LightboxState) => Partial<LightboxState>,\n store: LightboxStore\n) {\n const state = store.getState();\n store.setState({ ...state, ...update(state) });\n}\n\nexport function openLightboxAction(\n payload: { slides: LightboxSlideData[]; startIndex?: number },\n store: LightboxStore\n) {\n updateLightboxStateAction(\n () => ({\n opened: true,\n slides: payload.slides,\n currentIndex: clampIndex(payload.startIndex ?? 0, payload.slides.length),\n }),\n store\n );\n}\n\nexport function closeLightboxAction(store: LightboxStore) {\n updateLightboxStateAction(() => ({ opened: false }), store);\n}\n\nexport function nextLightboxAction(store: LightboxStore) {\n updateLightboxStateAction((state) => {\n const nextIndex = state.currentIndex + 1;\n\n if (nextIndex < state.slides.length) {\n return { currentIndex: nextIndex };\n }\n\n return { currentIndex: state.loop && state.slides.length > 0 ? 0 : state.currentIndex };\n }, store);\n}\n\nexport function prevLightboxAction(store: LightboxStore) {\n updateLightboxStateAction((state) => {\n const prevIndex = state.currentIndex - 1;\n\n if (prevIndex >= 0) {\n return { currentIndex: prevIndex };\n }\n\n return {\n currentIndex: state.loop && state.slides.length > 0 ? state.slides.length - 1 : 0,\n };\n }, store);\n}\n\nexport function setLightboxIndexAction(index: number, store: LightboxStore) {\n updateLightboxStateAction(\n (state) => ({ currentIndex: clampIndex(index, state.slides.length) }),\n store\n );\n}\n\nexport const lightboxActions = {\n open: openLightboxAction,\n close: closeLightboxAction,\n next: nextLightboxAction,\n prev: prevLightboxAction,\n setIndex: setLightboxIndexAction,\n updateState: updateLightboxStateAction,\n};\n\n/** Creates an isolated store and a set of actions bound to it, use to run multiple independent lightboxes */\nexport function createLightbox() {\n const store = createLightboxStore();\n const actions = {\n /** Opens the lightbox with the given slides, optionally at the given index */\n open: (payload: { slides: LightboxSlideData[]; startIndex?: number }) =>\n openLightboxAction(payload, store),\n\n /** Closes the lightbox */\n close: () => closeLightboxAction(store),\n\n /** Navigates to the next slide */\n next: () => nextLightboxAction(store),\n\n /** Navigates to the previous slide */\n prev: () => prevLightboxAction(store),\n\n /** Sets the current slide index, the value is clamped to the slides range */\n setIndex: (index: number) => setLightboxIndexAction(index, store),\n };\n\n return [store, actions] as const;\n}\n\n/** Default lightbox store (`lightboxStore`) and actions bound to it (`lightbox`), used by `Lightbox.Provider` and static `Lightbox.open/close/next/prev/setIndex` methods */\nexport const [lightboxStore, lightbox] = createLightbox();\n"],"mappings":";;;;AAoBA,MAAa,6BAAA,GACXA,eAAAA,YAAAA,CAA2B;CACzB,QAAQ;CACR,QAAQ,CAAC;CACT,cAAc;CACd,MAAM;AACR,CAAC;;AAGH,MAAa,oBAAoB,WAAA,GAAyBC,eAAAA,SAAAA,CAAS,KAAK;AAExE,SAAS,WAAW,OAAe,aAAqB;CAEtD,OAAO,KAAK,IAAI,GAAG,KAAK,IADL,OAAO,SAAS,KAAK,IAAI,KAAK,MAAM,KAAK,IAAI,GACxB,KAAK,IAAI,GAAG,cAAc,CAAC,CAAC,CAAC;AACvE;AAEA,SAAgB,0BACd,QACA,OACA;CACA,MAAM,QAAQ,MAAM,SAAS;CAC7B,MAAM,SAAS;EAAE,GAAG;EAAO,GAAG,OAAO,KAAK;CAAE,CAAC;AAC/C;AAEA,SAAgB,mBACd,SACA,OACA;CACA,iCACS;EACL,QAAQ;EACR,QAAQ,QAAQ;EAChB,cAAc,WAAW,QAAQ,cAAc,GAAG,QAAQ,OAAO,MAAM;CACzE,IACA,KACF;AACF;AAEA,SAAgB,oBAAoB,OAAsB;CACxD,iCAAiC,EAAE,QAAQ,MAAM,IAAI,KAAK;AAC5D;AAEA,SAAgB,mBAAmB,OAAsB;CACvD,2BAA2B,UAAU;EACnC,MAAM,YAAY,MAAM,eAAe;EAEvC,IAAI,YAAY,MAAM,OAAO,QAC3B,OAAO,EAAE,cAAc,UAAU;EAGnC,OAAO,EAAE,cAAc,MAAM,QAAQ,MAAM,OAAO,SAAS,IAAI,IAAI,MAAM,aAAa;CACxF,GAAG,KAAK;AACV;AAEA,SAAgB,mBAAmB,OAAsB;CACvD,2BAA2B,UAAU;EACnC,MAAM,YAAY,MAAM,eAAe;EAEvC,IAAI,aAAa,GACf,OAAO,EAAE,cAAc,UAAU;EAGnC,OAAO,EACL,cAAc,MAAM,QAAQ,MAAM,OAAO,SAAS,IAAI,MAAM,OAAO,SAAS,IAAI,EAClF;CACF,GAAG,KAAK;AACV;AAEA,SAAgB,uBAAuB,OAAe,OAAsB;CAC1E,2BACG,WAAW,EAAE,cAAc,WAAW,OAAO,MAAM,OAAO,MAAM,EAAE,IACnE,KACF;AACF;AAEA,MAAa,kBAAkB;CAC7B,MAAM;CACN,OAAO;CACP,MAAM;CACN,MAAM;CACN,UAAU;CACV,aAAa;AACf;;AAGA,SAAgB,iBAAiB;CAC/B,MAAM,QAAQ,oBAAoB;CAmBlC,OAAO,CAAC,OAAO;;EAhBb,OAAO,YACL,mBAAmB,SAAS,KAAK;;EAGnC,aAAa,oBAAoB,KAAK;;EAGtC,YAAY,mBAAmB,KAAK;;EAGpC,YAAY,mBAAmB,KAAK;;EAGpC,WAAW,UAAkB,uBAAuB,OAAO,KAAK;CAG7C,CAAC;AACxB;;AAGA,MAAa,CAAC,eAAe,YAAY,eAAe"}
|
package/esm/Lightbox.mjs
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { lightbox } from "./lightbox.store.mjs";
|
|
3
|
+
import Lightbox_module_default from "./Lightbox.module.mjs";
|
|
4
|
+
import { LightboxCaption } from "./LightboxCaption/LightboxCaption.mjs";
|
|
5
|
+
import { LightboxCloseButton } from "./LightboxCloseButton/LightboxCloseButton.mjs";
|
|
6
|
+
import { LightboxNavigation } from "./LightboxNavigation/LightboxNavigation.mjs";
|
|
7
|
+
import { LightboxProviderComponent } from "./LightboxProvider/LightboxProvider.mjs";
|
|
8
|
+
import { LightboxRoot, lightboxRootDefaultProps } from "./LightboxRoot/LightboxRoot.mjs";
|
|
9
|
+
import { LightboxSlide } from "./LightboxSlide/LightboxSlide.mjs";
|
|
10
|
+
import { LightboxSlides } from "./LightboxSlides/LightboxSlides.mjs";
|
|
11
|
+
import { LightboxThumbnails } from "./LightboxThumbnails/LightboxThumbnails.mjs";
|
|
12
|
+
import { LightboxToolbar } from "./LightboxToolbar/LightboxToolbar.mjs";
|
|
13
|
+
import { factory, useProps } from "@mantine/core";
|
|
14
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
+
//#region packages/@mantine/lightbox/src/Lightbox.tsx
|
|
16
|
+
const defaultProps = {
|
|
17
|
+
...lightboxRootDefaultProps,
|
|
18
|
+
withNavigation: true
|
|
19
|
+
};
|
|
20
|
+
const Lightbox = factory((_props) => {
|
|
21
|
+
const { slides, toolbarItems, withNavigation, children, ...others } = useProps("Lightbox", defaultProps, _props);
|
|
22
|
+
return /* @__PURE__ */ jsx(LightboxRoot, {
|
|
23
|
+
...others,
|
|
24
|
+
slides,
|
|
25
|
+
children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
26
|
+
/* @__PURE__ */ jsx(LightboxToolbar, { toolbarItems }),
|
|
27
|
+
/* @__PURE__ */ jsx(LightboxSlides, { children: slides.map((slide, index) => /* @__PURE__ */ jsx(LightboxSlide, {
|
|
28
|
+
slide,
|
|
29
|
+
index
|
|
30
|
+
}, index)) }),
|
|
31
|
+
withNavigation && /* @__PURE__ */ jsx(LightboxNavigation, {}),
|
|
32
|
+
/* @__PURE__ */ jsx(LightboxCaption, {}),
|
|
33
|
+
/* @__PURE__ */ jsx(LightboxThumbnails, {})
|
|
34
|
+
] })
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
Lightbox.classes = Lightbox_module_default;
|
|
38
|
+
Lightbox.displayName = "@mantine/lightbox/Lightbox";
|
|
39
|
+
Lightbox.Root = LightboxRoot;
|
|
40
|
+
Lightbox.Toolbar = LightboxToolbar;
|
|
41
|
+
Lightbox.Slides = LightboxSlides;
|
|
42
|
+
Lightbox.Slide = LightboxSlide;
|
|
43
|
+
Lightbox.Thumbnails = LightboxThumbnails;
|
|
44
|
+
Lightbox.Navigation = LightboxNavigation;
|
|
45
|
+
Lightbox.Caption = LightboxCaption;
|
|
46
|
+
Lightbox.CloseButton = LightboxCloseButton;
|
|
47
|
+
Lightbox.Provider = LightboxProviderComponent;
|
|
48
|
+
Lightbox.open = lightbox.open;
|
|
49
|
+
Lightbox.close = lightbox.close;
|
|
50
|
+
Lightbox.next = lightbox.next;
|
|
51
|
+
Lightbox.prev = lightbox.prev;
|
|
52
|
+
Lightbox.setIndex = lightbox.setIndex;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { Lightbox };
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=Lightbox.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Lightbox.mjs","names":["classes"],"sources":["../src/Lightbox.tsx"],"sourcesContent":["import { factory, Factory, useProps } from '@mantine/core';\nimport { lightbox } from './lightbox.store';\nimport type { ToolbarItems } from './lightbox.types';\nimport { LightboxCaption } from './LightboxCaption/LightboxCaption';\nimport { LightboxCloseButton } from './LightboxCloseButton/LightboxCloseButton';\nimport { LightboxNavigation } from './LightboxNavigation/LightboxNavigation';\nimport { LightboxProviderComponent } from './LightboxProvider/LightboxProvider';\nimport {\n LightboxRoot,\n lightboxRootDefaultProps,\n LightboxRootProps,\n LightboxRootStylesNames,\n} from './LightboxRoot/LightboxRoot';\nimport { LightboxSlide } from './LightboxSlide/LightboxSlide';\nimport { LightboxSlides } from './LightboxSlides/LightboxSlides';\nimport { LightboxThumbnails } from './LightboxThumbnails/LightboxThumbnails';\nimport { LightboxToolbar } from './LightboxToolbar/LightboxToolbar';\nimport classes from './Lightbox.module.css';\n\nexport type LightboxStylesNames = LightboxRootStylesNames;\n\nexport interface LightboxProps extends Omit<LightboxRootProps, 'children'> {\n /** Custom toolbar items, overrides default toolbar. Can be a function that receives the current lightbox state and handlers. */\n toolbarItems?: ToolbarItems;\n\n /** Shows previous/next navigation arrows @default true */\n withNavigation?: boolean;\n\n /** Custom lightbox layout, overrides the default layout built from compound components */\n children?: React.ReactNode;\n}\n\nexport type LightboxFactory = Factory<{\n props: LightboxProps;\n ref: HTMLDivElement;\n stylesNames: LightboxStylesNames;\n staticComponents: {\n Root: typeof LightboxRoot;\n Toolbar: typeof LightboxToolbar;\n Slides: typeof LightboxSlides;\n Slide: typeof LightboxSlide;\n Thumbnails: typeof LightboxThumbnails;\n Navigation: typeof LightboxNavigation;\n Caption: typeof LightboxCaption;\n CloseButton: typeof LightboxCloseButton;\n Provider: typeof LightboxProviderComponent;\n open: typeof lightbox.open;\n close: typeof lightbox.close;\n next: typeof lightbox.next;\n prev: typeof lightbox.prev;\n setIndex: typeof lightbox.setIndex;\n };\n}>;\n\nconst defaultProps = {\n ...lightboxRootDefaultProps,\n withNavigation: true,\n} satisfies Partial<LightboxProps>;\n\nexport const Lightbox = factory<LightboxFactory>((_props) => {\n const props = useProps('Lightbox', defaultProps, _props);\n const { slides, toolbarItems, withNavigation, children, ...others } = props;\n\n return (\n <LightboxRoot {...others} slides={slides}>\n {children ?? (\n <>\n <LightboxToolbar toolbarItems={toolbarItems} />\n\n <LightboxSlides>\n {slides.map((slide, index) => (\n <LightboxSlide key={index} slide={slide} index={index} />\n ))}\n </LightboxSlides>\n\n {withNavigation && <LightboxNavigation />}\n <LightboxCaption />\n <LightboxThumbnails />\n </>\n )}\n </LightboxRoot>\n );\n});\n\nLightbox.classes = classes;\nLightbox.displayName = '@mantine/lightbox/Lightbox';\nLightbox.Root = LightboxRoot;\nLightbox.Toolbar = LightboxToolbar;\nLightbox.Slides = LightboxSlides;\nLightbox.Slide = LightboxSlide;\nLightbox.Thumbnails = LightboxThumbnails;\nLightbox.Navigation = LightboxNavigation;\nLightbox.Caption = LightboxCaption;\nLightbox.CloseButton = LightboxCloseButton;\nLightbox.Provider = LightboxProviderComponent;\nLightbox.open = lightbox.open;\nLightbox.close = lightbox.close;\nLightbox.next = lightbox.next;\nLightbox.prev = lightbox.prev;\nLightbox.setIndex = lightbox.setIndex;\n"],"mappings":";;;;;;;;;;;;;;;AAsDA,MAAM,eAAe;CACnB,GAAG;CACH,gBAAgB;AAClB;AAEA,MAAa,WAAW,SAA0B,WAAW;CAE3D,MAAM,EAAE,QAAQ,cAAc,gBAAgB,UAAU,GAAG,WAD7C,SAAS,YAAY,cAAc,MACyB;CAE1E,OACE,oBAAC,cAAD;EAAc,GAAI;EAAgB;EAC/B,UAAA,YACC,qBAAA,UAAA,EAAA,UAAA;GACE,oBAAC,iBAAD,EAA+B,aAAe,CAAA;GAE9C,oBAAC,gBAAD,EAAA,UACG,OAAO,KAAK,OAAO,UAClB,oBAAC,eAAD;IAAkC;IAAc;GAAQ,GAApC,KAAoC,CACzD,EACa,CAAA;GAEf,kBAAkB,oBAAC,oBAAD,CAAqB,CAAA;GACxC,oBAAC,iBAAD,CAAkB,CAAA;GAClB,oBAAC,oBAAD,CAAqB,CAAA;EACrB,EAAA,CAAA;CAEQ,CAAA;AAElB,CAAC;AAED,SAAS,UAAUA;AACnB,SAAS,cAAc;AACvB,SAAS,OAAO;AAChB,SAAS,UAAU;AACnB,SAAS,SAAS;AAClB,SAAS,QAAQ;AACjB,SAAS,aAAa;AACtB,SAAS,aAAa;AACtB,SAAS,UAAU;AACnB,SAAS,cAAc;AACvB,SAAS,WAAW;AACpB,SAAS,OAAO,SAAS;AACzB,SAAS,QAAQ,SAAS;AAC1B,SAAS,OAAO,SAAS;AACzB,SAAS,OAAO,SAAS;AACzB,SAAS,WAAW,SAAS"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
//#region packages/@mantine/lightbox/src/Lightbox.module.css
|
|
3
|
+
var Lightbox_module_default = {
|
|
4
|
+
"root": "m_4f1afa9a",
|
|
5
|
+
"overlay": "m_143cf98",
|
|
6
|
+
"content": "m_7b06bfc1",
|
|
7
|
+
"toolbar": "m_fe5b16c3",
|
|
8
|
+
"toolbarGroup": "m_9e01b17c",
|
|
9
|
+
"toolbarButton": "m_19d8cbd5",
|
|
10
|
+
"counter": "m_7b66e144",
|
|
11
|
+
"slides": "m_f5ce649a",
|
|
12
|
+
"slidesViewport": "m_7f838760",
|
|
13
|
+
"slidesContainer": "m_b5439507",
|
|
14
|
+
"slide": "m_9450faf9",
|
|
15
|
+
"slideImage": "m_e659b1e2",
|
|
16
|
+
"slideVideo": "m_e70f1d02",
|
|
17
|
+
"thumbnails": "m_411d1cbf",
|
|
18
|
+
"thumbnailsViewport": "m_3a7e4a85",
|
|
19
|
+
"thumbnailsContainer": "m_59a13682",
|
|
20
|
+
"thumbnail": "m_3be82a34",
|
|
21
|
+
"thumbnailImage": "m_fd95cf87",
|
|
22
|
+
"navigation": "m_15a759cc",
|
|
23
|
+
"navigationButton": "m_a5bee41e",
|
|
24
|
+
"caption": "m_633f252e",
|
|
25
|
+
"closeButton": "m_1ae53e92"
|
|
26
|
+
};
|
|
27
|
+
//#endregion
|
|
28
|
+
export { Lightbox_module_default as default };
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=Lightbox.module.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Lightbox.module.mjs","names":[],"sources":["../src/Lightbox.module.css"],"sourcesContent":[".root {\n --lightbox-transition-duration: 200ms;\n --lightbox-overlay-color: rgba(0, 0, 0, 0.9);\n --lightbox-z-index: 400;\n --lightbox-toolbar-height: 56px;\n --lightbox-thumbnails-height: 100px;\n\n display: contents;\n}\n\n.overlay {\n position: fixed;\n inset: 0;\n z-index: var(--lightbox-z-index);\n background-color: var(--lightbox-overlay-color);\n}\n\n.content {\n position: fixed;\n inset: 0;\n z-index: var(--lightbox-z-index);\n display: flex;\n flex-direction: column;\n color: var(--mantine-color-white);\n outline: none;\n}\n\n.toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n height: var(--lightbox-toolbar-height);\n padding: 0 var(--mantine-spacing-md);\n flex-shrink: 0;\n z-index: 1;\n}\n\n.toolbarGroup {\n display: flex;\n align-items: center;\n gap: var(--mantine-spacing-xs);\n}\n\n.toolbarButton {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border-radius: var(--mantine-radius-sm);\n color: var(--mantine-color-white);\n opacity: 0.8;\n transition:\n opacity var(--lightbox-transition-duration) ease,\n background-color var(--lightbox-transition-duration) ease;\n\n @mixin hover {\n opacity: 1;\n background-color: rgba(255, 255, 255, 0.1);\n }\n}\n\n.counter {\n font-size: var(--mantine-font-size-sm);\n color: var(--mantine-color-white);\n opacity: 0.8;\n user-select: none;\n}\n\n.slides {\n flex: 1;\n position: relative;\n overflow: hidden;\n min-height: 0;\n}\n\n.slidesViewport {\n height: 100%;\n overflow: hidden;\n}\n\n.slidesContainer {\n display: flex;\n height: 100%;\n}\n\n.slide {\n position: relative;\n flex: 0 0 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--mantine-spacing-md);\n min-width: 0;\n}\n\n.slideImage {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n user-select: none;\n -webkit-user-drag: none;\n transition: transform var(--lightbox-transition-duration) ease;\n\n &[data-zoom-enabled] {\n touch-action: none;\n }\n\n &[data-zoomed] {\n cursor: grab;\n\n &:active {\n cursor: grabbing;\n }\n }\n\n &[data-dragging] {\n transition: none;\n }\n\n &[data-zoom-enabled]:not([data-zoomed]) {\n cursor: zoom-in;\n }\n}\n\n.slideVideo {\n width: 100%;\n height: 100%;\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n}\n\n.thumbnails {\n display: block;\n padding: 0 var(--mantine-spacing-md);\n flex-shrink: 0;\n overflow: hidden;\n}\n\n.thumbnailsViewport {\n width: fit-content;\n max-width: 100%;\n margin-inline: auto;\n height: var(--lightbox-thumbnails-height);\n overflow: hidden;\n}\n\n.thumbnailsContainer {\n display: flex;\n gap: var(--mantine-spacing-xs);\n height: 100%;\n align-items: center;\n}\n\n.thumbnail {\n flex: 0 0 auto;\n width: 64px;\n height: 64px;\n border-radius: var(--mantine-radius-sm);\n overflow: hidden;\n opacity: 0.5;\n border: 2px solid transparent;\n cursor: pointer;\n transition:\n opacity var(--lightbox-transition-duration) ease,\n border-color var(--lightbox-transition-duration) ease;\n padding: 0;\n background: none;\n\n @mixin hover {\n opacity: 0.8;\n }\n\n &[data-active] {\n opacity: 1;\n border-color: var(--mantine-primary-color-filled);\n }\n}\n\n.thumbnailImage {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.navigation {\n position: absolute;\n top: 50%;\n display: flex;\n justify-content: space-between;\n width: 100%;\n padding: 0 var(--mantine-spacing-md);\n pointer-events: none;\n transform: translateY(-50%);\n z-index: 1;\n}\n\n.navigationButton {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n color: var(--mantine-color-white);\n pointer-events: all;\n opacity: 0.7;\n transition: opacity var(--lightbox-transition-duration) ease;\n\n @mixin hover {\n opacity: 1;\n }\n\n &[data-inactive] {\n opacity: 0.3;\n pointer-events: none;\n }\n}\n\n.caption {\n text-align: center;\n padding: var(--mantine-spacing-xs) var(--mantine-spacing-md);\n font-size: var(--mantine-font-size-sm);\n color: var(--mantine-color-white);\n opacity: 0.8;\n flex-shrink: 0;\n}\n\n.closeButton {\n color: var(--mantine-color-white);\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useLightboxContext } from "../lightbox.context.mjs";
|
|
3
|
+
import Lightbox_module_default from "../Lightbox.module.mjs";
|
|
4
|
+
import { Box, factory, useProps } from "@mantine/core";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
//#region packages/@mantine/lightbox/src/LightboxCaption/LightboxCaption.tsx
|
|
7
|
+
const LightboxCaption = factory((props) => {
|
|
8
|
+
const { classNames, className, style, styles, vars, children, ...others } = useProps("LightboxCaption", null, props);
|
|
9
|
+
const ctx = useLightboxContext();
|
|
10
|
+
const currentSlide = ctx.slides[ctx.currentIndex];
|
|
11
|
+
const caption = children ?? currentSlide?.caption;
|
|
12
|
+
if (!caption) return null;
|
|
13
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
14
|
+
...ctx.getStyles("caption", {
|
|
15
|
+
className,
|
|
16
|
+
style,
|
|
17
|
+
classNames,
|
|
18
|
+
styles
|
|
19
|
+
}),
|
|
20
|
+
mod: "reduce-motion",
|
|
21
|
+
...others,
|
|
22
|
+
children: caption
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
LightboxCaption.classes = Lightbox_module_default;
|
|
26
|
+
LightboxCaption.displayName = "@mantine/lightbox/LightboxCaption";
|
|
27
|
+
//#endregion
|
|
28
|
+
export { LightboxCaption };
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=LightboxCaption.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LightboxCaption.mjs","names":["classes"],"sources":["../../src/LightboxCaption/LightboxCaption.tsx"],"sourcesContent":["import {\n Box,\n BoxProps,\n CompoundStylesApiProps,\n ElementProps,\n factory,\n Factory,\n useProps,\n} from '@mantine/core';\nimport { useLightboxContext } from '../lightbox.context';\nimport classes from '../Lightbox.module.css';\n\nexport type LightboxCaptionStylesNames = 'caption';\n\nexport interface LightboxCaptionProps\n extends BoxProps, CompoundStylesApiProps<LightboxCaptionFactory>, ElementProps<'div'> {\n /** Custom caption content, overrides slide caption */\n children?: React.ReactNode;\n}\n\nexport type LightboxCaptionFactory = Factory<{\n props: LightboxCaptionProps;\n ref: HTMLDivElement;\n stylesNames: LightboxCaptionStylesNames;\n compound: true;\n}>;\n\nexport const LightboxCaption = factory<LightboxCaptionFactory>((props) => {\n const { classNames, className, style, styles, vars, children, ...others } = useProps(\n 'LightboxCaption',\n null,\n props\n );\n\n const ctx = useLightboxContext();\n const currentSlide = ctx.slides[ctx.currentIndex];\n const caption = children ?? currentSlide?.caption;\n\n if (!caption) {\n return null;\n }\n\n return (\n <Box\n {...ctx.getStyles('caption', { className, style, classNames, styles })}\n mod=\"reduce-motion\"\n {...others}\n >\n {caption}\n </Box>\n );\n});\n\nLightboxCaption.classes = classes;\nLightboxCaption.displayName = '@mantine/lightbox/LightboxCaption';\n"],"mappings":";;;;;;AA2BA,MAAa,kBAAkB,SAAiC,UAAU;CACxE,MAAM,EAAE,YAAY,WAAW,OAAO,QAAQ,MAAM,UAAU,GAAG,WAAW,SAC1E,mBACA,MACA,KACF;CAEA,MAAM,MAAM,mBAAmB;CAC/B,MAAM,eAAe,IAAI,OAAO,IAAI;CACpC,MAAM,UAAU,YAAY,cAAc;CAE1C,IAAI,CAAC,SACH,OAAO;CAGT,OACE,oBAAC,KAAD;EACE,GAAI,IAAI,UAAU,WAAW;GAAE;GAAW;GAAO;GAAY;EAAO,CAAC;EACrE,KAAI;EACJ,GAAI;EAEH,UAAA;CACE,CAAA;AAET,CAAC;AAED,gBAAgB,UAAUA;AAC1B,gBAAgB,cAAc"}
|