js-cloudimage-before-after 1.0.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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +305 -0
  3. package/dist/a11y/aria.d.ts +4 -0
  4. package/dist/a11y/keyboard.d.ts +22 -0
  5. package/dist/animation/entrance.d.ts +18 -0
  6. package/dist/core/ci-before-after.d.ts +64 -0
  7. package/dist/core/config.d.ts +3 -0
  8. package/dist/core/types.d.ts +127 -0
  9. package/dist/fullscreen/fullscreen.d.ts +16 -0
  10. package/dist/index.d.ts +10 -0
  11. package/dist/js-cloudimage-before-after.cjs.js +2 -0
  12. package/dist/js-cloudimage-before-after.cjs.js.map +1 -0
  13. package/dist/js-cloudimage-before-after.esm.js +1210 -0
  14. package/dist/js-cloudimage-before-after.esm.js.map +1 -0
  15. package/dist/js-cloudimage-before-after.min.js +2 -0
  16. package/dist/js-cloudimage-before-after.min.js.map +1 -0
  17. package/dist/labels/labels.d.ts +6 -0
  18. package/dist/react/ci-before-after-viewer.d.ts +3 -0
  19. package/dist/react/index.cjs +2 -0
  20. package/dist/react/index.cjs.map +1 -0
  21. package/dist/react/index.d.ts +3 -0
  22. package/dist/react/index.js +179 -0
  23. package/dist/react/index.js.map +1 -0
  24. package/dist/react/types.d.ts +11 -0
  25. package/dist/react/use-ci-before-after.d.ts +5 -0
  26. package/dist/slider/gestures.d.ts +31 -0
  27. package/dist/slider/handle.d.ts +2 -0
  28. package/dist/slider/slider.d.ts +11 -0
  29. package/dist/utils/cloudimage.d.ts +2 -0
  30. package/dist/utils/dom.d.ts +8 -0
  31. package/dist/utils/events.d.ts +12 -0
  32. package/dist/zoom/controls.d.ts +12 -0
  33. package/dist/zoom/gestures.d.ts +21 -0
  34. package/dist/zoom/scroll-hint.d.ts +7 -0
  35. package/dist/zoom/zoom-pan.d.ts +40 -0
  36. package/package.json +69 -0
@@ -0,0 +1,1210 @@
1
+ const he = ["drag", "hover", "click"], fe = ["horizontal", "vertical"], de = ["light", "dark"], me = ["arrows", "circle", "line"], be = ["top", "bottom"], ue = [
2
+ "top-left",
3
+ "top-center",
4
+ "top-right",
5
+ "bottom-left",
6
+ "bottom-center",
7
+ "bottom-right"
8
+ ], d = {
9
+ beforeAlt: "Before",
10
+ afterAlt: "After",
11
+ mode: "drag",
12
+ orientation: "horizontal",
13
+ initialPosition: 50,
14
+ zoom: !1,
15
+ zoomMax: 4,
16
+ zoomMin: 1,
17
+ theme: "light",
18
+ handleStyle: "arrows",
19
+ labelPosition: "top",
20
+ animateOnce: !0,
21
+ fullscreenButton: !0,
22
+ lazyLoad: !0,
23
+ zoomControls: !0,
24
+ zoomControlsPosition: "bottom-right",
25
+ scrollHint: !0,
26
+ keyboardStep: 1,
27
+ keyboardLargeStep: 10
28
+ };
29
+ function G(o) {
30
+ const e = o.labels;
31
+ let t = !0, i = "Before", n = "After";
32
+ e === !1 ? t = !1 : typeof e == "object" && (i = e.before ?? "Before", n = e.after ?? "After");
33
+ const r = o.animate;
34
+ let s = !1, l = 800, a = 0, c = "ease-out";
35
+ r === !0 ? s = !0 : typeof r == "object" && (s = !0, l = Math.max(0, r.duration ?? 800), a = Math.max(0, r.delay ?? 0), c = r.easing ?? "ease-out");
36
+ const h = o.zoom ?? d.zoom;
37
+ return {
38
+ beforeSrc: o.beforeSrc,
39
+ afterSrc: o.afterSrc,
40
+ beforeAlt: o.beforeAlt ?? d.beforeAlt,
41
+ afterAlt: o.afterAlt ?? d.afterAlt,
42
+ mode: z(o.mode, he, d.mode, "mode"),
43
+ orientation: z(o.orientation, fe, d.orientation, "orientation"),
44
+ initialPosition: ve(o.initialPosition ?? d.initialPosition),
45
+ zoom: h,
46
+ zoomMax: Math.max(1, o.zoomMax ?? d.zoomMax),
47
+ zoomMin: Math.max(1, Math.min(o.zoomMin ?? d.zoomMin, o.zoomMax ?? d.zoomMax)),
48
+ theme: z(o.theme, de, d.theme, "theme"),
49
+ handleStyle: z(o.handleStyle, me, d.handleStyle, "handleStyle"),
50
+ labelsEnabled: t,
51
+ labelBefore: i,
52
+ labelAfter: n,
53
+ labelPosition: z(o.labelPosition, be, d.labelPosition, "labelPosition"),
54
+ animateEnabled: s,
55
+ animateDuration: l,
56
+ animateDelay: a,
57
+ animateEasing: c,
58
+ animateOnce: o.animateOnce ?? d.animateOnce,
59
+ fullscreenButton: o.fullscreenButton ?? d.fullscreenButton,
60
+ lazyLoad: o.lazyLoad ?? d.lazyLoad,
61
+ zoomControls: o.zoomControls ?? (h ? d.zoomControls : !1),
62
+ zoomControlsPosition: z(o.zoomControlsPosition, ue, d.zoomControlsPosition, "zoomControlsPosition"),
63
+ scrollHint: o.scrollHint ?? (h ? d.scrollHint : !1),
64
+ keyboardStep: Math.max(0.5, o.keyboardStep ?? d.keyboardStep),
65
+ keyboardLargeStep: Math.max(1, o.keyboardLargeStep ?? d.keyboardLargeStep),
66
+ onSlide: o.onSlide,
67
+ onZoom: o.onZoom,
68
+ onFullscreenChange: o.onFullscreenChange,
69
+ onReady: o.onReady,
70
+ cloudimage: o.cloudimage
71
+ };
72
+ }
73
+ function w(o, e, t) {
74
+ if (e.includes(o)) return o;
75
+ console.warn(`CIBeforeAfter: Invalid ${t} "${o}". Allowed: ${e.join(", ")}`);
76
+ }
77
+ function z(o, e, t, i) {
78
+ return o === void 0 ? t : e.includes(o) ? o : (console.warn(`CIBeforeAfter: Invalid ${i} "${o}". Allowed: ${e.join(", ")}. Using default "${t}".`), t);
79
+ }
80
+ function pe(o) {
81
+ const e = (k) => o.getAttribute(`data-ci-before-after-${k}`), t = (k) => {
82
+ const x = e(k);
83
+ if (x !== null)
84
+ return x === "true";
85
+ }, i = (k) => {
86
+ const x = e(k);
87
+ if (x === null) return;
88
+ const _ = parseFloat(x);
89
+ return isNaN(_) ? void 0 : _;
90
+ }, n = e("before-src"), r = e("after-src");
91
+ if (!n || !r)
92
+ throw new Error("CIBeforeAfter: data-ci-before-after-before-src and data-ci-before-after-after-src are required");
93
+ const s = {
94
+ beforeSrc: n,
95
+ afterSrc: r
96
+ }, l = e("before-alt");
97
+ l !== null && (s.beforeAlt = l);
98
+ const a = e("after-alt");
99
+ a !== null && (s.afterAlt = a);
100
+ const c = e("mode");
101
+ c && (s.mode = w(c, he, "mode"));
102
+ const h = e("orientation");
103
+ h && (s.orientation = w(h, fe, "orientation"));
104
+ const m = i("initial-position");
105
+ m !== void 0 && (s.initialPosition = m);
106
+ const b = t("zoom");
107
+ b !== void 0 && (s.zoom = b);
108
+ const p = i("zoom-max");
109
+ p !== void 0 && (s.zoomMax = p);
110
+ const g = i("zoom-min");
111
+ g !== void 0 && (s.zoomMin = g);
112
+ const u = e("theme");
113
+ u && (s.theme = w(u, de, "theme"));
114
+ const y = e("handle-style");
115
+ y && (s.handleStyle = w(y, me, "handleStyle"));
116
+ const P = t("labels"), C = e("label-before"), T = e("label-after");
117
+ P === !1 ? s.labels = !1 : C !== null || T !== null ? s.labels = {
118
+ before: C ?? void 0,
119
+ after: T ?? void 0
120
+ } : P === !0 && (s.labels = !0);
121
+ const O = e("label-position");
122
+ O && (s.labelPosition = w(O, be, "labelPosition"));
123
+ const D = t("animate"), Z = i("animate-duration"), H = i("animate-delay"), A = e("animate-easing");
124
+ Z !== void 0 || H !== void 0 || A != null ? s.animate = {
125
+ duration: Z,
126
+ delay: H,
127
+ easing: A ?? void 0
128
+ } : D !== void 0 && (s.animate = D);
129
+ const B = t("animate-once");
130
+ B !== void 0 && (s.animateOnce = B);
131
+ const R = t("fullscreen-button");
132
+ R !== void 0 && (s.fullscreenButton = R);
133
+ const $ = t("lazy-load");
134
+ $ !== void 0 && (s.lazyLoad = $);
135
+ const F = t("zoom-controls");
136
+ F !== void 0 && (s.zoomControls = F);
137
+ const Y = e("zoom-controls-position");
138
+ Y && (s.zoomControlsPosition = w(Y, ue, "zoomControlsPosition"));
139
+ const X = t("scroll-hint");
140
+ X !== void 0 && (s.scrollHint = X);
141
+ const W = i("keyboard-step");
142
+ W !== void 0 && (s.keyboardStep = W);
143
+ const N = i("keyboard-large-step");
144
+ N !== void 0 && (s.keyboardLargeStep = N);
145
+ const j = e("ci-token");
146
+ return j && (s.cloudimage = {
147
+ token: j,
148
+ apiVersion: e("ci-api-version") ?? void 0,
149
+ domain: e("ci-domain") ?? void 0,
150
+ limitFactor: i("ci-limit-factor"),
151
+ params: e("ci-params") ?? void 0
152
+ }), s;
153
+ }
154
+ function ve(o) {
155
+ return isFinite(o) ? Math.max(0, Math.min(100, o)) : 50;
156
+ }
157
+ const V = "ci-before-after-styles";
158
+ function U(o) {
159
+ if (!S() || document.getElementById(V)) return;
160
+ const e = document.createElement("style");
161
+ e.id = V, e.textContent = o, document.head.appendChild(e);
162
+ }
163
+ function f(o, e, t) {
164
+ const i = document.createElement(o);
165
+ if (e && (i.className = e), t)
166
+ for (const [n, r] of Object.entries(t))
167
+ i.setAttribute(n, r);
168
+ return i;
169
+ }
170
+ function we(o) {
171
+ if (typeof o == "string") {
172
+ const e = document.querySelector(o);
173
+ if (!e)
174
+ throw new Error(`CIBeforeAfter: Element not found for selector "${o}"`);
175
+ return e;
176
+ }
177
+ return o;
178
+ }
179
+ function S() {
180
+ return typeof window < "u" && typeof document < "u";
181
+ }
182
+ function I() {
183
+ if (!S()) return !1;
184
+ const o = document;
185
+ return !!(o.fullscreenEnabled || o.webkitFullscreenEnabled);
186
+ }
187
+ function ze(o) {
188
+ const e = o;
189
+ return e.requestFullscreen ? e.requestFullscreen() : e.webkitRequestFullscreen ? e.webkitRequestFullscreen() : Promise.reject(new Error("Fullscreen API not supported"));
190
+ }
191
+ function q() {
192
+ const o = document;
193
+ return o.exitFullscreen ? o.exitFullscreen() : o.webkitExitFullscreen ? o.webkitExitFullscreen() : Promise.reject(new Error("Fullscreen API not supported"));
194
+ }
195
+ function K() {
196
+ const o = document;
197
+ return o.fullscreenElement || o.webkitFullscreenElement || null;
198
+ }
199
+ class v {
200
+ constructor() {
201
+ this.cleanups = [];
202
+ }
203
+ on(e, t, i, n) {
204
+ e.addEventListener(t, i, n), this.cleanups.push(() => e.removeEventListener(t, i, n));
205
+ }
206
+ onPassive(e, t, i) {
207
+ this.on(e, t, i, { passive: !0 });
208
+ }
209
+ onNonPassive(e, t, i) {
210
+ this.on(e, t, i, { passive: !1 });
211
+ }
212
+ destroy() {
213
+ for (const e of this.cleanups)
214
+ e();
215
+ this.cleanups = [];
216
+ }
217
+ }
218
+ function ye(o, e) {
219
+ var n;
220
+ let t, i;
221
+ if ("touches" in o) {
222
+ const r = o.touches[0] || ((n = o.changedTouches) == null ? void 0 : n[0]);
223
+ if (!r) return { x: 0, y: 0 };
224
+ t = r.clientX, i = r.clientY;
225
+ } else
226
+ t = o.clientX, i = o.clientY;
227
+ return {
228
+ x: t - e.left,
229
+ y: i - e.top
230
+ };
231
+ }
232
+ function E(o, e, t) {
233
+ const { x: i, y: n } = ye(o, e), r = t === "horizontal" ? e.width : e.height;
234
+ return r === 0 ? 50 : Math.max(0, Math.min(100, (t === "horizontal" ? i : n) / r * 100));
235
+ }
236
+ const Pe = /^[a-zA-Z0-9_-]+$/, Ce = /^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/, ke = /^v\d+$/;
237
+ function xe(o) {
238
+ if (!Pe.test(o.token))
239
+ throw new Error(`CIBeforeAfter: Invalid cloudimage token "${o.token}". Must match [a-zA-Z0-9_-]+`);
240
+ if (o.domain && !Ce.test(o.domain))
241
+ throw new Error(`CIBeforeAfter: Invalid cloudimage domain "${o.domain}".`);
242
+ if (o.apiVersion && !ke.test(o.apiVersion))
243
+ throw new Error(`CIBeforeAfter: Invalid cloudimage apiVersion "${o.apiVersion}". Must be "v" followed by digits.`);
244
+ }
245
+ function Le(o, e, t) {
246
+ xe(t);
247
+ const {
248
+ token: i,
249
+ apiVersion: n = "v7",
250
+ domain: r = "cloudimg.io",
251
+ limitFactor: s = 100,
252
+ params: l = "",
253
+ devicePixelRatioList: a = [1, 1.5, 2]
254
+ } = t, c = typeof window < "u" && window.devicePixelRatio || 1, m = (a.length > 0 ? a : [1]).reduce(
255
+ (P, C) => Math.abs(C - c) < Math.abs(P - c) ? C : P
256
+ ), b = s > 0 ? s : 100, p = e * m, g = Math.ceil(p / b) * b, u = `https://${i}.${r}/${n}`, y = l ? `?${l}&w=${g}` : `?w=${g}`;
257
+ return o.startsWith("http://") || o.startsWith("https://") ? `${u}/${o}${y}` : `${u}/${o}${y}`;
258
+ }
259
+ function M(o, e, t, i) {
260
+ let n = e;
261
+ i && i.level > 1 && (t === "horizontal" ? n = e / i.level - i.panX * 100 / (i.level * i.containerWidth) : n = e / i.level - i.panY * 100 / (i.level * i.containerHeight), n = Math.max(0, Math.min(100, n)));
262
+ const r = t === "horizontal" ? `inset(0 0 0 ${n}%)` : `inset(${n}% 0 0 0)`;
263
+ o.style.clipPath = r, o.style.setProperty("-webkit-clip-path", r);
264
+ }
265
+ function Ee(o, e, t) {
266
+ t === "horizontal" ? (o.style.left = `${e}%`, o.style.top = "") : (o.style.top = `${e}%`, o.style.left = "");
267
+ }
268
+ function J(o) {
269
+ return isFinite(o) ? Math.max(0, Math.min(100, o)) : 50;
270
+ }
271
+ const Ae = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>', Ie = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>', Me = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m18 15-6-6-6 6"/></svg>', Se = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>', Te = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 8 22 12 18 16"/><polyline points="6 8 2 12 6 16"/><line x1="2" x2="22" y1="12" y2="12"/></svg>', Oe = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="8 18 12 22 16 18"/><polyline points="8 6 12 2 16 6"/><line x1="12" x2="12" y1="2" y2="22"/></svg>';
272
+ function Q(o, e, t) {
273
+ const i = f("div", `ci-before-after-handle ci-before-after-handle--${o}`, {
274
+ role: "slider",
275
+ "aria-valuenow": String(Math.round(t)),
276
+ "aria-valuemin": "0",
277
+ "aria-valuemax": "100",
278
+ "aria-label": "Image comparison slider. Use arrow keys to adjust the before and after split position.",
279
+ "aria-orientation": e,
280
+ tabindex: "0"
281
+ });
282
+ switch (e === "horizontal" ? i.style.left = `${t}%` : i.style.top = `${t}%`, o) {
283
+ case "arrows":
284
+ De(i, e);
285
+ break;
286
+ case "circle":
287
+ Ze(i, e);
288
+ break;
289
+ case "line":
290
+ He(i);
291
+ break;
292
+ }
293
+ return i;
294
+ }
295
+ function De(o, e) {
296
+ const t = f("div", "ci-before-after-handle-line"), i = f("div", "ci-before-after-handle-grip"), n = f("div", "ci-before-after-handle-line");
297
+ e === "horizontal" ? i.innerHTML = Ae + Ie : i.innerHTML = Me + Se, o.append(t, i, n);
298
+ }
299
+ function Ze(o, e) {
300
+ const t = f("div", "ci-before-after-handle-grip");
301
+ e === "horizontal" ? t.innerHTML = Te : t.innerHTML = Oe, o.append(t);
302
+ }
303
+ function He(o) {
304
+ const e = f("div", "ci-before-after-handle-line"), t = f("div", "ci-before-after-handle-grip ci-before-after-handle-grip--pill"), i = f("div", "ci-before-after-handle-line");
305
+ o.append(e, t, i);
306
+ }
307
+ class ee {
308
+ constructor(e, t, i, n, r) {
309
+ this.container = e, this.handle = t, this.mode = i, this.orientation = n, this.callbacks = r, this.events = new v(), this.containerRect = null, this.rafId = null, this.pendingPosition = null, this.abortController = null, this.bind();
310
+ }
311
+ bind() {
312
+ switch (this.mode) {
313
+ case "drag":
314
+ this.bindDrag();
315
+ break;
316
+ case "hover":
317
+ this.bindHover();
318
+ break;
319
+ case "click":
320
+ this.bindClick();
321
+ break;
322
+ }
323
+ }
324
+ bindDrag() {
325
+ this.events.on(this.handle, "mousedown", (e) => {
326
+ e.preventDefault(), this.startDrag();
327
+ }), this.events.on(this.handle, "touchstart", (e) => {
328
+ e.preventDefault(), this.handle.focus(), this.startTouchDrag();
329
+ }, { passive: !1 });
330
+ }
331
+ startDrag() {
332
+ this.cleanupWindowListeners(), this.abortController = new AbortController();
333
+ const e = this.abortController.signal;
334
+ this.containerRect = this.container.getBoundingClientRect(), this.callbacks.onDragStart();
335
+ const t = (n) => {
336
+ if (!this.containerRect) return;
337
+ const r = E(n, this.containerRect, this.orientation);
338
+ this.schedulePositionUpdate(r);
339
+ }, i = () => {
340
+ this.flushPositionUpdate(), this.callbacks.onDragEnd(), this.containerRect = null, this.cleanupWindowListeners();
341
+ };
342
+ window.addEventListener("mousemove", t, { signal: e }), window.addEventListener("mouseup", i, { signal: e });
343
+ }
344
+ startTouchDrag() {
345
+ this.cleanupWindowListeners(), this.abortController = new AbortController();
346
+ const e = this.abortController.signal;
347
+ this.containerRect = this.container.getBoundingClientRect(), this.callbacks.onDragStart();
348
+ const t = (n) => {
349
+ if (!this.containerRect || n.touches.length !== 1) return;
350
+ n.preventDefault();
351
+ const r = E(n, this.containerRect, this.orientation);
352
+ this.schedulePositionUpdate(r);
353
+ }, i = () => {
354
+ this.flushPositionUpdate(), this.callbacks.onDragEnd(), this.containerRect = null, this.cleanupWindowListeners();
355
+ };
356
+ window.addEventListener("touchmove", t, { passive: !1, signal: e }), window.addEventListener("touchend", i, { signal: e }), window.addEventListener("touchcancel", i, { signal: e });
357
+ }
358
+ schedulePositionUpdate(e) {
359
+ this.pendingPosition = e, this.rafId === null && (this.rafId = requestAnimationFrame(() => {
360
+ this.rafId = null, this.pendingPosition !== null && (this.callbacks.onPositionChange(this.pendingPosition), this.pendingPosition = null);
361
+ }));
362
+ }
363
+ flushPositionUpdate() {
364
+ this.rafId !== null && (cancelAnimationFrame(this.rafId), this.rafId = null), this.pendingPosition !== null && (this.callbacks.onPositionChange(this.pendingPosition), this.pendingPosition = null);
365
+ }
366
+ cleanupWindowListeners() {
367
+ this.abortController && (this.abortController.abort(), this.abortController = null);
368
+ }
369
+ bindHover() {
370
+ this.events.on(this.container, "mousemove", (e) => {
371
+ const t = this.container.getBoundingClientRect(), i = E(e, t, this.orientation);
372
+ this.schedulePositionUpdate(i);
373
+ });
374
+ }
375
+ bindClick() {
376
+ this.events.on(this.container, "click", (e) => {
377
+ if (this.handle.contains(e.target)) return;
378
+ const t = this.container.getBoundingClientRect(), i = E(e, t, this.orientation);
379
+ this.callbacks.onPositionChange(i);
380
+ });
381
+ }
382
+ updateMode(e) {
383
+ this.events.destroy(), this.cleanupWindowListeners(), this.flushPositionUpdate(), this.mode = e, this.bind();
384
+ }
385
+ updateOrientation(e) {
386
+ this.orientation = e;
387
+ }
388
+ destroy() {
389
+ this.cleanupWindowListeners(), this.rafId !== null && (cancelAnimationFrame(this.rafId), this.rafId = null), this.pendingPosition = null, this.events.destroy(), this.containerRect = null;
390
+ }
391
+ }
392
+ class Be {
393
+ constructor(e, t, i, n, r) {
394
+ this.viewport = e, this.container = t, this.config = i, this.onZoomChange = n, this.zoomLevel = 1, this.panX = 0, this.panY = 0, this.containerWidth = 0, this.containerHeight = 0, this.transitioning = !1, this.transitionEndCleanup = null, this.resizeObserver = null, this.onTransformChange = r, this.updateContainerSize(), this.observeResize();
395
+ }
396
+ observeResize() {
397
+ typeof ResizeObserver > "u" || (this.resizeObserver = new ResizeObserver((e) => {
398
+ for (const t of e) {
399
+ const { width: i, height: n } = t.contentRect;
400
+ this.containerWidth = i, this.containerHeight = n;
401
+ }
402
+ }), this.resizeObserver.observe(this.container));
403
+ }
404
+ getZoom() {
405
+ return this.zoomLevel;
406
+ }
407
+ getContainerSize() {
408
+ return { width: this.containerWidth, height: this.containerHeight };
409
+ }
410
+ setZoom(e, t, i) {
411
+ var s;
412
+ const n = Math.max(this.config.zoomMin, Math.min(this.config.zoomMax, e));
413
+ if (n === this.zoomLevel) return;
414
+ const r = this.zoomLevel;
415
+ this.zoomLevel = n, t !== void 0 && i !== void 0 && (this.panX = t - (t - this.panX) * (n / r), this.panY = i - (i - this.panY) * (n / r)), this.clampPan(), this.applyTransform(!0), (s = this.onZoomChange) == null || s.call(this, this.zoomLevel);
416
+ }
417
+ zoomIn() {
418
+ this.setZoom(
419
+ this.zoomLevel * 1.5,
420
+ this.containerWidth / 2,
421
+ this.containerHeight / 2
422
+ );
423
+ }
424
+ zoomOut() {
425
+ this.setZoom(
426
+ this.zoomLevel / 1.5,
427
+ this.containerWidth / 2,
428
+ this.containerHeight / 2
429
+ );
430
+ }
431
+ resetZoom() {
432
+ var e;
433
+ this.zoomLevel = Math.max(1, this.config.zoomMin), this.panX = 0, this.panY = 0, this.applyTransform(!0), (e = this.onZoomChange) == null || e.call(this, this.zoomLevel);
434
+ }
435
+ getPan() {
436
+ return { x: this.panX, y: this.panY };
437
+ }
438
+ setPan(e, t) {
439
+ this.panX = e, this.panY = t, this.clampPan(), this.applyTransform(!1);
440
+ }
441
+ pan(e, t) {
442
+ this.zoomLevel <= 1 || (this.panX += e, this.panY += t, this.clampPan(), this.applyTransform(!1));
443
+ }
444
+ handleWheel(e) {
445
+ if (!e.ctrlKey && !e.metaKey) return;
446
+ e.preventDefault();
447
+ const t = this.container.getBoundingClientRect(), i = e.clientX - t.left, n = e.clientY - t.top, r = e.deltaY > 0 ? 0.9 : 1.1;
448
+ this.setZoom(this.zoomLevel * r, i, n);
449
+ }
450
+ toggleZoom(e, t) {
451
+ const i = Math.max(1, this.config.zoomMin);
452
+ this.zoomLevel > i ? this.resetZoom() : this.setZoom(Math.max(2, i * 1.5), e, t);
453
+ }
454
+ updateConfig(e) {
455
+ var i;
456
+ this.config = e;
457
+ const t = Math.max(e.zoomMin, Math.min(e.zoomMax, this.zoomLevel));
458
+ t !== this.zoomLevel && (this.zoomLevel = t, (i = this.onZoomChange) == null || i.call(this, this.zoomLevel)), this.clampPan(), this.applyTransform(!1);
459
+ }
460
+ updateContainerSize() {
461
+ const e = this.container.getBoundingClientRect();
462
+ this.containerWidth = e.width, this.containerHeight = e.height;
463
+ }
464
+ clampPan() {
465
+ if (this.zoomLevel <= 1) {
466
+ this.panX = 0, this.panY = 0;
467
+ return;
468
+ }
469
+ const e = this.containerWidth * (this.zoomLevel - 1), t = this.containerHeight * (this.zoomLevel - 1);
470
+ this.panX = Math.max(-e, Math.min(0, this.panX)), this.panY = Math.max(-t, Math.min(0, this.panY));
471
+ }
472
+ applyTransform(e) {
473
+ var t;
474
+ if (this.transitionEndCleanup && (this.transitionEndCleanup(), this.transitionEndCleanup = null), e) {
475
+ this.viewport.style.transition = "transform 300ms ease", this.transitioning = !0;
476
+ const i = (n) => {
477
+ n.target === this.viewport && (this.viewport.style.transition = "", this.transitioning = !1, this.transitionEndCleanup = null, this.viewport.removeEventListener("transitionend", i));
478
+ };
479
+ this.viewport.addEventListener("transitionend", i), this.transitionEndCleanup = () => {
480
+ this.viewport.removeEventListener("transitionend", i), this.viewport.style.transition = "", this.transitioning = !1;
481
+ };
482
+ } else this.transitioning || (this.viewport.style.transition = "");
483
+ this.viewport.style.transform = `scale(${this.zoomLevel}) translate(${this.panX / this.zoomLevel}px, ${this.panY / this.zoomLevel}px)`, (t = this.onTransformChange) == null || t.call(this);
484
+ }
485
+ destroy() {
486
+ var e;
487
+ this.transitionEndCleanup && (this.transitionEndCleanup(), this.transitionEndCleanup = null), this.viewport.style.transform = "", this.viewport.style.transition = "", (e = this.resizeObserver) == null || e.disconnect(), this.resizeObserver = null;
488
+ }
489
+ }
490
+ const Re = 3;
491
+ class te {
492
+ constructor(e, t, i, n) {
493
+ this.container = e, this.handle = t, this.zoomPan = i, this.scrollHintCallback = n, this.events = new v(), this.isPanning = !1, this.lastPanX = 0, this.lastPanY = 0, this.initialPinchDistance = 0, this.initialPinchZoom = 1, this.abortController = null, this.bind();
494
+ }
495
+ bind() {
496
+ this.events.onNonPassive(this.container, "wheel", (e) => {
497
+ var t;
498
+ e.ctrlKey || e.metaKey ? this.zoomPan.handleWheel(e) : this.zoomPan.getZoom() > 1 || (t = this.scrollHintCallback) == null || t.call(this);
499
+ }), this.events.on(this.container, "dblclick", (e) => {
500
+ if (this.handle.contains(e.target)) return;
501
+ const t = this.container.getBoundingClientRect();
502
+ this.zoomPan.toggleZoom(e.clientX - t.left, e.clientY - t.top);
503
+ }), this.events.on(this.container, "mousedown", (e) => {
504
+ this.handle.contains(e.target) || this.zoomPan.getZoom() <= 1 || (e.preventDefault(), this.startPan(e.clientX, e.clientY));
505
+ }), this.events.on(this.container, "touchstart", (e) => {
506
+ this.handle.contains(e.target) || (e.touches.length === 2 ? (e.preventDefault(), this.startPinch(e)) : e.touches.length === 1 && this.zoomPan.getZoom() > 1 && (e.preventDefault(), this.startTouchPan(e)));
507
+ }, { passive: !1 }), typeof window < "u" && "GestureEvent" in window && (this.events.onNonPassive(this.container, "gesturestart", (e) => {
508
+ e.preventDefault(), this.initialPinchZoom = this.zoomPan.getZoom();
509
+ const t = e, i = this.container.getBoundingClientRect();
510
+ t.clientX - i.left, t.clientY - i.top;
511
+ }), this.events.onNonPassive(this.container, "gesturechange", (e) => {
512
+ e.preventDefault();
513
+ const t = e, i = this.container.getBoundingClientRect();
514
+ this.zoomPan.setZoom(
515
+ this.initialPinchZoom * t.scale,
516
+ t.clientX - i.left,
517
+ t.clientY - i.top
518
+ );
519
+ }));
520
+ }
521
+ startPan(e, t) {
522
+ this.cleanupWindowListeners(), this.abortController = new AbortController();
523
+ const i = this.abortController.signal;
524
+ this.isPanning = !1, this.lastPanX = e, this.lastPanY = t;
525
+ const n = e, r = t, s = (a) => {
526
+ const c = a.clientX - this.lastPanX, h = a.clientY - this.lastPanY;
527
+ if (!this.isPanning) {
528
+ const m = a.clientX - n, b = a.clientY - r;
529
+ if (Math.hypot(m, b) < Re) return;
530
+ this.isPanning = !0, this.container.style.cursor = "grabbing";
531
+ }
532
+ this.lastPanX = a.clientX, this.lastPanY = a.clientY, this.zoomPan.pan(c, h);
533
+ }, l = () => {
534
+ this.isPanning = !1, this.container.style.cursor = "", this.cleanupWindowListeners();
535
+ };
536
+ window.addEventListener("mousemove", s, { signal: i }), window.addEventListener("mouseup", l, { signal: i });
537
+ }
538
+ startTouchPan(e) {
539
+ this.cleanupWindowListeners(), this.abortController = new AbortController();
540
+ const t = this.abortController.signal, i = e.touches[0];
541
+ this.lastPanX = i.clientX, this.lastPanY = i.clientY;
542
+ const n = (s) => {
543
+ if (s.touches.length !== 1) return;
544
+ s.preventDefault();
545
+ const l = s.touches[0], a = l.clientX - this.lastPanX, c = l.clientY - this.lastPanY;
546
+ this.lastPanX = l.clientX, this.lastPanY = l.clientY, this.zoomPan.pan(a, c);
547
+ }, r = () => {
548
+ this.cleanupWindowListeners();
549
+ };
550
+ window.addEventListener("touchmove", n, { passive: !1, signal: t }), window.addEventListener("touchend", r, { signal: t }), window.addEventListener("touchcancel", r, { signal: t });
551
+ }
552
+ startPinch(e) {
553
+ if (e.touches.length < 2) return;
554
+ this.cleanupWindowListeners(), this.abortController = new AbortController();
555
+ const t = this.abortController.signal, [i, n] = [e.touches[0], e.touches[1]];
556
+ this.initialPinchDistance = Math.hypot(n.clientX - i.clientX, n.clientY - i.clientY), this.initialPinchDistance === 0 && (this.initialPinchDistance = 1), this.initialPinchZoom = this.zoomPan.getZoom();
557
+ const r = this.container.getBoundingClientRect(), s = (i.clientX + n.clientX) / 2 - r.left, l = (i.clientY + n.clientY) / 2 - r.top, a = (h) => {
558
+ if (h.touches.length !== 2) return;
559
+ h.preventDefault();
560
+ const [m, b] = [h.touches[0], h.touches[1]], g = Math.hypot(b.clientX - m.clientX, b.clientY - m.clientY) / this.initialPinchDistance;
561
+ this.zoomPan.setZoom(this.initialPinchZoom * g, s, l);
562
+ }, c = () => {
563
+ this.cleanupWindowListeners();
564
+ };
565
+ window.addEventListener("touchmove", a, { passive: !1, signal: t }), window.addEventListener("touchend", c, { signal: t }), window.addEventListener("touchcancel", c, { signal: t });
566
+ }
567
+ cleanupWindowListeners() {
568
+ this.abortController && (this.abortController.abort(), this.abortController = null);
569
+ }
570
+ destroy() {
571
+ this.cleanupWindowListeners(), this.events.destroy();
572
+ }
573
+ }
574
+ const $e = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>', Fe = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/></svg>', Ye = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>';
575
+ function ie(o, e) {
576
+ const t = new v(), i = f("div", `ci-before-after-zoom-controls ci-before-after-zoom-controls--${o}`), n = f("button", "ci-before-after-zoom-in", {
577
+ type: "button",
578
+ "aria-label": "Zoom in"
579
+ });
580
+ n.innerHTML = $e, t.on(n, "click", e.onZoomIn);
581
+ const r = f("button", "ci-before-after-zoom-out", {
582
+ type: "button",
583
+ "aria-label": "Zoom out"
584
+ });
585
+ r.innerHTML = Fe, t.on(r, "click", e.onZoomOut);
586
+ const s = f("button", "ci-before-after-zoom-reset", {
587
+ type: "button",
588
+ "aria-label": "Reset zoom"
589
+ });
590
+ return s.innerHTML = Ye, t.on(s, "click", e.onReset), i.append(n, r, s), { element: i, events: t };
591
+ }
592
+ class oe {
593
+ constructor(e) {
594
+ this.timeout = null, this.el = f("div", "ci-before-after-scroll-hint", {
595
+ "aria-hidden": "true"
596
+ });
597
+ const t = typeof navigator < "u" && /Mac|iPhone|iPad|iPod/.test(navigator.userAgent);
598
+ this.el.textContent = t ? "⌘ + scroll or pinch to zoom" : "Ctrl + scroll or pinch to zoom", e.appendChild(this.el);
599
+ }
600
+ show() {
601
+ this.timeout && clearTimeout(this.timeout), this.el.classList.add("ci-before-after-scroll-hint--visible"), this.timeout = setTimeout(() => {
602
+ this.el.classList.remove("ci-before-after-scroll-hint--visible"), this.timeout = null;
603
+ }, 1500);
604
+ }
605
+ destroy() {
606
+ this.timeout && clearTimeout(this.timeout), this.el.remove();
607
+ }
608
+ }
609
+ function ne(o, e, t, i) {
610
+ const n = `ci-before-after-label--${t}`, r = f(
611
+ "div",
612
+ `ci-before-after-label ci-before-after-label-before ${n}`,
613
+ { "aria-hidden": "true" }
614
+ );
615
+ r.textContent = o;
616
+ const s = f(
617
+ "div",
618
+ `ci-before-after-label ci-before-after-label-after ${n}`,
619
+ { "aria-hidden": "true" }
620
+ );
621
+ return s.textContent = e, { before: r, after: s };
622
+ }
623
+ function re(o, e, t, i) {
624
+ if (!o || !e) return;
625
+ const n = 15;
626
+ t < n ? o.classList.add("ci-before-after-label--hidden") : o.classList.remove("ci-before-after-label--hidden"), t > 100 - n ? e.classList.add("ci-before-after-label--hidden") : e.classList.remove("ci-before-after-label--hidden");
627
+ }
628
+ const se = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" x2="14" y1="3" y2="10"/><line x1="3" x2="10" y1="21" y2="14"/></svg>', Xe = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 14 10 14 10 20"/><polyline points="20 10 14 10 14 4"/><line x1="14" x2="21" y1="10" y2="3"/><line x1="3" x2="10" y1="21" y2="14"/></svg>';
629
+ class ae {
630
+ constructor(e, t) {
631
+ this.container = e, this.onFullscreenChange = t, this.button = null, this.events = new v(), this.isActive = !1, I() && (this.createButton(), this.bindEvents());
632
+ }
633
+ createButton() {
634
+ this.button = f("button", "ci-before-after-fullscreen-btn", {
635
+ type: "button",
636
+ "aria-label": "Enter fullscreen",
637
+ "aria-pressed": "false"
638
+ }), this.button.innerHTML = se, this.events.on(this.button, "click", () => {
639
+ this.toggle().catch(() => {
640
+ });
641
+ }), this.container.appendChild(this.button);
642
+ }
643
+ bindEvents() {
644
+ this.events.on(document, "fullscreenchange", () => this.handleChange()), this.events.on(document, "webkitfullscreenchange", () => this.handleChange());
645
+ }
646
+ handleChange() {
647
+ var i;
648
+ const e = K(), t = this.isActive;
649
+ this.isActive = e === this.container, t !== this.isActive && (this.container.classList.toggle("ci-before-after-container--fullscreen", this.isActive), this.button && (this.button.innerHTML = this.isActive ? Xe : se, this.button.setAttribute("aria-label", this.isActive ? "Exit fullscreen" : "Enter fullscreen"), this.button.setAttribute("aria-pressed", String(this.isActive))), (i = this.onFullscreenChange) == null || i.call(this, this.isActive));
650
+ }
651
+ async enter() {
652
+ I() && await ze(this.container);
653
+ }
654
+ async exit() {
655
+ I() && K() === this.container && await q();
656
+ }
657
+ async toggle() {
658
+ this.isActive ? await this.exit() : await this.enter();
659
+ }
660
+ getIsFullscreen() {
661
+ return this.isActive;
662
+ }
663
+ destroy() {
664
+ var t, i;
665
+ const e = this.isActive;
666
+ this.events.destroy(), e && (this.isActive = !1, (t = this.onFullscreenChange) == null || t.call(this, !1), q().catch(() => {
667
+ })), this.container.classList.remove("ci-before-after-container--fullscreen"), (i = this.button) == null || i.remove();
668
+ }
669
+ }
670
+ class We {
671
+ constructor(e, t, i, n, r, s) {
672
+ this.container = e, this.duration = t, this.delay = i, this.easing = n, this.animateOnce = r, this.onAnimate = s, this.observer = null, this.hasPlayed = !1, this.isAnimating = !1, this.delayTimer = null, this.durationTimer = null, this.observe();
673
+ }
674
+ observe() {
675
+ typeof IntersectionObserver > "u" || (this.observer = new IntersectionObserver(
676
+ (e) => {
677
+ for (const t of e)
678
+ if (t.isIntersecting) {
679
+ if (this.animateOnce && this.hasPlayed || this.isAnimating) continue;
680
+ this.play();
681
+ }
682
+ },
683
+ { threshold: 0.3 }
684
+ ), this.observer.observe(this.container));
685
+ }
686
+ play() {
687
+ var e, t;
688
+ if (this.hasPlayed = !0, this.isAnimating = !0, typeof window < "u" && ((e = window.matchMedia) != null && e.call(window, "(prefers-reduced-motion: reduce)").matches)) {
689
+ this.onAnimate(!0), this.isAnimating = !1, this.animateOnce && ((t = this.observer) == null || t.disconnect());
690
+ return;
691
+ }
692
+ this.container.classList.add("ci-before-after-animate-entrance"), this.container.style.setProperty("--ci-before-after-animate-duration", `${this.duration}ms`), this.container.style.setProperty("--ci-before-after-animate-easing", this.easing), this.delayTimer = setTimeout(() => {
693
+ this.delayTimer = null, this.onAnimate(!1), this.durationTimer = setTimeout(() => {
694
+ var i;
695
+ this.durationTimer = null, this.container.classList.remove("ci-before-after-animate-entrance"), this.isAnimating = !1, this.animateOnce && ((i = this.observer) == null || i.disconnect());
696
+ }, this.duration);
697
+ }, this.delay);
698
+ }
699
+ getHasPlayed() {
700
+ return this.hasPlayed;
701
+ }
702
+ destroy() {
703
+ var e;
704
+ this.delayTimer && clearTimeout(this.delayTimer), this.durationTimer && clearTimeout(this.durationTimer), this.delayTimer = null, this.durationTimer = null, this.isAnimating = !1, this.container.classList.remove("ci-before-after-animate-entrance"), this.container.style.removeProperty("--ci-before-after-animate-duration"), this.container.style.removeProperty("--ci-before-after-animate-easing"), (e = this.observer) == null || e.disconnect(), this.observer = null;
705
+ }
706
+ }
707
+ class le {
708
+ constructor(e, t, i, n, r, s) {
709
+ this.handle = e, this.orientation = t, this.step = i, this.largeStep = n, this.zoomEnabled = r, this.callbacks = s, this.events = new v(), this.bind();
710
+ }
711
+ bind() {
712
+ this.events.on(this.handle, "keydown", (e) => {
713
+ this.handleKeyDown(e);
714
+ });
715
+ }
716
+ handleKeyDown(e) {
717
+ var r, s, l, a, c, h;
718
+ if (e.ctrlKey || e.altKey || e.metaKey) return;
719
+ const t = this.callbacks.getPosition(), i = e.shiftKey ? this.largeStep : this.step;
720
+ let n = null;
721
+ if (this.orientation === "horizontal")
722
+ switch (e.key) {
723
+ case "ArrowLeft":
724
+ n = t - i;
725
+ break;
726
+ case "ArrowRight":
727
+ n = t + i;
728
+ break;
729
+ }
730
+ else
731
+ switch (e.key) {
732
+ case "ArrowUp":
733
+ n = t - i;
734
+ break;
735
+ case "ArrowDown":
736
+ n = t + i;
737
+ break;
738
+ }
739
+ switch (e.key) {
740
+ case "Home":
741
+ n = 0;
742
+ break;
743
+ case "End":
744
+ n = 100;
745
+ break;
746
+ }
747
+ if (n !== null) {
748
+ e.preventDefault(), n = Math.max(0, Math.min(100, n)), this.callbacks.onPositionChange(n);
749
+ return;
750
+ }
751
+ if (this.zoomEnabled)
752
+ switch (e.key) {
753
+ case "+":
754
+ case "=":
755
+ e.preventDefault(), (s = (r = this.callbacks).onZoomIn) == null || s.call(r);
756
+ break;
757
+ case "-":
758
+ e.preventDefault(), (a = (l = this.callbacks).onZoomOut) == null || a.call(l);
759
+ break;
760
+ case "0":
761
+ e.preventDefault(), (h = (c = this.callbacks).onZoomReset) == null || h.call(c);
762
+ break;
763
+ }
764
+ }
765
+ updateConfig(e, t, i, n) {
766
+ this.orientation = e, this.step = t, this.largeStep = i, this.zoomEnabled = n;
767
+ }
768
+ destroy() {
769
+ this.events.destroy();
770
+ }
771
+ }
772
+ function Ne(o, e) {
773
+ o.setAttribute("aria-valuenow", String(Math.round(e)));
774
+ }
775
+ function je(o) {
776
+ o.setAttribute("role", "group"), o.setAttribute("aria-label", "Before and after image comparison");
777
+ }
778
+ class _e {
779
+ constructor(e, t) {
780
+ this.events = new v(), this.imageEvents = new v(), this.sliderGestures = null, this.zoomPan = null, this.zoomGestures = null, this.scrollHint = null, this.fullscreenManager = null, this.entranceAnimation = null, this.keyboardHandler = null, this.resizeObserver = null, this.zoomControlsEl = null, this.zoomControlsEvents = null, this.lazyLoadObserver = null, this.resizeDebounceTimer = null, this.animTransitionTimer = null, this.suppressCallbacks = !1;
781
+ const i = we(e);
782
+ this.userConfig = { ...t }, this.config = G(t), this.state = {
783
+ position: this.config.initialPosition,
784
+ isDragging: !1,
785
+ zoomLevel: 1,
786
+ panX: 0,
787
+ panY: 0,
788
+ isReady: !1,
789
+ isFullscreen: !1
790
+ }, this.buildDOM(i), this.initModules(), this.loadImages();
791
+ }
792
+ // --- Public API ---
793
+ getElements() {
794
+ return {
795
+ container: this.elements.container,
796
+ viewport: this.elements.viewport,
797
+ beforeImage: this.elements.beforeImage,
798
+ afterImage: this.elements.afterImage,
799
+ handle: this.elements.handle
800
+ };
801
+ }
802
+ setPosition(e) {
803
+ const t = J(e);
804
+ this.updatePosition(t);
805
+ }
806
+ getPosition() {
807
+ return this.state.position;
808
+ }
809
+ setZoom(e) {
810
+ var t;
811
+ (t = this.zoomPan) == null || t.setZoom(e);
812
+ }
813
+ getZoom() {
814
+ var e;
815
+ return ((e = this.zoomPan) == null ? void 0 : e.getZoom()) ?? 1;
816
+ }
817
+ resetZoom() {
818
+ var e;
819
+ (e = this.zoomPan) == null || e.resetZoom();
820
+ }
821
+ enterFullscreen() {
822
+ var e;
823
+ (e = this.fullscreenManager) == null || e.enter().catch(() => {
824
+ });
825
+ }
826
+ exitFullscreen() {
827
+ var e;
828
+ (e = this.fullscreenManager) == null || e.exit().catch(() => {
829
+ });
830
+ }
831
+ isFullscreen() {
832
+ var e;
833
+ return ((e = this.fullscreenManager) == null ? void 0 : e.getIsFullscreen()) ?? !1;
834
+ }
835
+ update(e) {
836
+ var s, l, a, c, h, m, b, p;
837
+ this.userConfig = { ...this.userConfig, ...e };
838
+ const t = this.config;
839
+ this.config = G(this.userConfig);
840
+ const i = this.config.beforeSrc !== t.beforeSrc, n = this.config.afterSrc !== t.afterSrc, r = !Ge(this.config.cloudimage, t.cloudimage);
841
+ if ((i || n || r) && (this.lazyLoadObserver && (this.lazyLoadObserver.disconnect(), this.lazyLoadObserver = null), this.state.isReady = !1, this.elements.container.classList.add("ci-before-after-loading"), (i || r) && (this.elements.beforeImage.src = this.resolveImageSrc(this.config.beforeSrc)), (n || r) && (this.elements.afterImage.src = this.resolveImageSrc(this.config.afterSrc)), this.registerImageLoadHandlers(i || r, n || r), this.config.cloudimage && !t.cloudimage ? this.initResizeObserver() : !this.config.cloudimage && t.cloudimage && ((s = this.resizeObserver) == null || s.disconnect(), this.resizeObserver = null)), this.config.beforeAlt !== t.beforeAlt && this.elements.beforeImage.setAttribute("alt", this.config.beforeAlt), this.config.afterAlt !== t.afterAlt && this.elements.afterImage.setAttribute("alt", this.config.afterAlt), this.elements.container.classList.toggle("ci-before-after-theme-dark", this.config.theme === "dark"), this.elements.container.classList.toggle("ci-before-after-container--horizontal", this.config.orientation === "horizontal"), this.elements.container.classList.toggle("ci-before-after-container--vertical", this.config.orientation === "vertical"), this.elements.container.classList.toggle("ci-before-after-container--hover-mode", this.config.mode === "hover"), this.elements.container.classList.toggle("ci-before-after-container--click-mode", this.config.mode === "click"), this.elements.viewport.classList.toggle("ci-before-after-viewport--zoomable", this.config.zoom), (this.config.handleStyle !== t.handleStyle || this.config.orientation !== t.orientation) && this.rebuildHandle(), this.config.mode !== t.mode && ((l = this.sliderGestures) == null || l.updateMode(this.config.mode)), this.config.orientation !== t.orientation && ((a = this.sliderGestures) == null || a.updateOrientation(this.config.orientation)), (this.config.labelsEnabled !== t.labelsEnabled || this.config.labelBefore !== t.labelBefore || this.config.labelAfter !== t.labelAfter || this.config.labelPosition !== t.labelPosition || this.config.orientation !== t.orientation) && this.rebuildLabels(), this.config.zoom !== t.zoom)
842
+ this.rebuildZoom();
843
+ else if (this.zoomPan && (this.zoomPan.updateConfig(this.config), this.config.scrollHint !== t.scrollHint && ((c = this.scrollHint) == null || c.destroy(), this.scrollHint = null, this.config.scrollHint && (this.scrollHint = new oe(this.elements.container))), (this.config.zoomControls !== t.zoomControls || this.config.zoomControlsPosition !== t.zoomControlsPosition) && ((h = this.zoomControlsEvents) == null || h.destroy(), this.zoomControlsEvents = null, (m = this.zoomControlsEl) == null || m.remove(), this.zoomControlsEl = null, this.elements.container.classList.remove("ci-before-after-container--zoom-top-right"), this.elements.container.classList.remove("ci-before-after-container--zoom-top"), this.elements.container.classList.remove("ci-before-after-container--zoom-left"), this.config.zoomControls))) {
844
+ const g = ie(
845
+ this.config.zoomControlsPosition,
846
+ {
847
+ onZoomIn: () => {
848
+ var u;
849
+ return (u = this.zoomPan) == null ? void 0 : u.zoomIn();
850
+ },
851
+ onZoomOut: () => {
852
+ var u;
853
+ return (u = this.zoomPan) == null ? void 0 : u.zoomOut();
854
+ },
855
+ onReset: () => {
856
+ var u;
857
+ return (u = this.zoomPan) == null ? void 0 : u.resetZoom();
858
+ }
859
+ }
860
+ );
861
+ this.zoomControlsEl = g.element, this.zoomControlsEvents = g.events, this.elements.container.appendChild(this.zoomControlsEl), this.applyZoomPositionClasses();
862
+ }
863
+ this.config.initialPosition !== t.initialPosition && this.updatePosition(this.config.initialPosition), this.config.fullscreenButton !== t.fullscreenButton && this.rebuildFullscreen(), this.config.animateEnabled !== t.animateEnabled && ((b = this.entranceAnimation) == null || b.destroy(), this.entranceAnimation = null, this.config.animateEnabled && this.initEntranceAnimation()), (p = this.keyboardHandler) == null || p.updateConfig(
864
+ this.config.orientation,
865
+ this.config.keyboardStep,
866
+ this.config.keyboardLargeStep,
867
+ this.config.zoom
868
+ ), this.updatePosition(this.state.position);
869
+ }
870
+ destroy() {
871
+ var e, t, i, n, r, s, l, a, c, h, m;
872
+ (e = this.sliderGestures) == null || e.destroy(), (t = this.zoomGestures) == null || t.destroy(), (i = this.zoomPan) == null || i.destroy(), this.zoomPan = null, (n = this.scrollHint) == null || n.destroy(), (r = this.fullscreenManager) == null || r.destroy(), (s = this.entranceAnimation) == null || s.destroy(), (l = this.keyboardHandler) == null || l.destroy(), this.events.destroy(), this.imageEvents.destroy(), (a = this.resizeObserver) == null || a.disconnect(), (c = this.lazyLoadObserver) == null || c.disconnect(), this.lazyLoadObserver = null, (h = this.zoomControlsEvents) == null || h.destroy(), this.zoomControlsEvents = null, (m = this.zoomControlsEl) == null || m.remove(), this.resizeDebounceTimer && clearTimeout(this.resizeDebounceTimer), this.animTransitionTimer && clearTimeout(this.animTransitionTimer), this.elements.container.innerHTML = "", this.elements.container.removeAttribute("role"), this.elements.container.removeAttribute("aria-label"), this.elements.container.className = this.elements.container.className.split(" ").filter((b) => !b.startsWith("ci-before-after")).join(" ");
873
+ }
874
+ // --- Private Methods ---
875
+ buildDOM(e) {
876
+ e.innerHTML = "";
877
+ const t = `ci-before-after-container--${this.config.orientation}`;
878
+ e.classList.add("ci-before-after-container", t), this.config.mode === "hover" && e.classList.add("ci-before-after-container--hover-mode"), this.config.mode === "click" && e.classList.add("ci-before-after-container--click-mode"), this.config.theme === "dark" && e.classList.add("ci-before-after-theme-dark"), e.classList.add("ci-before-after-loading"), je(e);
879
+ const i = f("div", "ci-before-after-viewport");
880
+ this.config.zoom && i.classList.add("ci-before-after-viewport--zoomable");
881
+ const n = f("div", "ci-before-after-wrapper"), r = f("img", "ci-before-after-image ci-before-after-before", {
882
+ alt: this.config.beforeAlt,
883
+ draggable: "false",
884
+ role: "img"
885
+ }), s = f("div", "ci-before-after-clip");
886
+ M(s, this.state.position, this.config.orientation);
887
+ const l = f("img", "ci-before-after-image ci-before-after-after", {
888
+ alt: this.config.afterAlt,
889
+ draggable: "false",
890
+ role: "img"
891
+ });
892
+ s.appendChild(l), n.append(r, s), i.appendChild(n), e.appendChild(i);
893
+ const a = Q(this.config.handleStyle, this.config.orientation, this.state.position);
894
+ e.appendChild(a);
895
+ const c = a.querySelector(".ci-before-after-handle-grip");
896
+ let h = null, m = null;
897
+ if (this.config.labelsEnabled) {
898
+ const b = ne(
899
+ this.config.labelBefore,
900
+ this.config.labelAfter,
901
+ this.config.labelPosition,
902
+ this.config.orientation
903
+ );
904
+ h = b.before, m = b.after, e.append(h, m);
905
+ }
906
+ this.elements = {
907
+ container: e,
908
+ viewport: i,
909
+ wrapper: n,
910
+ beforeImage: r,
911
+ afterImage: l,
912
+ clip: s,
913
+ handle: a,
914
+ handleGrip: c,
915
+ labelBefore: h,
916
+ labelAfter: m
917
+ };
918
+ }
919
+ initModules() {
920
+ this.sliderGestures = new ee(
921
+ this.elements.container,
922
+ this.elements.handle,
923
+ this.config.mode,
924
+ this.config.orientation,
925
+ {
926
+ onPositionChange: (e) => this.updatePosition(e),
927
+ onDragStart: () => this.onDragStart(),
928
+ onDragEnd: () => this.onDragEnd()
929
+ }
930
+ ), this.keyboardHandler = new le(
931
+ this.elements.handle,
932
+ this.config.orientation,
933
+ this.config.keyboardStep,
934
+ this.config.keyboardLargeStep,
935
+ this.config.zoom,
936
+ {
937
+ onPositionChange: (e) => this.updatePosition(e),
938
+ getPosition: () => this.state.position,
939
+ onZoomIn: () => {
940
+ var e;
941
+ return (e = this.zoomPan) == null ? void 0 : e.zoomIn();
942
+ },
943
+ onZoomOut: () => {
944
+ var e;
945
+ return (e = this.zoomPan) == null ? void 0 : e.zoomOut();
946
+ },
947
+ onZoomReset: () => {
948
+ var e;
949
+ return (e = this.zoomPan) == null ? void 0 : e.resetZoom();
950
+ }
951
+ }
952
+ ), this.config.zoom && this.initZoom(), this.config.fullscreenButton && (this.elements.container.classList.add("ci-before-after-container--has-fullscreen"), this.fullscreenManager = new ae(
953
+ this.elements.container,
954
+ (e) => {
955
+ this.state.isFullscreen = e, L(this.config.onFullscreenChange, e);
956
+ }
957
+ )), this.config.animateEnabled && this.initEntranceAnimation(), this.config.cloudimage && this.initResizeObserver();
958
+ }
959
+ initZoom() {
960
+ if (this.zoomPan = new Be(
961
+ this.elements.viewport,
962
+ this.elements.container,
963
+ this.config,
964
+ (e) => {
965
+ this.state.zoomLevel = e, this.syncClip(), L(this.config.onZoom, e);
966
+ },
967
+ () => this.syncClip()
968
+ ), this.config.scrollHint && (this.scrollHint = new oe(this.elements.container)), this.zoomGestures = new te(
969
+ this.elements.container,
970
+ this.elements.handle,
971
+ this.zoomPan,
972
+ () => {
973
+ var e;
974
+ return (e = this.scrollHint) == null ? void 0 : e.show();
975
+ }
976
+ ), this.config.zoomControls) {
977
+ const e = ie(
978
+ this.config.zoomControlsPosition,
979
+ {
980
+ onZoomIn: () => {
981
+ var t;
982
+ return (t = this.zoomPan) == null ? void 0 : t.zoomIn();
983
+ },
984
+ onZoomOut: () => {
985
+ var t;
986
+ return (t = this.zoomPan) == null ? void 0 : t.zoomOut();
987
+ },
988
+ onReset: () => {
989
+ var t;
990
+ return (t = this.zoomPan) == null ? void 0 : t.resetZoom();
991
+ }
992
+ }
993
+ );
994
+ this.zoomControlsEl = e.element, this.zoomControlsEvents = e.events, this.elements.container.appendChild(this.zoomControlsEl), this.applyZoomPositionClasses();
995
+ }
996
+ }
997
+ applyZoomPositionClasses() {
998
+ const e = this.config.zoomControlsPosition;
999
+ this.elements.container.classList.toggle("ci-before-after-container--zoom-top-right", e === "top-right"), this.elements.container.classList.toggle("ci-before-after-container--zoom-top", e.startsWith("top-")), this.elements.container.classList.toggle("ci-before-after-container--zoom-left", e.endsWith("-left"));
1000
+ }
1001
+ initEntranceAnimation() {
1002
+ this.animTransitionTimer && (clearTimeout(this.animTransitionTimer), this.animTransitionTimer = null, this.elements.handle.style.transition = "", this.elements.clip.style.transition = "");
1003
+ const e = 0;
1004
+ this.suppressCallbacks = !0, this.updatePosition(e), this.suppressCallbacks = !1, this.entranceAnimation = new We(
1005
+ this.elements.container,
1006
+ this.config.animateDuration,
1007
+ this.config.animateDelay,
1008
+ this.config.animateEasing,
1009
+ this.config.animateOnce,
1010
+ (t) => {
1011
+ t || (this.elements.handle.style.transition = `left ${this.config.animateDuration}ms ${this.config.animateEasing}, top ${this.config.animateDuration}ms ${this.config.animateEasing}`, this.elements.clip.style.transition = `clip-path ${this.config.animateDuration}ms ${this.config.animateEasing}`), this.updatePosition(this.config.initialPosition), t || (this.animTransitionTimer = setTimeout(() => {
1012
+ this.animTransitionTimer = null, this.elements.handle.style.transition = "", this.elements.clip.style.transition = "";
1013
+ }, this.config.animateDuration));
1014
+ }
1015
+ );
1016
+ }
1017
+ loadImages() {
1018
+ const e = this.resolveImageSrc(this.config.beforeSrc), t = this.resolveImageSrc(this.config.afterSrc);
1019
+ this.config.lazyLoad && typeof IntersectionObserver < "u" ? (this.lazyLoadObserver = new IntersectionObserver(
1020
+ (i) => {
1021
+ var n;
1022
+ for (const r of i)
1023
+ r.isIntersecting && (this.elements.beforeImage.src = e, this.elements.afterImage.src = t, (n = this.lazyLoadObserver) == null || n.disconnect(), this.lazyLoadObserver = null);
1024
+ },
1025
+ { threshold: 0 }
1026
+ ), this.lazyLoadObserver.observe(this.elements.container)) : (this.elements.beforeImage.src = e, this.elements.afterImage.src = t), this.registerImageLoadHandlers(!0, !0);
1027
+ }
1028
+ /**
1029
+ * Register load/error handlers for images. Cleans up previous handlers first.
1030
+ * When only one image changed, the unchanged image is treated as already loaded.
1031
+ */
1032
+ registerImageLoadHandlers(e, t) {
1033
+ this.imageEvents.destroy();
1034
+ let i = !e, n = !t;
1035
+ const r = () => {
1036
+ i && n && this.onImagesReady();
1037
+ }, s = () => {
1038
+ i || (i = !0, r());
1039
+ }, l = () => {
1040
+ n || (n = !0, r());
1041
+ }, a = () => {
1042
+ console.warn(`CIBeforeAfter: Failed to load image "${this.elements.beforeImage.src}"`), i || (i = !0, r());
1043
+ }, c = () => {
1044
+ console.warn(`CIBeforeAfter: Failed to load image "${this.elements.afterImage.src}"`), n || (n = !0, r());
1045
+ };
1046
+ this.imageEvents.on(this.elements.beforeImage, "load", s), this.imageEvents.on(this.elements.afterImage, "load", l), this.imageEvents.on(this.elements.beforeImage, "error", a), this.imageEvents.on(this.elements.afterImage, "error", c), this.elements.beforeImage.complete && this.elements.beforeImage.src && s(), this.elements.afterImage.complete && this.elements.afterImage.src && l();
1047
+ }
1048
+ onImagesReady() {
1049
+ if (this.state.isReady) return;
1050
+ this.state.isReady = !0;
1051
+ const { naturalWidth: e, naturalHeight: t } = this.elements.beforeImage;
1052
+ e && t && (this.elements.wrapper.style.aspectRatio = `${e} / ${t}`), this.elements.container.classList.remove("ci-before-after-loading"), L(this.config.onReady);
1053
+ }
1054
+ getClipZoomInfo() {
1055
+ if (!this.zoomPan || this.zoomPan.getZoom() <= 1) return;
1056
+ const e = this.zoomPan.getPan(), t = this.zoomPan.getContainerSize();
1057
+ return {
1058
+ level: this.zoomPan.getZoom(),
1059
+ panX: e.x,
1060
+ panY: e.y,
1061
+ containerWidth: t.width,
1062
+ containerHeight: t.height
1063
+ };
1064
+ }
1065
+ syncClip() {
1066
+ M(this.elements.clip, this.state.position, this.config.orientation, this.getClipZoomInfo());
1067
+ }
1068
+ updatePosition(e) {
1069
+ this.state.position = J(e), M(this.elements.clip, this.state.position, this.config.orientation, this.getClipZoomInfo()), Ee(this.elements.handle, this.state.position, this.config.orientation), Ne(this.elements.handle, this.state.position), re(
1070
+ this.elements.labelBefore,
1071
+ this.elements.labelAfter,
1072
+ this.state.position,
1073
+ this.config.orientation
1074
+ ), this.suppressCallbacks || L(this.config.onSlide, this.state.position);
1075
+ }
1076
+ onDragStart() {
1077
+ this.state.isDragging = !0, this.elements.container.classList.add("ci-before-after-container--dragging");
1078
+ }
1079
+ onDragEnd() {
1080
+ this.state.isDragging = !1, this.elements.container.classList.remove("ci-before-after-container--dragging");
1081
+ }
1082
+ resolveImageSrc(e) {
1083
+ if (this.config.cloudimage) {
1084
+ const t = this.elements.container.getBoundingClientRect().width || 800;
1085
+ return Le(e, t, this.config.cloudimage);
1086
+ }
1087
+ return e;
1088
+ }
1089
+ rebuildHandle() {
1090
+ var i, n;
1091
+ const e = document.activeElement === this.elements.handle;
1092
+ this.elements.handle.remove();
1093
+ const t = Q(this.config.handleStyle, this.config.orientation, this.state.position);
1094
+ this.elements.container.appendChild(t), this.elements.handle = t, this.elements.handleGrip = t.querySelector(".ci-before-after-handle-grip"), (i = this.sliderGestures) == null || i.destroy(), this.sliderGestures = new ee(
1095
+ this.elements.container,
1096
+ this.elements.handle,
1097
+ this.config.mode,
1098
+ this.config.orientation,
1099
+ {
1100
+ onPositionChange: (r) => this.updatePosition(r),
1101
+ onDragStart: () => this.onDragStart(),
1102
+ onDragEnd: () => this.onDragEnd()
1103
+ }
1104
+ ), (n = this.keyboardHandler) == null || n.destroy(), this.keyboardHandler = new le(
1105
+ this.elements.handle,
1106
+ this.config.orientation,
1107
+ this.config.keyboardStep,
1108
+ this.config.keyboardLargeStep,
1109
+ this.config.zoom,
1110
+ {
1111
+ onPositionChange: (r) => this.updatePosition(r),
1112
+ getPosition: () => this.state.position,
1113
+ onZoomIn: () => {
1114
+ var r;
1115
+ return (r = this.zoomPan) == null ? void 0 : r.zoomIn();
1116
+ },
1117
+ onZoomOut: () => {
1118
+ var r;
1119
+ return (r = this.zoomPan) == null ? void 0 : r.zoomOut();
1120
+ },
1121
+ onZoomReset: () => {
1122
+ var r;
1123
+ return (r = this.zoomPan) == null ? void 0 : r.resetZoom();
1124
+ }
1125
+ }
1126
+ ), this.zoomGestures && this.zoomPan && (this.zoomGestures.destroy(), this.zoomGestures = new te(
1127
+ this.elements.container,
1128
+ this.elements.handle,
1129
+ this.zoomPan,
1130
+ () => {
1131
+ var r;
1132
+ return (r = this.scrollHint) == null ? void 0 : r.show();
1133
+ }
1134
+ )), e && this.elements.handle.focus();
1135
+ }
1136
+ rebuildLabels() {
1137
+ var e, t;
1138
+ if ((e = this.elements.labelBefore) == null || e.remove(), (t = this.elements.labelAfter) == null || t.remove(), this.elements.labelBefore = null, this.elements.labelAfter = null, this.config.labelsEnabled) {
1139
+ const i = ne(
1140
+ this.config.labelBefore,
1141
+ this.config.labelAfter,
1142
+ this.config.labelPosition,
1143
+ this.config.orientation
1144
+ );
1145
+ this.elements.labelBefore = i.before, this.elements.labelAfter = i.after, this.elements.container.append(i.before, i.after), re(i.before, i.after, this.state.position, this.config.orientation);
1146
+ }
1147
+ }
1148
+ rebuildZoom() {
1149
+ var e, t, i, n, r;
1150
+ (e = this.zoomGestures) == null || e.destroy(), this.zoomGestures = null, (t = this.scrollHint) == null || t.destroy(), this.scrollHint = null, (i = this.zoomControlsEvents) == null || i.destroy(), this.zoomControlsEvents = null, (n = this.zoomControlsEl) == null || n.remove(), this.zoomControlsEl = null, (r = this.zoomPan) == null || r.destroy(), this.zoomPan = null, this.elements.container.classList.remove("ci-before-after-container--zoom-top-right"), this.elements.container.classList.remove("ci-before-after-container--zoom-top"), this.elements.container.classList.remove("ci-before-after-container--zoom-left"), this.config.zoom && this.initZoom();
1151
+ }
1152
+ rebuildFullscreen() {
1153
+ var e;
1154
+ (e = this.fullscreenManager) == null || e.destroy(), this.fullscreenManager = null, this.elements.container.classList.remove("ci-before-after-container--has-fullscreen"), this.config.fullscreenButton && (this.elements.container.classList.add("ci-before-after-container--has-fullscreen"), this.fullscreenManager = new ae(
1155
+ this.elements.container,
1156
+ (t) => {
1157
+ this.state.isFullscreen = t, L(this.config.onFullscreenChange, t);
1158
+ }
1159
+ ));
1160
+ }
1161
+ initResizeObserver() {
1162
+ typeof ResizeObserver > "u" || (this.resizeObserver = new ResizeObserver(() => {
1163
+ this.resizeDebounceTimer && clearTimeout(this.resizeDebounceTimer), this.resizeDebounceTimer = setTimeout(() => {
1164
+ if (this.config.cloudimage) {
1165
+ const e = this.resolveImageSrc(this.config.beforeSrc), t = this.resolveImageSrc(this.config.afterSrc);
1166
+ this.elements.beforeImage.src !== e && (this.elements.beforeImage.src = e), this.elements.afterImage.src !== t && (this.elements.afterImage.src = t);
1167
+ }
1168
+ this.resizeDebounceTimer = null;
1169
+ }, 200);
1170
+ }), this.resizeObserver.observe(this.elements.container));
1171
+ }
1172
+ }
1173
+ function L(o, ...e) {
1174
+ if (o)
1175
+ try {
1176
+ o(...e);
1177
+ } catch (t) {
1178
+ console.error("CIBeforeAfter: callback error:", t);
1179
+ }
1180
+ }
1181
+ function Ge(o, e) {
1182
+ if (o === e) return !0;
1183
+ if (!o || !e) return !1;
1184
+ const t = Object.keys(o), i = Object.keys(e);
1185
+ if (t.length !== i.length) return !1;
1186
+ for (const n of t)
1187
+ if (o[n] !== e[n]) return !1;
1188
+ return !0;
1189
+ }
1190
+ const ce = ".ci-before-after-container{--ci-before-after-handle-width: 4px;--ci-before-after-handle-color: #ffffff;--ci-before-after-handle-shadow: 0 0 8px rgba(0, 0, 0, .3);--ci-before-after-grip-size: 44px;--ci-before-after-grip-bg: #ffffff;--ci-before-after-grip-border: 2px solid rgba(0, 0, 0, .1);--ci-before-after-grip-border-radius: 50%;--ci-before-after-grip-shadow: 0 2px 8px rgba(0, 0, 0, .2);--ci-before-after-grip-icon-color: #333333;--ci-before-after-grip-icon-size: 20px;--ci-before-after-grip-hover-bg: #f0f0f0;--ci-before-after-grip-hover-shadow: 0 4px 16px rgba(0, 0, 0, .25);--ci-before-after-grip-active-bg: #e0e0e0;--ci-before-after-grip-active-scale: .95;--ci-before-after-label-font-family: inherit;--ci-before-after-label-font-size: 14px;--ci-before-after-label-font-weight: 600;--ci-before-after-label-color: #ffffff;--ci-before-after-label-bg: rgba(0, 0, 0, .5);--ci-before-after-label-padding: 6px 14px;--ci-before-after-label-border-radius: 6px;--ci-before-after-label-offset-x: 12px;--ci-before-after-label-offset-y: 12px;--ci-before-after-label-backdrop-filter: blur(4px);--ci-before-after-handle-transition: .15s ease;--ci-before-after-slide-transition: 0ms;--ci-before-after-animate-duration: .8s;--ci-before-after-animate-easing: ease-out;--ci-before-after-zoom-controls-bg: rgba(255, 255, 255, .9);--ci-before-after-zoom-controls-color: #333333;--ci-before-after-zoom-controls-border-radius: 8px;--ci-before-after-zoom-controls-shadow: 0 2px 8px rgba(0, 0, 0, .15)}.ci-before-after-theme-dark{--ci-before-after-handle-color: #1a1a1a;--ci-before-after-handle-shadow: 0 0 8px rgba(255, 255, 255, .2);--ci-before-after-grip-bg: #1a1a1a;--ci-before-after-grip-border: 2px solid rgba(255, 255, 255, .2);--ci-before-after-grip-shadow: 0 2px 8px rgba(0, 0, 0, .5);--ci-before-after-grip-icon-color: #f0f0f0;--ci-before-after-grip-hover-bg: #2a2a2a;--ci-before-after-grip-active-bg: #333333;--ci-before-after-label-bg: rgba(0, 0, 0, .45);--ci-before-after-label-color: #f0f0f0;--ci-before-after-zoom-controls-bg: rgba(30, 30, 30, .9);--ci-before-after-zoom-controls-color: #f0f0f0}.ci-before-after-container{position:relative;overflow:hidden;width:100%;border-radius:var(--ci-before-after-border-radius, 0px);box-shadow:var(--ci-before-after-shadow, none);user-select:none;-webkit-user-select:none;touch-action:pan-y;line-height:0}.ci-before-after-container--vertical{touch-action:pan-x}.ci-before-after-container--fullscreen{background:#000;display:flex;align-items:center;justify-content:center;width:100vw;height:100vh}.ci-before-after-container--fullscreen .ci-before-after-wrapper{max-height:100vh}.ci-before-after-container--fullscreen .ci-before-after-image{object-fit:contain}.ci-before-after-container--dragging{cursor:ew-resize}.ci-before-after-container--vertical.ci-before-after-container--dragging{cursor:ns-resize}.ci-before-after-viewport{position:relative;width:100%;height:100%;transform-origin:0 0}.ci-before-after-viewport--zoomable{will-change:transform}.ci-before-after-wrapper{position:relative;width:100%;overflow:hidden}.ci-before-after-image{display:block;width:100%;height:100%;object-fit:cover}.ci-before-after-before{display:block;width:100%}.ci-before-after-after{position:absolute;top:0;left:0;width:100%;height:100%}.ci-before-after-clip{position:absolute;top:0;left:0;right:0;bottom:0}.ci-before-after-handle{position:absolute;top:0;bottom:0;display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:10;transform:translate(-50%);cursor:ew-resize;outline:none}.ci-before-after-handle:focus-visible .ci-before-after-handle-grip{outline:3px solid #4d90fe;outline-offset:2px}.ci-before-after-container--vertical .ci-before-after-handle{top:auto;bottom:auto;left:0;right:0;flex-direction:row;transform:translateY(-50%);cursor:ns-resize}.ci-before-after-handle-line{flex:1;width:var(--ci-before-after-handle-width);background:var(--ci-before-after-handle-color);box-shadow:var(--ci-before-after-handle-shadow)}.ci-before-after-container--vertical .ci-before-after-handle-line{width:auto;height:var(--ci-before-after-handle-width);flex:1}.ci-before-after-handle-grip{display:flex;align-items:center;justify-content:center;width:var(--ci-before-after-grip-size);height:var(--ci-before-after-grip-size);background:var(--ci-before-after-grip-bg);border:var(--ci-before-after-grip-border);border-radius:var(--ci-before-after-grip-border-radius);box-shadow:var(--ci-before-after-grip-shadow);color:var(--ci-before-after-grip-icon-color);flex-shrink:0;transition:background .15s ease,box-shadow .15s ease,transform .15s ease}.ci-before-after-handle-grip svg{width:var(--ci-before-after-grip-icon-size);height:var(--ci-before-after-grip-icon-size)}.ci-before-after-handle-grip:hover,.ci-before-after-handle:hover .ci-before-after-handle-grip{background:var(--ci-before-after-grip-hover-bg);box-shadow:var(--ci-before-after-grip-hover-shadow);transform:scale(1.1)}.ci-before-after-container--dragging .ci-before-after-handle-grip{background:var(--ci-before-after-grip-active-bg);transform:scale(var(--ci-before-after-grip-active-scale))}.ci-before-after-handle--line .ci-before-after-handle-grip,.ci-before-after-handle--line .ci-before-after-handle-grip--pill{width:8px;height:32px;border-radius:4px}.ci-before-after-container--vertical .ci-before-after-handle--line .ci-before-after-handle-grip{width:32px;height:8px}.ci-before-after-handle--circle .ci-before-after-handle-line{display:none}.ci-before-after-label{position:absolute;z-index:5;font-family:var(--ci-before-after-label-font-family);font-size:var(--ci-before-after-label-font-size);font-weight:var(--ci-before-after-label-font-weight);color:var(--ci-before-after-label-color);background:var(--ci-before-after-label-bg);padding:var(--ci-before-after-label-padding);border-radius:var(--ci-before-after-label-border-radius);backdrop-filter:var(--ci-before-after-label-backdrop-filter);-webkit-backdrop-filter:var(--ci-before-after-label-backdrop-filter);pointer-events:none;line-height:1.2;transition:opacity .2s ease;opacity:1}.ci-before-after-label--hidden{opacity:0}.ci-before-after-container--horizontal .ci-before-after-label--top.ci-before-after-label-before{top:var(--ci-before-after-label-offset-y);left:25%;transform:translate(-50%)}.ci-before-after-container--horizontal .ci-before-after-label--top.ci-before-after-label-after{top:var(--ci-before-after-label-offset-y);left:75%;transform:translate(-50%)}.ci-before-after-container--horizontal .ci-before-after-label--bottom.ci-before-after-label-before{bottom:var(--ci-before-after-label-offset-y);left:25%;transform:translate(-50%)}.ci-before-after-container--horizontal .ci-before-after-label--bottom.ci-before-after-label-after{bottom:var(--ci-before-after-label-offset-y);left:75%;transform:translate(-50%)}.ci-before-after-container--vertical .ci-before-after-label--top.ci-before-after-label-before{top:var(--ci-before-after-label-offset-y);left:var(--ci-before-after-label-offset-x)}.ci-before-after-container--vertical .ci-before-after-label--top.ci-before-after-label-after{bottom:var(--ci-before-after-label-offset-y);left:var(--ci-before-after-label-offset-x)}.ci-before-after-container--vertical .ci-before-after-label--bottom.ci-before-after-label-before{top:var(--ci-before-after-label-offset-y);right:var(--ci-before-after-label-offset-x)}.ci-before-after-container--vertical .ci-before-after-label--bottom.ci-before-after-label-after{bottom:var(--ci-before-after-label-offset-y);right:var(--ci-before-after-label-offset-x)}.ci-before-after-container--vertical.ci-before-after-container--zoom-left .ci-before-after-label--top.ci-before-after-label-before,.ci-before-after-container--vertical.ci-before-after-container--zoom-left .ci-before-after-label--top.ci-before-after-label-after{left:calc(var(--ci-before-after-label-offset-x) + 44px)}.ci-before-after-zoom-controls{position:absolute;z-index:20;display:flex;gap:2px;background:var(--ci-before-after-zoom-controls-bg);border-radius:var(--ci-before-after-zoom-controls-border-radius);box-shadow:var(--ci-before-after-zoom-controls-shadow);padding:0;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.ci-before-after-zoom-controls button{display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:none;background:transparent;color:var(--ci-before-after-zoom-controls-color);cursor:pointer;border-radius:6px;padding:0;transition:background .15s ease}.ci-before-after-zoom-controls button:hover{background:#00000014}.ci-before-after-theme-dark .ci-before-after-zoom-controls button:hover{background:#ffffff1f}.ci-before-after-zoom-controls button:focus-visible{outline:2px solid #4d90fe;outline-offset:-2px}.ci-before-after-zoom-controls--top-left{top:12px;left:12px}.ci-before-after-zoom-controls--top-center{top:12px;left:50%;transform:translate(-50%)}.ci-before-after-zoom-controls--top-right{top:12px;right:12px}.ci-before-after-zoom-controls--bottom-left{bottom:12px;left:12px}.ci-before-after-zoom-controls--bottom-center{bottom:12px;left:50%;transform:translate(-50%)}.ci-before-after-zoom-controls--bottom-right{bottom:12px;right:12px}.ci-before-after-fullscreen-btn{position:absolute;top:12px;right:12px;z-index:20;display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:none;background:var(--ci-before-after-zoom-controls-bg);color:var(--ci-before-after-zoom-controls-color);border-radius:8px;cursor:pointer;box-shadow:var(--ci-before-after-zoom-controls-shadow);padding:0;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);transition:background .15s ease}.ci-before-after-fullscreen-btn:hover{background:#e6e6e6f2}.ci-before-after-theme-dark .ci-before-after-fullscreen-btn:hover{background:#323232f2}.ci-before-after-fullscreen-btn:focus-visible{outline:2px solid #4d90fe;outline-offset:2px}.ci-before-after-container--zoom-top-right .ci-before-after-fullscreen-btn{right:132px}.ci-before-after-container--zoom-top.ci-before-after-container--horizontal .ci-before-after-label--top{top:auto;bottom:var(--ci-before-after-label-offset-y)}.ci-before-after-scroll-hint{position:absolute;bottom:50%;left:50%;transform:translate(-50%,50%);z-index:30;background:#000000bf;color:#fff;padding:8px 16px;border-radius:8px;font-size:13px;font-weight:500;white-space:nowrap;pointer-events:none;opacity:0;transition:opacity .2s ease;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);line-height:1.4}.ci-before-after-scroll-hint--visible{opacity:1}.ci-before-after-loading .ci-before-after-wrapper{min-height:200px;background:linear-gradient(90deg,#f0f0f0 25%,#e0e0e0,#f0f0f0 75%);background-size:200% 100%;animation:ci-before-after-shimmer 1.5s infinite}.ci-before-after-theme-dark.ci-before-after-loading .ci-before-after-wrapper{background:linear-gradient(90deg,#2a2a2a 25%,#333,#2a2a2a 75%);background-size:200% 100%}@keyframes ci-before-after-shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}.ci-before-after-container--hover-mode{cursor:ew-resize}.ci-before-after-container--vertical.ci-before-after-container--hover-mode{cursor:ns-resize}.ci-before-after-container--click-mode{cursor:pointer}@media(prefers-reduced-motion:reduce){.ci-before-after-container,.ci-before-after-container *{animation:none!important;transition-duration:.01ms!important}}";
1191
+ class ge extends _e {
1192
+ static autoInit(e) {
1193
+ if (!S()) return [];
1194
+ U(ce);
1195
+ const i = (e || document).querySelectorAll("[data-ci-before-after-before-src]"), n = [];
1196
+ return i.forEach((r) => {
1197
+ const s = pe(r);
1198
+ n.push(new ge(r, s));
1199
+ }), n;
1200
+ }
1201
+ constructor(e, t) {
1202
+ U(ce), super(e, t);
1203
+ }
1204
+ }
1205
+ export {
1206
+ ge as CIBeforeAfter,
1207
+ _e as CIBeforeAfterCore,
1208
+ ge as default
1209
+ };
1210
+ //# sourceMappingURL=js-cloudimage-before-after.esm.js.map