js-cloudimage-hotspot 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.
- package/LICENSE +21 -0
- package/README.md +294 -0
- package/dist/a11y/aria.d.ts +7 -0
- package/dist/a11y/aria.d.ts.map +1 -0
- package/dist/a11y/focus.d.ts +9 -0
- package/dist/a11y/focus.d.ts.map +1 -0
- package/dist/a11y/keyboard.d.ts +14 -0
- package/dist/a11y/keyboard.d.ts.map +1 -0
- package/dist/core/CIHotspot.d.ts +48 -0
- package/dist/core/CIHotspot.d.ts.map +1 -0
- package/dist/core/ci-hotspot.d.ts +95 -0
- package/dist/core/ci-hotspot.d.ts.map +1 -0
- package/dist/core/config.d.ts +15 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/types.d.ts +227 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/editor/ci-hotspot-editor.d.ts +58 -0
- package/dist/editor/ci-hotspot-editor.d.ts.map +1 -0
- package/dist/editor/drag-manager.d.ts +18 -0
- package/dist/editor/drag-manager.d.ts.map +1 -0
- package/dist/editor/editor-toolbar.d.ts +26 -0
- package/dist/editor/editor-toolbar.d.ts.map +1 -0
- package/dist/editor/index.d.ts +3 -0
- package/dist/editor/index.d.ts.map +1 -0
- package/dist/editor/js-cloudimage-hotspot-editor.cjs.js +4 -0
- package/dist/editor/js-cloudimage-hotspot-editor.cjs.js.map +1 -0
- package/dist/editor/js-cloudimage-hotspot-editor.esm.js +1981 -0
- package/dist/editor/js-cloudimage-hotspot-editor.esm.js.map +1 -0
- package/dist/editor/js-cloudimage-hotspot-editor.min.js +4 -0
- package/dist/editor/js-cloudimage-hotspot-editor.min.js.map +1 -0
- package/dist/editor/property-panel.d.ts +17 -0
- package/dist/editor/property-panel.d.ts.map +1 -0
- package/dist/editor/selection-manager.d.ts +15 -0
- package/dist/editor/selection-manager.d.ts.map +1 -0
- package/dist/editor/types.d.ts +32 -0
- package/dist/editor/types.d.ts.map +1 -0
- package/dist/editor/undo-manager.d.ts +16 -0
- package/dist/editor/undo-manager.d.ts.map +1 -0
- package/dist/fullscreen/fullscreen.d.ts +14 -0
- package/dist/fullscreen/fullscreen.d.ts.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/js-cloudimage-hotspot.cjs.js +2 -0
- package/dist/js-cloudimage-hotspot.cjs.js.map +1 -0
- package/dist/js-cloudimage-hotspot.esm.js +1408 -0
- package/dist/js-cloudimage-hotspot.esm.js.map +1 -0
- package/dist/js-cloudimage-hotspot.min.js +2 -0
- package/dist/js-cloudimage-hotspot.min.js.map +1 -0
- package/dist/markers/Marker.d.ts +10 -0
- package/dist/markers/Marker.d.ts.map +1 -0
- package/dist/markers/pulse.d.ts +9 -0
- package/dist/markers/pulse.d.ts.map +1 -0
- package/dist/popover/Popover.d.ts +41 -0
- package/dist/popover/Popover.d.ts.map +1 -0
- package/dist/popover/position.d.ts +6 -0
- package/dist/popover/position.d.ts.map +1 -0
- package/dist/popover/sanitize.d.ts +6 -0
- package/dist/popover/sanitize.d.ts.map +1 -0
- package/dist/popover/template.d.ts +9 -0
- package/dist/popover/template.d.ts.map +1 -0
- package/dist/react/index.cjs +2 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.js +1617 -0
- package/dist/react/index.js.map +1 -0
- package/dist/utils/cloudimage.d.ts +16 -0
- package/dist/utils/cloudimage.d.ts.map +1 -0
- package/dist/utils/coordinates.d.ts +17 -0
- package/dist/utils/coordinates.d.ts.map +1 -0
- package/dist/utils/dom.d.ts +13 -0
- package/dist/utils/dom.d.ts.map +1 -0
- package/dist/utils/events.d.ts +15 -0
- package/dist/utils/events.d.ts.map +1 -0
- package/dist/zoom/ScrollHint.d.ts +8 -0
- package/dist/zoom/ScrollHint.d.ts.map +1 -0
- package/dist/zoom/ZoomPan.d.ts +51 -0
- package/dist/zoom/ZoomPan.d.ts.map +1 -0
- package/dist/zoom/controls.d.ts +14 -0
- package/dist/zoom/controls.d.ts.map +1 -0
- package/dist/zoom/gestures.d.ts +28 -0
- package/dist/zoom/gestures.d.ts.map +1 -0
- package/dist/zoom/scroll-hint.d.ts +8 -0
- package/dist/zoom/scroll-hint.d.ts.map +1 -0
- package/dist/zoom/zoom-pan.d.ts +53 -0
- package/dist/zoom/zoom-pan.d.ts.map +1 -0
- package/package.json +97 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/** Popover trigger mode */
|
|
2
|
+
export type TriggerMode = 'hover' | 'click' | 'load';
|
|
3
|
+
/** Popover placement preference */
|
|
4
|
+
export type Placement = 'top' | 'bottom' | 'left' | 'right' | 'auto';
|
|
5
|
+
/** Theme name */
|
|
6
|
+
export type Theme = 'light' | 'dark';
|
|
7
|
+
/** Scene transition animation type */
|
|
8
|
+
export type SceneTransition = 'fade' | 'slide' | 'none';
|
|
9
|
+
/** Zoom controls position */
|
|
10
|
+
export type ZoomControlsPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
|
|
11
|
+
/** A scene in multi-image navigation */
|
|
12
|
+
export interface Scene {
|
|
13
|
+
/** Unique scene identifier */
|
|
14
|
+
id: string;
|
|
15
|
+
/** Image source URL for this scene */
|
|
16
|
+
src: string;
|
|
17
|
+
/** Alt text for this scene's image */
|
|
18
|
+
alt?: string;
|
|
19
|
+
/** Hotspots specific to this scene */
|
|
20
|
+
hotspots: HotspotItem[];
|
|
21
|
+
}
|
|
22
|
+
/** Data fields for the built-in popover template */
|
|
23
|
+
export interface PopoverData {
|
|
24
|
+
title?: string;
|
|
25
|
+
price?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
image?: string;
|
|
28
|
+
url?: string;
|
|
29
|
+
ctaText?: string;
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
}
|
|
32
|
+
/** Cloudimage CDN integration configuration */
|
|
33
|
+
export interface CloudimageConfig {
|
|
34
|
+
/** Cloudimage customer token (e.g. 'demo'). Enables Cloudimage when set. */
|
|
35
|
+
token: string;
|
|
36
|
+
/** API version (default: 'v7') */
|
|
37
|
+
apiVersion?: string;
|
|
38
|
+
/** Custom Cloudimage domain (default: 'cloudimg.io') */
|
|
39
|
+
domain?: string;
|
|
40
|
+
/** Round requested width to nearest N pixels for better CDN caching. Default: 100 */
|
|
41
|
+
limitFactor?: number;
|
|
42
|
+
/** Custom URL transformation params (e.g. 'q=80&org_if_sml=1') */
|
|
43
|
+
params?: string;
|
|
44
|
+
/** Supported device pixel ratios (default: [1, 1.5, 2]) */
|
|
45
|
+
devicePixelRatioList?: number[];
|
|
46
|
+
}
|
|
47
|
+
/** Responsive breakpoint configuration for individual hotspots */
|
|
48
|
+
export interface ResponsiveConfig {
|
|
49
|
+
maxWidth?: number;
|
|
50
|
+
minWidth?: number;
|
|
51
|
+
/** Action when breakpoint matches. Currently only 'hide' is implemented. */
|
|
52
|
+
action?: 'hide' | 'collapse';
|
|
53
|
+
}
|
|
54
|
+
/** Individual hotspot definition */
|
|
55
|
+
export interface HotspotItem {
|
|
56
|
+
/** Unique identifier (required) */
|
|
57
|
+
id: string;
|
|
58
|
+
/** X coordinate: percentage string ('65%') or pixel number (650) */
|
|
59
|
+
x: string | number;
|
|
60
|
+
/** Y coordinate: percentage string ('40%') or pixel number (400) */
|
|
61
|
+
y: string | number;
|
|
62
|
+
/** Accessible label displayed as marker tooltip and used by screen readers */
|
|
63
|
+
label: string;
|
|
64
|
+
/** Arbitrary data passed to the popover template */
|
|
65
|
+
data?: PopoverData;
|
|
66
|
+
/** Raw HTML content for the popover (sanitized before rendering) */
|
|
67
|
+
content?: string;
|
|
68
|
+
/** Custom CSS class added to this marker element */
|
|
69
|
+
className?: string;
|
|
70
|
+
/** Override global trigger for this specific hotspot */
|
|
71
|
+
trigger?: TriggerMode;
|
|
72
|
+
/** Keep popover open until explicitly closed (default: false) */
|
|
73
|
+
keepOpen?: boolean;
|
|
74
|
+
/** Override global placement for this specific hotspot's popover */
|
|
75
|
+
placement?: Placement;
|
|
76
|
+
/** Custom click handler for this hotspot */
|
|
77
|
+
onClick?: (event: MouseEvent | KeyboardEvent, hotspot: HotspotItem) => void;
|
|
78
|
+
/** Whether this hotspot marker is initially hidden (default: false) */
|
|
79
|
+
hidden?: boolean;
|
|
80
|
+
/** Custom icon — CSS class name, SVG string, or image URL */
|
|
81
|
+
icon?: string;
|
|
82
|
+
/** Scene ID to navigate to on click (v1.3 multi-image) */
|
|
83
|
+
navigateTo?: string;
|
|
84
|
+
/** Rotation angle in degrees for the navigate arrow (default: 0 = right). E.g. 180 = left, 90 = down, -90 = up */
|
|
85
|
+
arrowDirection?: number;
|
|
86
|
+
/** Responsive breakpoint configuration */
|
|
87
|
+
responsive?: ResponsiveConfig;
|
|
88
|
+
}
|
|
89
|
+
/** Main library configuration */
|
|
90
|
+
export interface CIHotspotConfig {
|
|
91
|
+
/** Image source URL (required unless `scenes` is provided) */
|
|
92
|
+
src?: string;
|
|
93
|
+
/** Alt text for the image */
|
|
94
|
+
alt?: string;
|
|
95
|
+
/** Array of hotspot definitions (required unless `scenes` is provided) */
|
|
96
|
+
hotspots?: HotspotItem[];
|
|
97
|
+
/** Popover trigger mode (default: 'hover') */
|
|
98
|
+
trigger?: TriggerMode;
|
|
99
|
+
/** Enable zoom & pan (default: false) */
|
|
100
|
+
zoom?: boolean;
|
|
101
|
+
/** Maximum zoom level (default: 4) */
|
|
102
|
+
zoomMax?: number;
|
|
103
|
+
/** Minimum zoom level (default: 1) */
|
|
104
|
+
zoomMin?: number;
|
|
105
|
+
/** Theme — applies a preset of CSS variable values (default: 'light') */
|
|
106
|
+
theme?: Theme;
|
|
107
|
+
/** Invert marker colors so they blend with the theme instead of contrasting (default: false) */
|
|
108
|
+
invertMarkerTheme?: boolean;
|
|
109
|
+
/** Custom popover render function */
|
|
110
|
+
renderPopover?: (hotspot: HotspotItem) => string | HTMLElement;
|
|
111
|
+
/** Called when a hotspot is activated (popover opens) */
|
|
112
|
+
onOpen?: (hotspot: HotspotItem) => void;
|
|
113
|
+
/** Called when a hotspot is deactivated (popover closes) */
|
|
114
|
+
onClose?: (hotspot: HotspotItem) => void;
|
|
115
|
+
/** Called on zoom level change */
|
|
116
|
+
onZoom?: (level: number) => void;
|
|
117
|
+
/** Called when a hotspot marker is clicked */
|
|
118
|
+
onClick?: (event: MouseEvent | KeyboardEvent, hotspot: HotspotItem) => void;
|
|
119
|
+
/** Enable/disable marker pulse animation (default: true) */
|
|
120
|
+
pulse?: boolean;
|
|
121
|
+
/** Show zoom controls UI (default: true when zoom is enabled) */
|
|
122
|
+
zoomControls?: boolean;
|
|
123
|
+
/** Show scroll-to-zoom hint when user scrolls without modifier key (default: true when zoom is enabled) */
|
|
124
|
+
scrollHint?: boolean;
|
|
125
|
+
/** Popover placement preference (default: 'top') */
|
|
126
|
+
placement?: Placement;
|
|
127
|
+
/** Enable lazy loading of the image (default: true) */
|
|
128
|
+
lazyLoad?: boolean;
|
|
129
|
+
/** Optional Cloudimage integration for responsive image loading */
|
|
130
|
+
cloudimage?: CloudimageConfig;
|
|
131
|
+
/** Array of scenes for multi-image navigation (v1.3) */
|
|
132
|
+
scenes?: Scene[];
|
|
133
|
+
/** Initial scene ID to display (defaults to first scene) */
|
|
134
|
+
initialScene?: string;
|
|
135
|
+
/** Scene transition animation type (default: 'fade') */
|
|
136
|
+
sceneTransition?: SceneTransition;
|
|
137
|
+
/** Fixed aspect ratio for the scene container (e.g. '16/9'). Prevents layout jumps between scenes with different image dimensions. Images use object-fit: contain. */
|
|
138
|
+
sceneAspectRatio?: string;
|
|
139
|
+
/** Called when the active scene changes */
|
|
140
|
+
onSceneChange?: (sceneId: string, scene: Scene) => void;
|
|
141
|
+
/** Show fullscreen toggle button (default: true) */
|
|
142
|
+
fullscreenButton?: boolean;
|
|
143
|
+
/** Position of zoom controls (default: 'bottom-right') */
|
|
144
|
+
zoomControlsPosition?: ZoomControlsPosition;
|
|
145
|
+
/** Called when fullscreen state changes */
|
|
146
|
+
onFullscreenChange?: (isFullscreen: boolean) => void;
|
|
147
|
+
}
|
|
148
|
+
/** Instance methods returned by CIHotspot */
|
|
149
|
+
export interface CIHotspotInstance {
|
|
150
|
+
/** Get references to internal DOM elements */
|
|
151
|
+
getElements(): {
|
|
152
|
+
container: HTMLElement;
|
|
153
|
+
viewport: HTMLElement;
|
|
154
|
+
image: HTMLImageElement;
|
|
155
|
+
markers: HTMLElement;
|
|
156
|
+
};
|
|
157
|
+
/** Open a specific hotspot popover by ID */
|
|
158
|
+
open(id: string): void;
|
|
159
|
+
/** Close a specific hotspot popover by ID */
|
|
160
|
+
close(id: string): void;
|
|
161
|
+
/** Close all open popovers */
|
|
162
|
+
closeAll(): void;
|
|
163
|
+
/** Set zoom level programmatically */
|
|
164
|
+
setZoom(level: number): void;
|
|
165
|
+
/** Get current zoom level */
|
|
166
|
+
getZoom(): number;
|
|
167
|
+
/** Reset zoom and pan to initial state */
|
|
168
|
+
resetZoom(): void;
|
|
169
|
+
/** Add a hotspot dynamically */
|
|
170
|
+
addHotspot(hotspot: HotspotItem): void;
|
|
171
|
+
/** Remove a hotspot by ID */
|
|
172
|
+
removeHotspot(id: string): void;
|
|
173
|
+
/** Update hotspot configuration */
|
|
174
|
+
updateHotspot(id: string, updates: Partial<HotspotItem>): void;
|
|
175
|
+
/** Destroy the instance and clean up DOM/listeners */
|
|
176
|
+
destroy(): void;
|
|
177
|
+
/** Update the entire configuration */
|
|
178
|
+
update(config: Partial<CIHotspotConfig>): void;
|
|
179
|
+
/** Navigate to a scene by ID */
|
|
180
|
+
goToScene(sceneId: string): void;
|
|
181
|
+
/** Get the current scene ID (returns undefined if not in scenes mode) */
|
|
182
|
+
getCurrentScene(): string | undefined;
|
|
183
|
+
/** Get all scene IDs (returns empty array if not in scenes mode) */
|
|
184
|
+
getScenes(): string[];
|
|
185
|
+
/** Enter browser fullscreen mode */
|
|
186
|
+
enterFullscreen(): void;
|
|
187
|
+
/** Exit browser fullscreen mode */
|
|
188
|
+
exitFullscreen(): void;
|
|
189
|
+
/** Check if currently in fullscreen mode */
|
|
190
|
+
isFullscreen(): boolean;
|
|
191
|
+
}
|
|
192
|
+
/** Internal resolved config — src and hotspots always defined after mergeConfig */
|
|
193
|
+
export type ResolvedCIHotspotConfig = CIHotspotConfig & {
|
|
194
|
+
src: string;
|
|
195
|
+
hotspots: HotspotItem[];
|
|
196
|
+
};
|
|
197
|
+
/** Hotspot with coordinates normalized to percentages */
|
|
198
|
+
export interface NormalizedHotspot extends Omit<HotspotItem, 'x' | 'y'> {
|
|
199
|
+
x: number;
|
|
200
|
+
y: number;
|
|
201
|
+
}
|
|
202
|
+
/** Bounding rectangle */
|
|
203
|
+
export interface Rect {
|
|
204
|
+
x: number;
|
|
205
|
+
y: number;
|
|
206
|
+
width: number;
|
|
207
|
+
height: number;
|
|
208
|
+
}
|
|
209
|
+
/** 2D point */
|
|
210
|
+
export interface Point {
|
|
211
|
+
x: number;
|
|
212
|
+
y: number;
|
|
213
|
+
}
|
|
214
|
+
/** Internal zoom/pan state */
|
|
215
|
+
export interface ZoomState {
|
|
216
|
+
zoom: number;
|
|
217
|
+
panX: number;
|
|
218
|
+
panY: number;
|
|
219
|
+
}
|
|
220
|
+
/** Computed popover position result */
|
|
221
|
+
export interface PositionResult {
|
|
222
|
+
x: number;
|
|
223
|
+
y: number;
|
|
224
|
+
placement: Placement;
|
|
225
|
+
arrowOffset: number;
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { HotspotItem } from '../core/types';
|
|
2
|
+
import type { EditorConfig, EditorMode, EditorSnapshot } from './types';
|
|
3
|
+
import { EventEmitter } from '../utils/events';
|
|
4
|
+
import { CIHotspot } from '../core/ci-hotspot';
|
|
5
|
+
import { EditorToolbar } from './editor-toolbar';
|
|
6
|
+
import { SelectionManager } from './selection-manager';
|
|
7
|
+
import { UndoManager } from './undo-manager';
|
|
8
|
+
export declare class CIHotspotEditor {
|
|
9
|
+
private config;
|
|
10
|
+
private rootEl;
|
|
11
|
+
private editorEl;
|
|
12
|
+
private canvasEl;
|
|
13
|
+
private sidebarEl;
|
|
14
|
+
private statusEl;
|
|
15
|
+
private viewer;
|
|
16
|
+
private hotspots;
|
|
17
|
+
private mode;
|
|
18
|
+
private nextId;
|
|
19
|
+
private toolbar;
|
|
20
|
+
private selection;
|
|
21
|
+
private propertyPanel;
|
|
22
|
+
private dragManager;
|
|
23
|
+
private undoManager;
|
|
24
|
+
readonly events: EventEmitter;
|
|
25
|
+
private cleanups;
|
|
26
|
+
private toastEl;
|
|
27
|
+
private toastTimer;
|
|
28
|
+
private destroyed;
|
|
29
|
+
constructor(element: HTMLElement | string, config: EditorConfig);
|
|
30
|
+
private injectEditorStyles;
|
|
31
|
+
private buildDOM;
|
|
32
|
+
private initModules;
|
|
33
|
+
rebuildViewer(): void;
|
|
34
|
+
addHotspot(partial?: Partial<HotspotItem>): HotspotItem | undefined;
|
|
35
|
+
removeHotspot(id: string): void;
|
|
36
|
+
updateHotspot(id: string, updates: Partial<HotspotItem>): void;
|
|
37
|
+
getHotspots(): HotspotItem[];
|
|
38
|
+
getHotspot(id: string): HotspotItem | undefined;
|
|
39
|
+
setHotspots(hotspots: HotspotItem[]): void;
|
|
40
|
+
getMode(): EditorMode;
|
|
41
|
+
setMode(mode: EditorMode): void;
|
|
42
|
+
getCanvasEl(): HTMLElement;
|
|
43
|
+
getViewer(): CIHotspot | null;
|
|
44
|
+
getSrc(): string;
|
|
45
|
+
setSrc(src: string): void;
|
|
46
|
+
getSelection(): SelectionManager;
|
|
47
|
+
getToolbar(): EditorToolbar;
|
|
48
|
+
getUndoManager(): UndoManager;
|
|
49
|
+
createSnapshot(): EditorSnapshot;
|
|
50
|
+
restoreSnapshot(snapshot: EditorSnapshot): void;
|
|
51
|
+
exportJSON(): string;
|
|
52
|
+
importJSON(json: string): void;
|
|
53
|
+
private notifyChange;
|
|
54
|
+
private updateStatus;
|
|
55
|
+
showToast(message: string, duration?: number): void;
|
|
56
|
+
destroy(): void;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=ci-hotspot-editor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci-hotspot-editor.d.ts","sourceRoot":"","sources":["../../src/editor/ci-hotspot-editor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAA0B,MAAM,eAAe,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAExE,OAAO,EAAE,YAAY,EAAe,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAI7C,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAGC;IACf,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,SAAS,CAAe;IAChC,OAAO,CAAC,QAAQ,CAAe;IAE/B,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,IAAI,CAAwB;IACpC,OAAO,CAAC,MAAM,CAAK;IAEnB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,aAAa,CAAiB;IACtC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,WAAW,CAAe;IAElC,QAAQ,CAAC,MAAM,eAAsB;IACrC,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,SAAS,CAAS;gBAEd,OAAO,EAAE,WAAW,GAAG,MAAM,EAAE,MAAM,EAAE,YAAY;IA+B/D,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,QAAQ;IAoBhB,OAAO,CAAC,WAAW;IAmFnB,aAAa,IAAI,IAAI;IA0BrB,UAAU,CAAC,OAAO,GAAE,OAAO,CAAC,WAAW,CAAM,GAAG,WAAW,GAAG,SAAS;IAuBvE,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAe/B,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI;IAc9D,WAAW,IAAI,WAAW,EAAE;IAI5B,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAK/C,WAAW,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,IAAI;IAQ1C,OAAO,IAAI,UAAU;IAIrB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IAS/B,WAAW,IAAI,WAAW;IAI1B,SAAS,IAAI,SAAS,GAAG,IAAI;IAI7B,MAAM,IAAI,MAAM;IAIhB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAMzB,YAAY,IAAI,gBAAgB;IAIhC,UAAU,IAAI,aAAa;IAI3B,cAAc,IAAI,WAAW;IAM7B,cAAc,IAAI,cAAc;IAOhC,eAAe,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IAe/C,UAAU,IAAI,MAAM;IAIpB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAwB9B,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,YAAY;IAWpB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAO,GAAG,IAAI;IAiBjD,OAAO,IAAI,IAAI;CAiBhB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CIHotspotEditor } from './ci-hotspot-editor';
|
|
2
|
+
export declare class DragManager {
|
|
3
|
+
private editor;
|
|
4
|
+
private cleanups;
|
|
5
|
+
private dragging;
|
|
6
|
+
private dragId;
|
|
7
|
+
private startX;
|
|
8
|
+
private startY;
|
|
9
|
+
private markerEl;
|
|
10
|
+
private origLeft;
|
|
11
|
+
private origTop;
|
|
12
|
+
private rafId;
|
|
13
|
+
constructor(editor: CIHotspotEditor);
|
|
14
|
+
bind(): void;
|
|
15
|
+
private unbind;
|
|
16
|
+
destroy(): void;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=drag-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drag-manager.d.ts","sourceRoot":"","sources":["../../src/editor/drag-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,qBAAa,WAAW;IAWV,OAAO,CAAC,MAAM;IAV1B,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,OAAO,CAAM;IACrB,OAAO,CAAC,KAAK,CAAuB;gBAEhB,MAAM,EAAE,eAAe;IAI3C,IAAI,IAAI,IAAI;IA8FZ,OAAO,CAAC,MAAM;IAKd,OAAO,IAAI,IAAI;CAOhB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CIHotspotEditor } from './ci-hotspot-editor';
|
|
2
|
+
export declare class EditorToolbar {
|
|
3
|
+
private parentEl;
|
|
4
|
+
private editor;
|
|
5
|
+
private toolbarEl;
|
|
6
|
+
private urlBarEl;
|
|
7
|
+
private selectBtn;
|
|
8
|
+
private addBtn;
|
|
9
|
+
private undoBtn;
|
|
10
|
+
private redoBtn;
|
|
11
|
+
private deleteBtn;
|
|
12
|
+
private exportBtn;
|
|
13
|
+
private importBtn;
|
|
14
|
+
private copyBtn;
|
|
15
|
+
constructor(parentEl: HTMLElement, editor: CIHotspotEditor);
|
|
16
|
+
private build;
|
|
17
|
+
private createBtn;
|
|
18
|
+
private createSeparator;
|
|
19
|
+
updateState(): void;
|
|
20
|
+
private showExportJSON;
|
|
21
|
+
private copyJSON;
|
|
22
|
+
private showImportModal;
|
|
23
|
+
private loadImageUrl;
|
|
24
|
+
destroy(): void;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=editor-toolbar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor-toolbar.d.ts","sourceRoot":"","sources":["../../src/editor/editor-toolbar.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAc3D,qBAAa,aAAa;IAatB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,MAAM;IAbhB,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,OAAO,CAAqB;gBAG1B,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,eAAe;IAWjC,OAAO,CAAC,KAAK;IAyDb,OAAO,CAAC,SAAS;IAajB,OAAO,CAAC,eAAe;IAIvB,WAAW,IAAI,IAAI;IAcnB,OAAO,CAAC,cAAc;YAYR,QAAQ;IAStB,OAAO,CAAC,eAAe;IAgEvB,OAAO,CAAC,YAAY;IAOpB,OAAO,IAAI,IAAI;CAIhB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const $="ci-hotspot-styles";function K(){return typeof window<"u"&&typeof document<"u"}function st(a){if(typeof a=="string"){const t=document.querySelector(a);if(!t)throw new Error(`CIHotspot: element "${a}" not found`);return t}return a}function h(a,t,e){const i=document.createElement(a);if(t&&(i.className=t),e)for(const[o,r]of Object.entries(e))i.setAttribute(o,r);return i}function v(a,...t){a.classList.add(...t)}function y(a,...t){a.classList.remove(...t)}function Q(a){if(!K()||document.getElementById($))return;const t=document.createElement("style");t.id=$,t.textContent=a,document.head.appendChild(t)}class rt{constructor(){this.listeners=new Map}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e)}off(t,e){var i;(i=this.listeners.get(t))==null||i.delete(e)}emit(t,...e){var i;(i=this.listeners.get(t))==null||i.forEach(o=>o(...e))}removeAll(){this.listeners.clear()}}function f(a,t,e,i){return a.addEventListener(t,e,i),()=>a.removeEventListener(t,e,i)}const nt={alt:"",trigger:"hover",zoom:!1,zoomMax:4,zoomMin:1,theme:"light",pulse:!0,zoomControls:!0,placement:"top",lazyLoad:!0,sceneTransition:"fade",scrollHint:!0,invertMarkerTheme:!1,fullscreenButton:!0,zoomControlsPosition:"bottom-right"},at={"data-ci-hotspot-src":{key:"src",type:"string"},"data-ci-hotspot-alt":{key:"alt",type:"string"},"data-ci-hotspot-items":{key:"hotspots",type:"json"},"data-ci-hotspot-trigger":{key:"trigger",type:"string"},"data-ci-hotspot-zoom":{key:"zoom",type:"boolean"},"data-ci-hotspot-zoom-max":{key:"zoomMax",type:"number"},"data-ci-hotspot-zoom-min":{key:"zoomMin",type:"number"},"data-ci-hotspot-theme":{key:"theme",type:"string"},"data-ci-hotspot-pulse":{key:"pulse",type:"boolean"},"data-ci-hotspot-placement":{key:"placement",type:"string"},"data-ci-hotspot-lazy-load":{key:"lazyLoad",type:"boolean"},"data-ci-hotspot-zoom-controls":{key:"zoomControls",type:"boolean"},"data-ci-hotspot-scroll-hint":{key:"scrollHint",type:"boolean"},"data-ci-hotspot-ci-token":{key:"token",type:"string",nested:"cloudimage"},"data-ci-hotspot-ci-api-version":{key:"apiVersion",type:"string",nested:"cloudimage"},"data-ci-hotspot-ci-domain":{key:"domain",type:"string",nested:"cloudimage"},"data-ci-hotspot-ci-limit-factor":{key:"limitFactor",type:"number",nested:"cloudimage"},"data-ci-hotspot-ci-params":{key:"params",type:"string",nested:"cloudimage"},"data-ci-hotspot-scenes":{key:"scenes",type:"json"},"data-ci-hotspot-initial-scene":{key:"initialScene",type:"string"},"data-ci-hotspot-scene-transition":{key:"sceneTransition",type:"string"},"data-ci-hotspot-scene-aspect-ratio":{key:"sceneAspectRatio",type:"string"},"data-ci-hotspot-invert-marker-theme":{key:"invertMarkerTheme",type:"boolean"},"data-ci-hotspot-fullscreen-button":{key:"fullscreenButton",type:"boolean"},"data-ci-hotspot-zoom-controls-position":{key:"zoomControlsPosition",type:"string"}};function ct(a){const t={},e={};for(const[i,o]of Object.entries(at)){const r=a.getAttribute(i);if(r===null)continue;const s=lt(r,o.type);o.nested==="cloudimage"?e[o.key]=s:t[o.key]=s}return Object.keys(e).length>0&&(t.cloudimage=e),t}function lt(a,t){switch(t){case"boolean":return a==="true";case"number":{const e=parseFloat(a);if(isNaN(e)){console.warn(`CIHotspot: invalid number value "${a}"`);return}return e}case"json":try{return JSON.parse(a)}catch{console.warn(`CIHotspot: failed to parse JSON value "${a}"`);return}default:return a}}function X(a){return{...nt,...a,src:a.src||"",hotspots:a.hotspots||[]}}function j(a){if(a.scenes&&a.scenes.length>0){const t=new Set;for(const e of a.scenes){if(!e.id)throw new Error('CIHotspot: each scene must have an "id"');if(t.has(e.id))throw new Error(`CIHotspot: duplicate scene ID "${e.id}"`);if(t.add(e.id),!e.src)throw new Error(`CIHotspot: scene "${e.id}" must have a "src"`)}for(const e of a.scenes)for(const i of e.hotspots||[])if(i.navigateTo&&!t.has(i.navigateTo))throw new Error(`CIHotspot: hotspot "${i.id}" navigateTo "${i.navigateTo}" is not a valid scene ID`);if(a.initialScene&&!t.has(a.initialScene))throw new Error(`CIHotspot: initialScene "${a.initialScene}" not found in scenes`)}else if(!a.src)throw new Error('CIHotspot: "src" is required')}function Z(a){if(typeof a=="string"){const t=a.trim();return t.endsWith("%")?{value:parseFloat(t),isPercent:!0}:{value:parseFloat(t),isPercent:!1}}return{value:a,isPercent:!1}}function V(a,t,e,i){const o=Z(a),r=Z(t);return{x:o.isPercent?o.value:o.value/e*100,y:r.isPercent?r.value:r.value/i*100}}function dt(a,t){const e=h("button","ci-hotspot-marker",{"aria-label":a.label,"aria-expanded":"false","data-hotspot-id":a.id,tabindex:"0"});if(e.style.left=`${a.x}%`,e.style.top=`${a.y}%`,a.className){const i=a.className.trim().split(/\s+/).filter(Boolean);i.length&&v(e,...i)}return a.hidden&&v(e,"ci-hotspot-marker--hidden"),t&&v(e,"ci-hotspot-marker--pulse"),a.icon&&ut(e,a.icon),e}function ht(a){if(typeof DOMParser>"u")return"";const e=new DOMParser().parseFromString(a,"image/svg+xml").documentElement;return e.querySelector("parsererror")?"":(tt(e),new XMLSerializer().serializeToString(e))}const pt=new Set(["script","foreignobject","iframe","object","embed","animate","animatetransform","animatemotion","set","style","a","use","image","feimage"]);function tt(a){for(const t of Array.from(a.attributes)){const e=t.name.toLowerCase();(e.startsWith("on")||e==="style"||(e==="href"||e==="xlink:href")&&/^\s*javascript\s*:/i.test(t.value))&&a.removeAttribute(t.name)}for(const t of Array.from(a.children)){if(pt.has(t.tagName.toLowerCase())){t.remove();continue}tt(t)}}function ut(a,t){const e=t.trim();if(/^<svg[\s>]/i.test(e)||/^<\?xml/i.test(e))a.innerHTML=ht(t);else if(t.match(/\.(png|jpg|jpeg|gif|svg|webp)$/i)||t.startsWith("http")||t.startsWith("/")){const i=h("img",void 0,{src:t,alt:"","aria-hidden":"true"});i.style.width="100%",i.style.height="100%",i.style.objectFit="contain",a.appendChild(i)}else{const i=h("span",t,{"aria-hidden":"true"});a.appendChild(i)}}function g(a,t){t?(v(a,"ci-hotspot-marker--active"),a.setAttribute("aria-expanded","true")):(y(a,"ci-hotspot-marker--active"),a.setAttribute("aria-expanded","false"))}function ft(a,t){t?v(a,"ci-hotspot-marker--hidden"):y(a,"ci-hotspot-marker--hidden")}function I(a){a.remove()}function gt(a,t,e,i){const o=a.getBoundingClientRect(),r=e.getBoundingClientRect(),s=t.offsetWidth,n=t.offsetHeight,c=o.left+o.width/2-r.left,l=o.top+o.height/2-r.top,d=o.top-r.top,u=o.bottom-r.top,p=o.left-r.left,m=o.right-r.left,b=e.offsetWidth,k=e.offsetHeight,x=8,H={top:d-x,bottom:k-u-x,left:p-x,right:b-m-x};let w=i.placement;w==="auto"&&(w=mt(H)),w=vt(w,s,n,H);let T,S,N=0;switch(w){case"top":T=c-s/2,S=d-x-n;break;case"bottom":T=c-s/2,S=u+x;break;case"left":T=p-x-s,S=l-n/2;break;case"right":T=m+x,S=l-n/2;break;default:T=c-s/2,S=d-x-n}const L=bt(T,S,s,n,b,k);return N=w==="top"||w==="bottom"?T-L.x:S-L.y,{x:L.x,y:L.y,placement:w,arrowOffset:N}}function mt(a){const t=Math.max(a.top,a.bottom,a.left,a.right);return t===a.top?"top":t===a.bottom?"bottom":t===a.right?"right":"left"}function vt(a,t,e,i){const o=a;switch(o){case"top":if(i.top<e&&i.bottom>i.top)return"bottom";break;case"bottom":if(i.bottom<e&&i.top>i.bottom)return"top";break;case"left":if(i.left<t&&i.right>i.left)return"right";break;case"right":if(i.right<t&&i.left>i.right)return"left";break}return o}function bt(a,t,e,i,o,r){let n=a,c=t;return e>o-2*4?n=(o-e)/2:(n<4&&(n=4),n+e>o-4&&(n=o-4-e)),i>r-2*4?c=(r-i)/2:(c<4&&(c=4),c+i>r-4&&(c=r-4-i)),{x:n,y:c}}const yt=new Set(["a","b","br","div","em","h1","h2","h3","h4","h5","h6","i","img","li","ol","p","span","strong","ul"]),xt=new Set(["class","href","src","alt","title","target","rel"]),kt=/^(?:https?:|mailto:)/i,wt=/^(?:https?:|data:image\/(?!svg[+%]))/i,Et=new Set(["noopener","noreferrer","nofollow","external","author","help","license","next","prev","search","tag","bookmark"]);function Ct(a){const i=new DOMParser().parseFromString(`<body>${a}</body>`,"text/html").body;return et(i),i.innerHTML}function et(a){const t=Array.from(a.childNodes);for(const e of t)if(e.nodeType!==Node.TEXT_NODE)if(e.nodeType===Node.ELEMENT_NODE){const i=e,o=i.tagName.toLowerCase();if(!yt.has(o)){i.remove();continue}const r=Array.from(i.attributes);for(const s of r){const n=s.name.toLowerCase();if(n.startsWith("on")){i.removeAttribute(s.name);continue}if(!xt.has(n)){i.removeAttribute(s.name);continue}if(n==="href"&&!kt.test(s.value.trim()))i.removeAttribute(s.name);else if(n==="src"&&!wt.test(s.value.trim()))i.removeAttribute(s.name);else if(n==="rel"){const c=s.value.trim().toLowerCase().split(/\s+/).filter(l=>Et.has(l));c.length===0?i.removeAttribute(s.name):i.setAttribute(s.name,c.join(" "))}}et(i)}else e.remove()}function Tt(a){const t=[];a.image&&t.push(`<img class="ci-hotspot-popover-image" src="${F(a.image)}" alt="${F(a.title||"")}">`);const e=[];if(a.title&&e.push(`<h3 class="ci-hotspot-popover-title">${P(a.title)}</h3>`),a.price&&e.push(`<span class="ci-hotspot-popover-price">${P(a.price)}</span>`),a.description&&e.push(`<p class="ci-hotspot-popover-description">${P(a.description)}</p>`),a.url&&zt(a.url)){const i=a.ctaText||"View details";e.push(`<a class="ci-hotspot-popover-cta" href="${F(a.url)}">${P(String(i))}</a>`)}return e.length>0&&t.push(`<div class="ci-hotspot-popover-body">${e.join("")}</div>`),t.join("")}function St(a,t){return t?t(a):a.content?Ct(a.content):a.data?Tt(a.data):""}function P(a){return a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function zt(a){const t=a.replace(/[\s\x00-\x1f]/g,"");return/^https?:\/\//i.test(t)||/^\/(?!\/)/.test(t)||/^#/.test(t)}function F(a){return a.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">")}class W{constructor(t,e){this.visible=!1,this.markerEl=null,this.containerEl=null,this.hoverCleanups=[],this.hotspot=t,this.options=e;const i=e.triggerMode==="click"||e.triggerMode==="load";this.element=h("div","ci-hotspot-popover",{role:i?"dialog":"tooltip",id:`ci-hotspot-popover-${t.id}`,"aria-hidden":"true","data-placement":e.placement==="auto"?"top":e.placement,...i&&t.label?{"aria-label":t.label}:{}}),this.arrowEl=h("div","ci-hotspot-popover-arrow"),this.contentEl=h("div","ci-hotspot-popover-content"),this.element.appendChild(this.arrowEl),this.element.appendChild(this.contentEl);const o=St(t,e.renderFn);if(typeof o=="string"?this.contentEl.innerHTML=o:o instanceof HTMLElement&&this.contentEl.appendChild(o),e.triggerMode==="hover"){const r=()=>this.clearHideTimer(),s=()=>this.scheduleHide();this.element.addEventListener("mouseenter",r),this.element.addEventListener("mouseleave",s),this.hoverCleanups.push(()=>this.element.removeEventListener("mouseenter",r),()=>this.element.removeEventListener("mouseleave",s))}}mount(t,e){this.containerEl=t,this.markerEl=e,t.appendChild(this.element),this.options.triggerMode==="click"||this.options.triggerMode==="load"?(e.setAttribute("aria-haspopup","dialog"),e.setAttribute("aria-controls",this.element.id)):e.setAttribute("aria-describedby",this.element.id)}show(){var t,e;this.clearHideTimer(),!this.visible&&(this.visible=!0,v(this.element,"ci-hotspot-popover--visible"),this.element.setAttribute("aria-hidden","false"),this.updatePosition(),(e=(t=this.options).onOpen)==null||e.call(t,this.hotspot))}scheduleHide(t=200){this.clearHideTimer(),this.hideTimer=setTimeout(()=>{this.hide()},t)}hide(){var t,e;this.clearHideTimer(),this.visible&&(this.visible=!1,y(this.element,"ci-hotspot-popover--visible"),this.element.setAttribute("aria-hidden","true"),(e=(t=this.options).onClose)==null||e.call(t,this.hotspot))}clearHideTimer(){this.hideTimer!==void 0&&(clearTimeout(this.hideTimer),this.hideTimer=void 0)}updatePosition(){if(!this.markerEl||!this.containerEl||!this.visible)return;const t=gt(this.markerEl,this.element,this.containerEl,{placement:this.options.placement});this.element.style.left=`${t.x}px`,this.element.style.top=`${t.y}px`,this.element.setAttribute("data-placement",t.placement),this.positionArrow(t.placement,t.arrowOffset)}positionArrow(t,e){const i=this.arrowEl;i.style.left="",i.style.top="",t==="top"||t==="bottom"?i.style.left=`calc(50% - var(--ci-hotspot-arrow-size) + ${e}px)`:i.style.top=`calc(50% - var(--ci-hotspot-arrow-size) + ${e}px)`}isVisible(){return this.visible}getHotspot(){return this.hotspot}destroy(){var t,e,i;this.clearHideTimer(),this.hoverCleanups.forEach(o=>o()),this.hoverCleanups=[],(t=this.markerEl)==null||t.removeAttribute("aria-describedby"),(e=this.markerEl)==null||e.removeAttribute("aria-controls"),(i=this.markerEl)==null||i.removeAttribute("aria-haspopup"),this.element.remove(),this.markerEl=null,this.containerEl=null}}class Mt{constructor(t,e,i){this.lastTouchEnd=0,this.initialPinchDistance=0,this.initialPinchScale=1,this.panStartX=0,this.panStartY=0,this.isPinching=!1,this.isPanning=!1,this.wasPinching=!1,this.cleanups=[],this.el=t,this.callbacks=e,this.initialPinchScale=i();const o=n=>this.handleTouchStart(n,i),r=n=>this.handleTouchMove(n),s=n=>this.handleTouchEnd(n);t.addEventListener("touchstart",o,{passive:!1}),t.addEventListener("touchmove",r,{passive:!1}),t.addEventListener("touchend",s,{passive:!0}),this.cleanups.push(()=>t.removeEventListener("touchstart",o),()=>t.removeEventListener("touchmove",r),()=>t.removeEventListener("touchend",s))}handleTouchStart(t,e){t.touches.length===2?(t.preventDefault(),this.isPinching=!0,this.wasPinching=!1,this.initialPinchDistance=this.getTouchDistance(t.touches),this.initialPinchScale=e()):t.touches.length===1&&(this.panStartX=t.touches[0].clientX,this.panStartY=t.touches[0].clientY,this.wasPinching=!1)}handleTouchMove(t){var e,i,o,r,s,n;if(t.touches.length===2&&this.isPinching){t.preventDefault();const c=this.getTouchDistance(t.touches),l=this.initialPinchScale*(c/this.initialPinchDistance),d=(t.touches[0].clientX+t.touches[1].clientX)/2,u=(t.touches[0].clientY+t.touches[1].clientY)/2;(i=(e=this.callbacks).onPinch)==null||i.call(e,l,d,u)}else if(t.touches.length===1&&!this.isPinching&&!this.wasPinching){this.isPanning||(this.isPanning=!0,(r=(o=this.callbacks).onPanStart)==null||r.call(o));const c=t.touches[0].clientX-this.panStartX,l=t.touches[0].clientY-this.panStartY;(n=(s=this.callbacks).onPan)==null||n.call(s,c,l)}}handleTouchEnd(t){var e,i,o,r;if(this.isPinching&&t.touches.length<2&&(this.isPinching=!1,this.wasPinching=!0,t.touches.length===1&&(this.panStartX=t.touches[0].clientX,this.panStartY=t.touches[0].clientY)),this.isPanning&&(this.isPanning=!1,(i=(e=this.callbacks).onPanEnd)==null||i.call(e)),t.changedTouches.length===1&&t.touches.length===0){if(this.wasPinching){this.wasPinching=!1,this.lastTouchEnd=0;return}const s=Date.now();if(s-this.lastTouchEnd<300){const n=t.changedTouches[0];(r=(o=this.callbacks).onDoubleTap)==null||r.call(o,n.clientX,n.clientY)}this.lastTouchEnd=s}}getTouchDistance(t){const e=t[0].clientX-t[1].clientX,i=t[0].clientY-t[1].clientY;return Math.sqrt(e*e+i*i)}destroy(){this.cleanups.forEach(t=>t()),this.cleanups=[]}}class Ht{constructor(t,e,i){this.zoom=1,this.panX=0,this.panY=0,this.enabled=!0,this.isDragging=!1,this.dragStartX=0,this.dragStartY=0,this.lastPanX=0,this.lastPanY=0,this.gestures=null,this.isGesturing=!1,this.gestureStartZoom=1,this.touchStartPanX=0,this.touchStartPanY=0,this.cleanups=[],this.viewport=t,this.container=e,this.options=i,this.bindEvents()}bindEvents(){const t=s=>{var p,m;if(!this.enabled)return;if(this.isGesturing){s.preventDefault();return}if(!s.ctrlKey){(m=(p=this.options).onScrollWithoutZoom)==null||m.call(p);return}s.preventDefault();const n=this.container.getBoundingClientRect(),c=s.clientX-n.left,l=s.clientY-n.top;let d=s.deltaY;s.deltaMode===1&&(d*=20);const u=-d*.01;this.setZoom(this.zoom+u,c,l)};this.container.addEventListener("wheel",t,{passive:!1}),this.cleanups.push(()=>this.container.removeEventListener("wheel",t)),this.bindSafariGestures();const e=s=>{if(!this.enabled)return;const n=this.container.getBoundingClientRect(),c=s.clientX-n.left,l=s.clientY-n.top;this.zoom>1?this.resetZoom():this.setZoom(2,c,l)};this.container.addEventListener("dblclick",e),this.cleanups.push(()=>this.container.removeEventListener("dblclick",e));const i=s=>{!this.enabled||this.zoom<=1||s.button===0&&(this.isDragging=!0,this.dragStartX=s.clientX,this.dragStartY=s.clientY,this.lastPanX=this.panX,this.lastPanY=this.panY,v(this.viewport,"ci-hotspot-viewport--dragging"),this.container.style.cursor="grabbing",s.preventDefault())},o=s=>{if(!this.isDragging)return;const n=(s.clientX-this.dragStartX)/this.zoom,c=(s.clientY-this.dragStartY)/this.zoom;this.panX=this.lastPanX+n,this.panY=this.lastPanY+c,this.clampPan(),this.applyTransform()},r=()=>{this.isDragging&&(this.isDragging=!1,y(this.viewport,"ci-hotspot-viewport--dragging"),this.container.style.cursor=this.zoom>1?"grab":"")};this.container.addEventListener("mousedown",i),document.addEventListener("mousemove",o),document.addEventListener("mouseup",r),this.cleanups.push(()=>this.container.removeEventListener("mousedown",i),()=>document.removeEventListener("mousemove",o),()=>document.removeEventListener("mouseup",r)),this.gestures=new Mt(this.container,{onPinch:(s,n,c)=>{const l=this.container.getBoundingClientRect();this.setZoom(s,n-l.left,c-l.top)},onPanStart:()=>{this.touchStartPanX=this.panX,this.touchStartPanY=this.panY},onPan:(s,n)=>{this.zoom<=1||(this.panX=this.touchStartPanX+s/this.zoom,this.panY=this.touchStartPanY+n/this.zoom,this.clampPan(),this.applyTransform())},onDoubleTap:(s,n)=>{const c=this.container.getBoundingClientRect();this.zoom>1?this.resetZoom():this.setZoom(2,s-c.left,n-c.top)}},()=>this.zoom)}bindSafariGestures(){if(typeof window>"u"||!("GestureEvent"in window))return;const t=o=>{o.preventDefault(),this.isGesturing=!0,this.gestureStartZoom=this.zoom},e=o=>{if(o.preventDefault(),!this.enabled)return;const r=o,s=this.container.getBoundingClientRect(),n=o,c=n.clientX!=null?n.clientX-s.left:s.width/2,l=n.clientY!=null?n.clientY-s.top:s.height/2;this.setZoom(this.gestureStartZoom*r.scale,c,l)},i=o=>{o.preventDefault(),this.isGesturing=!1};this.container.addEventListener("gesturestart",t),this.container.addEventListener("gesturechange",e),this.container.addEventListener("gestureend",i),this.cleanups.push(()=>this.container.removeEventListener("gesturestart",t),()=>this.container.removeEventListener("gesturechange",e),()=>this.container.removeEventListener("gestureend",i))}setZoom(t,e,i){var r,s;const o=this.zoom;if(this.zoom=Math.max(this.options.zoomMin,Math.min(this.options.zoomMax,t)),e!==void 0&&i!==void 0&&o!==this.zoom){const n=this.container.offsetWidth,c=this.container.offsetHeight,l=this.zoom/o,d=e/n,u=i/c;this.panX=this.panX-n*d*(l-1)/this.zoom,this.panY=this.panY-c*u*(l-1)/this.zoom}this.clampPan(),this.applyTransform(),this.updateCursor(),(s=(r=this.options).onZoom)==null||s.call(r,this.zoom)}getZoom(){return this.zoom}resetZoom(){var t,e;this.zoom=1,this.panX=0,this.panY=0,this.applyTransform(),this.updateCursor(),(e=(t=this.options).onZoom)==null||e.call(t,1)}pan(t,e){this.zoom<=1||(this.panX+=t/this.zoom,this.panY+=e/this.zoom,this.clampPan(),this.applyTransform())}enable(){this.enabled=!0}disable(){this.enabled=!1}clampPan(){const t=this.container.offsetWidth,e=this.container.offsetHeight,i=t*(this.zoom-1)/this.zoom,o=e*(this.zoom-1)/this.zoom;this.panX=Math.max(-i,Math.min(0,this.panX)),this.panY=Math.max(-o,Math.min(0,this.panY)),this.zoom<=1&&(this.panX=0,this.panY=0)}applyTransform(){this.viewport.style.transform=`scale(${this.zoom}) translate(${this.panX}px, ${this.panY}px)`,this.viewport.style.setProperty("--zoom",String(this.zoom))}updateCursor(){this.isDragging||(this.container.style.cursor=this.zoom>1?"grab":"")}destroy(){var t;this.cleanups.forEach(e=>e()),this.cleanups=[],(t=this.gestures)==null||t.destroy(),this.gestures=null,this.viewport.style.transform="",this.viewport.style.removeProperty("--zoom"),this.container.style.cursor=""}}function Lt(a,t,e){const i=e.zoomStep||.5,o=h("div","ci-hotspot-zoom-controls");o.dataset.position=e.position||"bottom-right";const r=h("button","ci-hotspot-zoom-in",{"aria-label":"Zoom in",type:"button"});r.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" x2="16.65" y1="21" y2="16.65"/><line x1="11" x2="11" y1="8" y2="14"/><line x1="8" x2="14" y1="11" y2="11"/></svg>';const s=h("button","ci-hotspot-zoom-out",{"aria-label":"Zoom out",type:"button"});s.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" x2="16.65" y1="21" y2="16.65"/><line x1="8" x2="14" y1="11" y2="11"/></svg>';const n=h("button","ci-hotspot-zoom-reset",{"aria-label":"Reset zoom",type:"button"});n.innerHTML='<svg 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>',o.appendChild(r),o.appendChild(s),o.appendChild(n),r.addEventListener("click",l=>{l.stopPropagation(),t.setZoom(t.getZoom()+i),c()}),s.addEventListener("click",l=>{l.stopPropagation(),t.setZoom(t.getZoom()-i),c()}),n.addEventListener("click",l=>{l.stopPropagation(),t.resetZoom(),c()});function c(){const l=t.getZoom();r.disabled=l>=e.zoomMax,s.disabled=l<=e.zoomMin,n.disabled=Math.abs(l-1)<.001}return a.appendChild(o),c(),{element:o,update:c,destroy:()=>o.remove()}}const It=typeof navigator<"u"&&/Mac|iPhone|iPad|iPod/i.test(navigator.userAgent),Pt=It?"⌘ Scroll or pinch to zoom":"Ctrl + scroll to zoom",At=1500;class Dt{constructor(t){this.hideTimer=null,this.el=document.createElement("div"),this.el.className="ci-hotspot-scroll-hint",this.el.textContent=Pt,this.el.setAttribute("aria-hidden","true"),t.appendChild(this.el)}show(){this.hideTimer!==null&&clearTimeout(this.hideTimer),this.el.classList.add("ci-hotspot-scroll-hint--visible"),this.hideTimer=setTimeout(()=>{this.el.classList.remove("ci-hotspot-scroll-hint--visible"),this.hideTimer=null},At)}destroy(){this.hideTimer!==null&&(clearTimeout(this.hideTimer),this.hideTimer=null),this.el.remove()}}const Bt="cloudimg.io",Ft="v7",B=100;function Rt(a,t=B){return Math.ceil(a/t)*t}function it(a,t=1,e=1,i=B){const o=a*t*e;return Rt(o,i)}function z(a,t,e,i=1,o=1){const r=t.domain||Bt,s=t.apiVersion||Ft,n=t.limitFactor||B,c=it(e,o,i,n),l=encodeURI(a);let d=`https://${t.token}.${r}/${s}/${l}?width=${c}`;return t.params&&(d+=`&${t.params}`),d}function Ot(a,t,e,i){const o=e.limitFactor||B;let r=0;const s=new ResizeObserver(n=>{for(const c of n){const l=c.contentRect.width;if(l===0)continue;const d=typeof window<"u"&&window.devicePixelRatio||1,u=it(l,d,i(),o);u!==r&&(r=u,a.src=z(t,e,l,i(),d))}});return{observer:s,destroy:()=>s.disconnect()}}const A=50,U=.5;class Yt{constructor(t){this.cleanups=[];const{container:e,getZoomPan:i,onEscape:o,onFullscreenToggle:r}=t,s=f(e,"keydown",n=>{const c=n.target;if(c.tagName==="INPUT"||c.tagName==="TEXTAREA"||c.tagName==="SELECT")return;const l=i();switch(n.key){case"Escape":o==null||o();break;case"ArrowUp":l&&l.getZoom()>1&&(n.preventDefault(),l.pan(0,A));break;case"ArrowDown":l&&l.getZoom()>1&&(n.preventDefault(),l.pan(0,-A));break;case"ArrowLeft":l&&l.getZoom()>1&&(n.preventDefault(),l.pan(A,0));break;case"ArrowRight":l&&l.getZoom()>1&&(n.preventDefault(),l.pan(-A,0));break;case"+":case"=":l&&(n.preventDefault(),l.setZoom(l.getZoom()+U));break;case"-":l&&(n.preventDefault(),l.setZoom(l.getZoom()-U));break;case"0":l&&(n.preventDefault(),l.resetZoom());break;case"f":r&&(n.preventDefault(),r());break}});this.cleanups.push(s)}destroy(){this.cleanups.forEach(t=>t()),this.cleanups=[]}}const Nt='a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function _(a){return Array.from(a.querySelectorAll(Nt))}function O(a,t){let e=!1,i=null;function o(){if(e)return;e=!0;const n=_(a);n.length!==0&&(n[0].focus(),i=f(a,"keydown",c=>{if(c.key!=="Tab")return;const l=_(a);if(l.length===0)return;const d=l[0],u=l[l.length-1];c.shiftKey&&document.activeElement===d?(c.preventDefault(),u.focus()):!c.shiftKey&&document.activeElement===u&&(c.preventDefault(),d.focus())}))}function r(){e&&(e=!1,i==null||i(),i=null,t.focus())}function s(){r()}return{activate:o,deactivate:r,destroy:s}}let E=null,D=0;function $t(a){K()&&(E||(E=h("div",void 0,{"aria-live":"polite","aria-atomic":"true",role:"status"}),E.style.cssText="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0",document.body.appendChild(E)),E.textContent="",requestAnimationFrame(()=>{E&&(E.textContent=a)}))}function q(){D++}function Xt(){D=Math.max(0,D-1),D===0&&E&&(E.remove(),E=null)}const G='<svg 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>',jt='<svg 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>';function Zt(){return!!(document.fullscreenEnabled||document.webkitFullscreenEnabled)}function Vt(){return document.fullscreenElement||document.webkitFullscreenElement||null}function J(a){return a.requestFullscreen?a.requestFullscreen():a.webkitRequestFullscreen?(a.webkitRequestFullscreen(),Promise.resolve()):Promise.reject(new Error("Fullscreen API not supported"))}function R(){return document.exitFullscreen?document.exitFullscreen():document.webkitExitFullscreen?(document.webkitExitFullscreen(),Promise.resolve()):Promise.reject(new Error("Fullscreen API not supported"))}function Wt(a,t={}){if(!Zt())return null;const e=h("button","ci-hotspot-fullscreen-btn",{"aria-label":"Enter fullscreen","aria-pressed":"false",type:"button"});e.innerHTML=G;const i=[];function o(){return Vt()===a}function r(){var m;const p=o();e.innerHTML=p?jt:G,e.setAttribute("aria-label",p?"Exit fullscreen":"Enter fullscreen"),e.setAttribute("aria-pressed",String(p)),p?v(a,"ci-hotspot-container--fullscreen"):y(a,"ci-hotspot-container--fullscreen"),(m=t.onChange)==null||m.call(t,p)}function s(){o()?R().catch(()=>{}):J(a).catch(()=>{})}function n(){o()||J(a).catch(()=>{})}function c(){o()&&R().catch(()=>{})}const l=f(document,"fullscreenchange",r);i.push(l),document.addEventListener("webkitfullscreenchange",r),i.push(()=>document.removeEventListener("webkitfullscreenchange",r));const d=f(e,"click",p=>{p.stopPropagation(),s()});i.push(d),a.appendChild(e);function u(){o()&&R().catch(()=>{}),y(a,"ci-hotspot-container--fullscreen"),i.forEach(p=>p()),i.length=0,e.remove()}return{element:e,isFullscreen:o,toggle:s,enter:n,exit:c,destroy:u}}const ot='.ci-hotspot-container{--ci-hotspot-marker-size: 24px;--ci-hotspot-marker-color: #ffffff;--ci-hotspot-marker-bg: rgba(0, 0, 0, .6);--ci-hotspot-marker-border-width: 2px;--ci-hotspot-marker-border-color: rgba(255, 255, 255, .8);--ci-hotspot-marker-border: var(--ci-hotspot-marker-border-width) solid var(--ci-hotspot-marker-border-color);--ci-hotspot-marker-border-radius: 50%;--ci-hotspot-marker-shadow: 0 2px 8px rgba(0, 0, 0, .3);--ci-hotspot-pulse-color: rgba(0, 0, 0, .2);--ci-hotspot-pulse-size: 40px;--ci-hotspot-pulse-duration: 1.8s;--ci-hotspot-popover-bg: #ffffff;--ci-hotspot-popover-color: #1a1a1a;--ci-hotspot-popover-border: 1px solid rgba(0, 0, 0, .1);--ci-hotspot-popover-border-radius: 12px;--ci-hotspot-popover-shadow: 0 8px 32px rgba(0, 0, 0, .12);--ci-hotspot-popover-padding: 16px;--ci-hotspot-popover-max-width: 320px;--ci-hotspot-popover-max-height: 400px;--ci-hotspot-popover-font-family: inherit;--ci-hotspot-popover-font-size: 14px;--ci-hotspot-popover-line-height: 1.5;--ci-hotspot-popover-z-index: 1000;--ci-hotspot-arrow-size: 8px;--ci-hotspot-arrow-color: var(--ci-hotspot-popover-bg);--ci-hotspot-title-font-size: 16px;--ci-hotspot-title-font-weight: 600;--ci-hotspot-title-color: #1a1a1a;--ci-hotspot-price-color: #2d8c3c;--ci-hotspot-price-font-size: 18px;--ci-hotspot-price-font-weight: 700;--ci-hotspot-description-color: #666666;--ci-hotspot-cta-bg: #0058a3;--ci-hotspot-cta-color: #ffffff;--ci-hotspot-cta-border-radius: 8px;--ci-hotspot-cta-padding: 8px 16px;--ci-hotspot-hover-transition: .2s ease;--ci-hotspot-popover-transition: .3s ease;--ci-hotspot-scene-transition-duration: .4s;--ci-hotspot-zoom-controls-bg: rgba(255, 255, 255, .9);--ci-hotspot-zoom-controls-color: #333333;--ci-hotspot-zoom-controls-border-radius: 8px;--ci-hotspot-zoom-controls-shadow: 0 2px 8px rgba(0, 0, 0, .15)}.ci-hotspot-container *,.ci-hotspot-container *:before,.ci-hotspot-container *:after{box-sizing:border-box}.ci-hotspot-container{position:relative;overflow:hidden;width:100%;line-height:0;user-select:none;-webkit-user-select:none}.ci-hotspot-viewport{position:relative;width:100%;transform-origin:0 0;will-change:transform;transition:transform .3s ease}.ci-hotspot-viewport--dragging{transition:none}.ci-hotspot-image{display:block;width:100%;height:auto;pointer-events:none}.ci-hotspot-markers{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}.ci-hotspot-marker{position:absolute;width:var(--ci-hotspot-marker-size);height:var(--ci-hotspot-marker-size);padding:0;border:var(--ci-hotspot-marker-border);border-radius:var(--ci-hotspot-marker-border-radius);background:var(--ci-hotspot-marker-bg);color:var(--ci-hotspot-marker-color);box-shadow:var(--ci-hotspot-marker-shadow);cursor:pointer;pointer-events:auto;transform:translate(-50%,-50%) scale(calc(1 / var(--zoom, 1)));transition:transform var(--ci-hotspot-hover-transition),box-shadow var(--ci-hotspot-hover-transition);z-index:1;display:flex;align-items:center;justify-content:center;font-size:12px;line-height:1;outline:none}.ci-hotspot-marker:hover{transform:translate(-50%,-50%) scale(calc(1.2 / var(--zoom, 1)));box-shadow:0 4px 12px #0006}.ci-hotspot-marker:focus-visible{outline:3px solid var(--ci-hotspot-focus-ring, #4A90D9);outline-offset:2px}.ci-hotspot-marker--active{transform:translate(-50%,-50%) scale(calc(1.2 / var(--zoom, 1)));z-index:2}.ci-hotspot-marker--hidden{display:none}.ci-hotspot-marker--pulse:before{content:"";position:absolute;top:50%;left:50%;width:var(--ci-hotspot-pulse-size);height:var(--ci-hotspot-pulse-size);border-radius:50%;background:var(--ci-hotspot-pulse-color);transform:translate(-50%,-50%) scale(1);animation:ci-hotspot-pulse var(--ci-hotspot-pulse-duration) ease-out infinite;pointer-events:none}@keyframes ci-hotspot-pulse{0%{transform:translate(-50%,-50%) scale(1);opacity:1}to{transform:translate(-50%,-50%) scale(1.8);opacity:0}}.ci-hotspot-marker--pulse{animation:ci-hotspot-breathe 2.4s ease-in-out infinite}.ci-hotspot-marker--pulse:hover,.ci-hotspot-marker--pulse.ci-hotspot-marker--active{animation:none}@keyframes ci-hotspot-breathe{0%,to{transform:translate(-50%,-50%) scale(calc(1 / var(--zoom, 1)))}50%{transform:translate(-50%,-50%) scale(calc(1.15 / var(--zoom, 1)))}}.ci-hotspot-popover{position:absolute;z-index:var(--ci-hotspot-popover-z-index);max-width:var(--ci-hotspot-popover-max-width);background:var(--ci-hotspot-popover-bg);color:var(--ci-hotspot-popover-color);border:var(--ci-hotspot-popover-border);border-radius:var(--ci-hotspot-popover-border-radius);box-shadow:var(--ci-hotspot-popover-shadow);font-family:var(--ci-hotspot-popover-font-family);font-size:var(--ci-hotspot-popover-font-size);line-height:var(--ci-hotspot-popover-line-height);opacity:0;pointer-events:none;transform:translateY(4px);transition:opacity var(--ci-hotspot-popover-transition),transform var(--ci-hotspot-popover-transition)}.ci-hotspot-popover--visible{opacity:1;pointer-events:auto;transform:translateY(0);animation:ci-hotspot-popover-in var(--ci-hotspot-popover-transition) forwards}@keyframes ci-hotspot-popover-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.ci-hotspot-popover-arrow{position:absolute;width:calc(var(--ci-hotspot-arrow-size) * 2);height:calc(var(--ci-hotspot-arrow-size) * 2);background:var(--ci-hotspot-arrow-color);transform:rotate(45deg);pointer-events:none}.ci-hotspot-popover[data-placement=top] .ci-hotspot-popover-arrow{bottom:calc(var(--ci-hotspot-arrow-size) * -1)}.ci-hotspot-popover[data-placement=bottom] .ci-hotspot-popover-arrow{top:calc(var(--ci-hotspot-arrow-size) * -1)}.ci-hotspot-popover[data-placement=left] .ci-hotspot-popover-arrow{right:calc(var(--ci-hotspot-arrow-size) * -1)}.ci-hotspot-popover[data-placement=right] .ci-hotspot-popover-arrow{left:calc(var(--ci-hotspot-arrow-size) * -1)}.ci-hotspot-popover-content{padding:var(--ci-hotspot-popover-padding);max-height:var(--ci-hotspot-popover-max-height);overflow-y:auto;overflow-x:hidden;border-radius:var(--ci-hotspot-popover-border-radius)}.ci-hotspot-popover-image{display:block;width:100%;height:auto;border-radius:calc(var(--ci-hotspot-popover-border-radius) - 4px) calc(var(--ci-hotspot-popover-border-radius) - 4px) 0 0;margin:calc(var(--ci-hotspot-popover-padding) * -1);margin-bottom:12px;width:calc(100% + var(--ci-hotspot-popover-padding) * 2)}.ci-hotspot-popover-body{line-height:1.5}.ci-hotspot-popover-title{margin:0 0 4px;font-size:var(--ci-hotspot-title-font-size);font-weight:var(--ci-hotspot-title-font-weight);color:var(--ci-hotspot-title-color)}.ci-hotspot-popover-price{display:inline-block;margin-bottom:8px;font-size:var(--ci-hotspot-price-font-size);font-weight:var(--ci-hotspot-price-font-weight);color:var(--ci-hotspot-price-color)}.ci-hotspot-popover-description{margin:0 0 12px;color:var(--ci-hotspot-description-color)}.ci-hotspot-popover-cta{display:inline-block;padding:var(--ci-hotspot-cta-padding);background:var(--ci-hotspot-cta-bg);color:var(--ci-hotspot-cta-color);border-radius:var(--ci-hotspot-cta-border-radius);text-decoration:none;font-weight:600;font-size:14px;transition:opacity .2s ease}.ci-hotspot-popover-cta:hover{opacity:.9}.ci-hotspot-popover-cta:focus-visible{outline:3px solid var(--ci-hotspot-focus-ring, #4A90D9);outline-offset:2px}.ci-hotspot-zoom-controls{position:absolute;display:flex;gap:2px;background:var(--ci-hotspot-zoom-controls-bg);border-radius:var(--ci-hotspot-zoom-controls-border-radius);box-shadow:var(--ci-hotspot-zoom-controls-shadow);z-index:10;overflow:hidden}.ci-hotspot-zoom-controls button{display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:none;background:transparent;color:var(--ci-hotspot-zoom-controls-color);cursor:pointer;font-size:18px;line-height:1;padding:0;transition:background .15s ease}.ci-hotspot-zoom-controls button:hover{background:#0000000d}.ci-hotspot-zoom-controls button:disabled{opacity:.3;cursor:default}.ci-hotspot-zoom-controls button:disabled:hover{background:transparent}.ci-hotspot-zoom-controls button svg{width:18px;height:18px}.ci-hotspot-zoom-controls button:focus-visible{outline:3px solid var(--ci-hotspot-focus-ring, #4A90D9);outline-offset:-3px}.ci-hotspot-zoom-controls[data-position=bottom-right]{bottom:16px;right:16px}.ci-hotspot-zoom-controls[data-position=bottom-left]{bottom:16px;left:16px}.ci-hotspot-zoom-controls[data-position=bottom-center]{bottom:16px;left:50%;transform:translate(-50%)}.ci-hotspot-zoom-controls[data-position=top-right]{top:16px;right:16px}.ci-hotspot-zoom-controls[data-position=top-left]{top:16px;left:16px}.ci-hotspot-zoom-controls[data-position=top-center]{top:16px;left:50%;transform:translate(-50%)}.ci-hotspot-cluster{position:absolute;display:flex;align-items:center;justify-content:center;min-width:32px;height:32px;padding:0 8px;border-radius:16px;border:2px solid rgba(255,255,255,.8);background:var(--ci-hotspot-marker-bg);color:var(--ci-hotspot-marker-color);font-size:13px;font-weight:700;cursor:pointer;pointer-events:auto;transform:translate(-50%,-50%) scale(calc(1 / var(--zoom, 1)));box-shadow:var(--ci-hotspot-marker-shadow)}.ci-hotspot-loading .ci-hotspot-image{opacity:0;transition:opacity .3s ease}.ci-hotspot-loading .ci-hotspot-markers{display:none}.ci-hotspot-theme-dark{--ci-hotspot-marker-bg: rgba(255, 255, 255, .8);--ci-hotspot-marker-color: #1a1a1a;--ci-hotspot-marker-border-color: rgba(255, 255, 255, .4);--ci-hotspot-pulse-color: rgba(255, 255, 255, .2);--ci-hotspot-popover-bg: #1a1a1a;--ci-hotspot-popover-color: #f0f0f0;--ci-hotspot-popover-border: 1px solid rgba(255, 255, 255, .1);--ci-hotspot-popover-shadow: 0 8px 32px rgba(0, 0, 0, .4);--ci-hotspot-title-color: #f0f0f0;--ci-hotspot-description-color: #aaaaaa;--ci-hotspot-zoom-controls-bg: rgba(30, 30, 30, .9);--ci-hotspot-zoom-controls-color: #f0f0f0}.ci-hotspot-marker-inverted{--ci-hotspot-marker-bg: rgba(255, 255, 255, .8);--ci-hotspot-marker-color: #1a1a1a;--ci-hotspot-marker-border-color: rgba(0, 0, 0, .3);--ci-hotspot-marker-shadow: 0 2px 8px rgba(0, 0, 0, .15);--ci-hotspot-pulse-color: rgba(0, 0, 0, .15)}.ci-hotspot-theme-dark.ci-hotspot-marker-inverted{--ci-hotspot-marker-bg: rgba(0, 0, 0, .6);--ci-hotspot-marker-color: #ffffff;--ci-hotspot-marker-border-color: rgba(255, 255, 255, .3);--ci-hotspot-pulse-color: rgba(255, 255, 255, .15)}.ci-hotspot-scroll-hint{position:absolute;bottom:16px;left:50%;transform:translate(-50%) translateY(4px);padding:8px 16px;border-radius:20px;background:#000000b3;color:#fff;font-size:13px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;line-height:1;white-space:nowrap;z-index:100;opacity:0;pointer-events:none;transition:opacity .3s ease,transform .3s ease}.ci-hotspot-scroll-hint--visible{opacity:1;transform:translate(-50%) translateY(0)}.ci-hotspot-container--fixed-ratio .ci-hotspot-viewport{overflow:hidden}.ci-hotspot-container--fixed-ratio .ci-hotspot-image{position:absolute;top:0;left:0;width:100%;height:100%;object-fit:contain}.ci-hotspot-container--fixed-ratio .ci-hotspot-markers{z-index:1}.ci-hotspot-scene-incoming{position:absolute;top:0;left:0;width:100%;height:100%;object-fit:contain;pointer-events:none;z-index:0}.ci-hotspot-scene-fade-in{animation:ci-hotspot-scene-fade-in var(--ci-hotspot-scene-transition-duration) ease forwards;z-index:1}.ci-hotspot-scene-fade-out{animation:ci-hotspot-scene-fade-out var(--ci-hotspot-scene-transition-duration) ease forwards}@keyframes ci-hotspot-scene-fade-in{0%{opacity:0}to{opacity:1}}@keyframes ci-hotspot-scene-fade-out{0%{opacity:1}to{opacity:0}}.ci-hotspot-scene-slide-in{animation:ci-hotspot-scene-slide-in var(--ci-hotspot-scene-transition-duration) ease forwards;z-index:1}.ci-hotspot-scene-slide-out{animation:ci-hotspot-scene-slide-out var(--ci-hotspot-scene-transition-duration) ease forwards}@keyframes ci-hotspot-scene-slide-in{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes ci-hotspot-scene-slide-out{0%{transform:translate(0)}to{transform:translate(-100%)}}.ci-hotspot-scene-slide-in-reverse{animation:ci-hotspot-scene-slide-in-reverse var(--ci-hotspot-scene-transition-duration) ease forwards;z-index:1}.ci-hotspot-scene-slide-out-reverse{animation:ci-hotspot-scene-slide-out-reverse var(--ci-hotspot-scene-transition-duration) ease forwards}@keyframes ci-hotspot-scene-slide-in-reverse{0%{transform:translate(-100%)}to{transform:translate(0)}}@keyframes ci-hotspot-scene-slide-out-reverse{0%{transform:translate(0)}to{transform:translate(100%)}}.ci-hotspot-marker--navigate{--ci-hotspot-marker-bg: rgba(0, 88, 163, .7)}.ci-hotspot-navigate-icon{width:75%;height:75%;display:block}.ci-hotspot-scene-transitioning .ci-hotspot-markers{opacity:0;pointer-events:none;transition:opacity .1s ease}.ci-hotspot-scene-loading:after{content:"";position:absolute;top:50%;left:50%;width:32px;height:32px;margin:-16px 0 0 -16px;border:3px solid rgba(0,0,0,.1);border-top-color:#00000080;border-radius:50%;animation:ci-hotspot-spin .6s linear infinite;z-index:10;pointer-events:none}.ci-hotspot-theme-dark .ci-hotspot-scene-loading:after,.ci-hotspot-scene-loading.ci-hotspot-theme-dark:after{border-color:#ffffff1a;border-top-color:#ffffff80}@keyframes ci-hotspot-spin{to{transform:rotate(360deg)}}.ci-hotspot-fullscreen-btn{position:absolute;top:16px;right:16px;display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:none;border-radius:var(--ci-hotspot-zoom-controls-border-radius);background:var(--ci-hotspot-zoom-controls-bg);color:var(--ci-hotspot-zoom-controls-color);box-shadow:var(--ci-hotspot-zoom-controls-shadow);cursor:pointer;padding:0;z-index:10;transition:background .15s ease}.ci-hotspot-fullscreen-btn:hover{background:#0000000d}.ci-hotspot-fullscreen-btn svg{width:18px;height:18px}.ci-hotspot-fullscreen-btn:focus-visible{outline:3px solid var(--ci-hotspot-focus-ring, #4A90D9);outline-offset:2px}.ci-hotspot-container--fullscreen{background:#000;width:100vw;height:100vh;display:flex;align-items:center;justify-content:center}.ci-hotspot-container--fullscreen .ci-hotspot-viewport{width:fit-content;max-width:100%;max-height:100%}.ci-hotspot-container--fullscreen .ci-hotspot-image{max-height:100vh;width:auto;max-width:100%;object-fit:contain}.ci-hotspot-container--fullscreen.ci-hotspot-container--fixed-ratio .ci-hotspot-viewport{width:100%;height:100%}.ci-hotspot-container--fullscreen.ci-hotspot-container--fixed-ratio .ci-hotspot-image{width:100%;height:100%;max-height:none}.ci-hotspot-theme-dark .ci-hotspot-fullscreen-btn,.ci-hotspot-container--fullscreen .ci-hotspot-fullscreen-btn{background:#1e1e1ee6;color:#f0f0f0}.ci-hotspot-theme-dark .ci-hotspot-fullscreen-btn:hover,.ci-hotspot-container--fullscreen .ci-hotspot-fullscreen-btn:hover{background:#ffffff1a}@media (prefers-reduced-motion: reduce){.ci-hotspot-marker,.ci-hotspot-marker:before,.ci-hotspot-popover{animation:none!important;transition-duration:.01ms!important}.ci-hotspot-viewport,.ci-hotspot-scroll-hint{transition-duration:.01ms!important}.ci-hotspot-scene-fade-in,.ci-hotspot-scene-fade-out,.ci-hotspot-scene-slide-in,.ci-hotspot-scene-slide-out,.ci-hotspot-scene-slide-in-reverse,.ci-hotspot-scene-slide-out-reverse{animation-duration:.01ms!important}.ci-hotspot-scene-transitioning .ci-hotspot-markers{transition-duration:.01ms!important}.ci-hotspot-scene-loading:after{animation-duration:.01ms!important}.ci-hotspot-fullscreen-btn{transition-duration:.01ms!important}}',M=class M{constructor(t,e){this.markers=new Map,this.popovers=new Map,this.normalizedHotspots=new Map,this.scrollHint=null,this.zoomPan=null,this.zoomControls=null,this.cloudimageHandler=null,this.resizeObserver=null,this.keyboardHandler=null,this.fullscreenControl=null,this.focusTraps=new Map,this.cleanups=[],this.hotspotCleanups=new Map,this.imageLoaded=!1,this.destroyed=!1,this.scenesMap=new Map,this.isTransitioning=!1,this.activeTimers=new Set,this.sceneHotspotOverrides=new Map,this.preloadedScenes=new Set,this.rootEl=st(t),this.config=X(e),j(this.config),this.config.scenes&&this.config.scenes.length>0&&this.initScenes(),q(),Q(ot),this.buildDOM(),this.applyTheme(),this.setupImage(),this.initHotspots(),this.config.zoom&&this.initZoom(),this.initKeyboard(),this.initFullscreen(),this.setupResponsive()}static autoInit(t){const i=(t||document).querySelectorAll("[data-ci-hotspot-src], [data-ci-hotspot-scenes]"),o=[];return i.forEach(r=>{const s=ct(r);(s.src||s.scenes)&&o.push(new M(r,s))}),o}buildDOM(){this.containerEl=h("div","ci-hotspot-container"),this.viewportEl=h("div","ci-hotspot-viewport"),this.imgEl=h("img","ci-hotspot-image",{alt:this.config.alt||"",draggable:"false"}),this.markersEl=h("div","ci-hotspot-markers"),this.viewportEl.appendChild(this.imgEl),this.viewportEl.appendChild(this.markersEl),this.containerEl.appendChild(this.viewportEl),this.containerEl.setAttribute("role","group"),this.containerEl.setAttribute("aria-label",this.config.alt||"Image with hotspots"),this.config.sceneAspectRatio&&(v(this.containerEl,"ci-hotspot-container--fixed-ratio"),this.viewportEl.style.aspectRatio=this.config.sceneAspectRatio),this.rootEl.innerHTML="",this.rootEl.appendChild(this.containerEl),this.config.lazyLoad&&v(this.containerEl,"ci-hotspot-loading")}applyTheme(){this.config.theme==="dark"&&v(this.containerEl,"ci-hotspot-theme-dark"),this.config.invertMarkerTheme&&v(this.containerEl,"ci-hotspot-marker-inverted")}setupImage(){const t=()=>{y(this.containerEl,"ci-hotspot-loading"),this.imageLoaded=!0,this.renormalizePixelCoordinates(),this.syncMarkersToImage(),this.showLoadTriggerPopovers()};if(this.imgEl.addEventListener("load",t),this.cleanups.push(()=>this.imgEl.removeEventListener("load",t)),this.config.lazyLoad&&typeof IntersectionObserver<"u"){const e=new IntersectionObserver(i=>{var o;(o=i[0])!=null&&o.isIntersecting&&(this.loadImage(),e.disconnect())},{threshold:.1});e.observe(this.containerEl),this.cleanups.push(()=>e.disconnect())}else this.loadImage()}loadImage(){var t,e;if((t=this.config.cloudimage)!=null&&t.token){const i=this.containerEl.offsetWidth||300,o=window.devicePixelRatio||1,r=((e=this.zoomPan)==null?void 0:e.getZoom())||1;this.imgEl.src=z(this.config.src,this.config.cloudimage,i,r,o),this.cloudimageHandler=Ot(this.imgEl,this.config.src,this.config.cloudimage,()=>{var s;return((s=this.zoomPan)==null?void 0:s.getZoom())||1}),this.cloudimageHandler.observer.observe(this.containerEl),this.cleanups.push(()=>{var s;return(s=this.cloudimageHandler)==null?void 0:s.destroy()})}else this.imgEl.src=this.config.src}initHotspots(){for(const t of this.config.hotspots)this.addHotspotInternal(t)}addHotspotInternal(t){var d,u;if(this.markers.has(t.id)){const p=this.markers.get(t.id);I(p),this.markers.delete(t.id),(d=this.popovers.get(t.id))==null||d.destroy(),this.popovers.delete(t.id);const m=this.hotspotCleanups.get(t.id);m&&(m.forEach(k=>k()),this.hotspotCleanups.delete(t.id));const b=this.focusTraps.get(t.id);b&&(b.destroy(),this.focusTraps.delete(t.id))}const{x:e,y:i}=V(t.x,t.y,this.imgEl.naturalWidth||1e3,this.imgEl.naturalHeight||1e3),o={...t,x:e,y:i};this.normalizedHotspots.set(t.id,o);const r=this.config.pulse!==!1,s=dt(o,r);this.markers.set(t.id,s),this.markersEl.appendChild(s);const n=t.trigger||this.config.trigger||"hover";if(t.navigateTo){const p=this.enrichNavigateHotspot(t);if(!!(p.data||p.content||this.config.renderPopover)){const b=t.placement||this.config.placement||"top",k=new W(p,{placement:b,triggerMode:"hover",renderFn:this.config.renderPopover,onOpen:this.config.onOpen,onClose:this.config.onClose});this.popovers.set(t.id,k),k.mount(this.containerEl,s),this.bindNavigateTrigger(t,s,k)}else this.bindNavigateTrigger(t,s);return}const c=t.placement||this.config.placement||"top",l=new W(t,{placement:c,triggerMode:n,renderFn:this.config.renderPopover,onOpen:this.config.onOpen,onClose:this.config.onClose});this.popovers.set(t.id,l),l.mount(this.containerEl,s),this.bindTrigger(t,s,l,n),n==="load"&&this.imageLoaded&&(this.closeAll(),l.show(),g(s,!0),this.ensureFocusTrap(t.id,l.element,s),(u=this.focusTraps.get(t.id))==null||u.activate())}enrichNavigateHotspot(t){if(t.data||t.content)return t;const e=this.scenesMap.get(t.navigateTo);return e?{...t,data:{title:t.label||e.alt||e.id}}:t}bindNavigateTrigger(t,e,i){if(v(e,"ci-hotspot-marker--navigate"),e.innerHTML=M.NAVIGATE_ARROW_SVG,t.arrowDirection!=null){const n=e.querySelector("svg");n&&(n.style.transform=`rotate(${t.arrowDirection}deg)`)}const o=t.label||t.navigateTo;if(e.setAttribute("aria-label",`Navigate to ${o}`),e.setAttribute("aria-roledescription","navigation hotspot"),i){const n=f(e,"mouseenter",()=>{this.preloadSceneImage(t.navigateTo),i.clearHideTimer(),i.show(),g(e,!0)}),c=f(e,"mouseleave",()=>{i.scheduleHide(200),this.trackedTimeout(()=>{i.isVisible()||g(e,!1)},250)}),l=f(e,"focus",()=>{this.preloadSceneImage(t.navigateTo),i.clearHideTimer(),i.show(),g(e,!0)}),d=f(e,"blur",()=>{i.scheduleHide(200),this.trackedTimeout(()=>{i.isVisible()||g(e,!1)},250)});this.addHotspotCleanups(t.id,n,c,l,d)}else{const n=f(e,"mouseenter",()=>{this.preloadSceneImage(t.navigateTo)}),c=f(e,"focus",()=>{this.preloadSceneImage(t.navigateTo)});this.addHotspotCleanups(t.id,n,c)}const r=f(e,"click",n=>{var c,l,d;n.stopPropagation(),i==null||i.hide(),g(e,!1),(l=(c=this.config).onClick)==null||l.call(c,n,t),(d=t.onClick)==null||d.call(t,n,t),this.goToScene(t.navigateTo)}),s=f(e,"keydown",n=>{var c,l,d;(n.key==="Enter"||n.key===" ")&&(n.preventDefault(),i==null||i.hide(),g(e,!1),(l=(c=this.config).onClick)==null||l.call(c,n,t),(d=t.onClick)==null||d.call(t,n,t),this.goToScene(t.navigateTo))});this.addHotspotCleanups(t.id,r,s)}bindTrigger(t,e,i,o){o==="hover"?this.bindHoverTrigger(t,e,i):(o==="click"||o==="load")&&this.bindClickTrigger(t,e,i),this.bindKeyboardTrigger(t,e,i,o)}bindHoverTrigger(t,e,i){const o=f(e,"mouseenter",()=>{i.clearHideTimer(),i.show(),g(e,!0)}),r=f(e,"mouseleave",()=>{i.scheduleHide(200),this.trackedTimeout(()=>{i.isVisible()||g(e,!1)},250)});this.addHotspotCleanups(t.id,o,r)}bindClickTrigger(t,e,i){const o=O(i.element,e);this.focusTraps.set(t.id,o);const r=f(e,"click",n=>{var c,l,d;n.stopPropagation(),(l=(c=this.config).onClick)==null||l.call(c,n,t),(d=t.onClick)==null||d.call(t,n,t),i.isVisible()?(i.hide(),g(e,!1),o.deactivate()):(this.closeAll(),i.show(),g(e,!0),o.activate())}),s=f(document,"click",n=>{i.isVisible()&&!t.keepOpen&&!i.element.contains(n.target)&&!e.contains(n.target)&&(i.hide(),g(e,!1),o.deactivate())});this.addHotspotCleanups(t.id,r,s)}bindKeyboardTrigger(t,e,i,o){const r=f(e,"focus",()=>{o==="hover"&&(i.clearHideTimer(),i.show(),g(e,!0))}),s=f(e,"blur",()=>{o==="hover"&&(i.scheduleHide(200),this.trackedTimeout(()=>{i.isVisible()||g(e,!1)},250))}),n=f(e,"keydown",c=>{var l,d,u,p,m;c.key==="Enter"||c.key===" "?(c.preventDefault(),(d=(l=this.config).onClick)==null||d.call(l,c,t),i.isVisible()?(i.hide(),g(e,!1),(u=this.focusTraps.get(t.id))==null||u.deactivate()):(this.closeAll(),i.show(),g(e,!0),this.ensureFocusTrap(t.id,i.element,e),(p=this.focusTraps.get(t.id))==null||p.activate())):c.key==="Escape"&&i.isVisible()&&(i.hide(),g(e,!1),(m=this.focusTraps.get(t.id))==null||m.deactivate(),e.focus())});this.addHotspotCleanups(t.id,r,s,n)}renormalizePixelCoordinates(){const t=this.imgEl.naturalWidth,e=this.imgEl.naturalHeight;if(!(!t||!e)){for(const i of this.config.hotspots)if(typeof i.x=="number"||typeof i.y=="number"){const{x:o,y:r}=V(i.x,i.y,t,e),s=this.markers.get(i.id);s&&(s.style.left=`${o}%`,s.style.top=`${r}%`);const n=this.normalizedHotspots.get(i.id);n&&(n.x=o,n.y=r)}}}showLoadTriggerPopovers(){var t;for(const[e,i]of this.popovers){const o=this.normalizedHotspots.get(e);if(((o==null?void 0:o.trigger)||this.config.trigger||"hover")==="load"&&!i.isVisible()){i.show();const s=this.markers.get(e);s&&(g(s,!0),this.ensureFocusTrap(e,i.element,s),(t=this.focusTraps.get(e))==null||t.activate());break}}}initZoom(){this.config.scrollHint!==!1&&(this.scrollHint=new Dt(this.containerEl)),this.zoomPan=new Ht(this.viewportEl,this.containerEl,{zoomMin:this.config.zoomMin||1,zoomMax:this.config.zoomMax||4,onZoom:t=>{var e,i,o;(i=(e=this.config).onZoom)==null||i.call(e,t),(o=this.zoomControls)==null||o.update();for(const[,r]of this.popovers)r.isVisible()&&r.updatePosition()},onScrollWithoutZoom:()=>{var t;return(t=this.scrollHint)==null?void 0:t.show()}}),this.config.zoomControls!==!1&&(this.zoomControls=Lt(this.containerEl,this.zoomPan,{zoomMin:this.config.zoomMin||1,zoomMax:this.config.zoomMax||4,position:this.config.zoomControlsPosition}))}setupResponsive(){if(typeof ResizeObserver>"u")return;let t=0;this.resizeObserver=new ResizeObserver(()=>{t||(t=requestAnimationFrame(()=>{if(t=0,this.destroyed)return;this.syncMarkersToImage();const e=this.containerEl.offsetWidth;for(const[i,o]of this.normalizedHotspots)if(o.responsive){const r=this.markers.get(i);if(!r)continue;const s=o.responsive.maxWidth&&e>o.responsive.maxWidth||o.responsive.minWidth&&e<o.responsive.minWidth;ft(r,!!s)}}))}),this.cleanups.push(()=>{t&&cancelAnimationFrame(t)}),this.resizeObserver.observe(this.containerEl),this.cleanups.push(()=>{var e;return(e=this.resizeObserver)==null?void 0:e.disconnect()})}syncMarkersToImage(){if(!this.config.sceneAspectRatio)return;const t=this.viewportEl.offsetWidth,e=this.viewportEl.offsetHeight,i=this.imgEl.naturalWidth,o=this.imgEl.naturalHeight;if(!t||!e||!i||!o)return;const r=t/e,s=i/o;let n,c,l,d;s>r?(n=t,c=t/s,l=0,d=(e-c)/2):(c=e,n=e*s,l=(t-n)/2,d=0),this.markersEl.style.left=`${l}px`,this.markersEl.style.top=`${d}px`,this.markersEl.style.width=`${n}px`,this.markersEl.style.height=`${c}px`,this.markersEl.style.right="auto",this.markersEl.style.bottom="auto"}initScenes(){for(const i of this.config.scenes)this.scenesMap.set(i.id,i);const t=this.config.initialScene||this.config.scenes[0].id,e=this.scenesMap.get(t);this.config.src=e.src,this.config.alt=e.alt||"",this.config.hotspots=[...e.hotspots],this.currentSceneId=t}initKeyboard(){this.keyboardHandler=new Yt({container:this.containerEl,getZoomPan:()=>this.zoomPan,onEscape:()=>{var t;if((t=this.fullscreenControl)!=null&&t.isFullscreen()){this.fullscreenControl.exit();return}this.closeAll()},onFullscreenToggle:()=>{var t;(t=this.fullscreenControl)==null||t.toggle()}})}initFullscreen(){this.config.fullscreenButton!==!1&&(this.fullscreenControl=Wt(this.containerEl,{onChange:t=>{var e,i;requestAnimationFrame(()=>{for(const[,o]of this.popovers)o.isVisible()&&o.updatePosition()}),(i=(e=this.config).onFullscreenChange)==null||i.call(e,t)}}))}preloadSceneImage(t){var o;if(this.preloadedScenes.has(t))return;const e=this.scenesMap.get(t);if(!e)return;this.preloadedScenes.add(t);const i=new Image;if((o=this.config.cloudimage)!=null&&o.token){const r=this.containerEl.offsetWidth||300,s=typeof window<"u"&&window.devicePixelRatio||1;i.src=z(e.src,this.config.cloudimage,r,1,s)}else i.src=e.src}ensureFocusTrap(t,e,i){this.focusTraps.has(t)||this.focusTraps.set(t,O(e,i))}trackedTimeout(t,e){const i=setTimeout(()=>{this.activeTimers.delete(i),t()},e);this.activeTimers.add(i)}syncCurrentSceneHotspots(){!this.currentSceneId||this.isTransitioning||this.sceneHotspotOverrides.set(this.currentSceneId,[...this.config.hotspots])}addHotspotCleanups(t,...e){let i=this.hotspotCleanups.get(t);i||(i=[],this.hotspotCleanups.set(t,i)),i.push(...e)}clearHotspots(){for(const t of this.hotspotCleanups.values())t.forEach(e=>e());this.hotspotCleanups.clear();for(const[,t]of this.popovers)t.destroy();this.popovers.clear();for(const[,t]of this.markers)I(t);this.markers.clear(),this.normalizedHotspots.clear();for(const[,t]of this.focusTraps)t.destroy();this.focusTraps.clear()}getSceneTransitionDuration(){if(typeof getComputedStyle>"u")return 400;const t=getComputedStyle(this.containerEl).getPropertyValue("--ci-hotspot-scene-transition-duration").trim(),e=parseFloat(t);return isNaN(e)?400:t.endsWith("s")&&!t.endsWith("ms")?e*1e3:e}performSceneTransition(t,e,i,o){var c;if(e==="none"){this.clearHotspots(),this.switchToScene(t),o();return}const r=this.getSceneTransitionDuration();v(this.containerEl,"ci-hotspot-scene-transitioning");const s=h("img","ci-hotspot-scene-incoming",{alt:t.alt||"",draggable:"false"});if((c=this.config.cloudimage)!=null&&c.token){const l=this.containerEl.offsetWidth||300,d=typeof window<"u"&&window.devicePixelRatio||1;s.src=z(t.src,this.config.cloudimage,l,1,d)}else s.src=t.src;const n=()=>{if(!this.destroyed){if(e==="fade")v(s,"ci-hotspot-scene-fade-in"),v(this.imgEl,"ci-hotspot-scene-fade-out");else if(e==="slide"){const l=i?"-reverse":"";v(s,`ci-hotspot-scene-slide-in${l}`),v(this.imgEl,`ci-hotspot-scene-slide-out${l}`)}this.viewportEl.insertBefore(s,this.markersEl),this.transitionTimer=setTimeout(()=>{if(this.transitionTimer=void 0,this.destroyed)return;this.clearHotspots(),this.switchToScene(t);const l=()=>{s.remove(),y(this.imgEl,"ci-hotspot-scene-fade-out"),y(this.imgEl,"ci-hotspot-scene-slide-out"),y(this.imgEl,"ci-hotspot-scene-slide-out-reverse"),y(this.containerEl,"ci-hotspot-scene-transitioning"),o()};this.imgEl.complete&&this.imgEl.naturalWidth>0?l():(this.imgEl.addEventListener("load",l,{once:!0}),this.imgEl.addEventListener("error",l,{once:!0}))},r)}};s.complete?n():(v(this.containerEl,"ci-hotspot-scene-loading"),s.onload=()=>{y(this.containerEl,"ci-hotspot-scene-loading"),n()},s.onerror=()=>{this.destroyed||(y(this.containerEl,"ci-hotspot-scene-loading"),s.remove(),y(this.containerEl,"ci-hotspot-scene-transitioning"),this.clearHotspots(),this.switchToScene(t),o())})}switchToScene(t){var i;this.config.src=t.src,this.config.alt=t.alt||"",this.config.hotspots=this.sceneHotspotOverrides.get(t.id)??[...t.hotspots],this.imgEl.alt=t.alt||"",this.containerEl.setAttribute("aria-label",t.alt||"Image with hotspots"),this.imageLoaded=!1;const e=()=>{this.imageLoaded=!0,this.renormalizePixelCoordinates(),this.syncMarkersToImage(),this.showLoadTriggerPopovers()};if(this.imgEl.addEventListener("load",e,{once:!0}),(i=this.config.cloudimage)!=null&&i.token){const o=this.containerEl.offsetWidth||300,r=typeof window<"u"&&window.devicePixelRatio||1;this.imgEl.src=z(t.src,this.config.cloudimage,o,1,r)}else this.imgEl.src=t.src;this.imgEl.complete&&this.imgEl.naturalWidth>0&&!this.imageLoaded&&(this.imgEl.removeEventListener("load",e),e()),this.initHotspots()}getElements(){return{container:this.containerEl,viewport:this.viewportEl,image:this.imgEl,markers:this.markersEl}}open(t){var o;if(this.destroyed)return;const e=this.popovers.get(t),i=this.markers.get(t);!e||!i||e.isVisible()||(this.closeAll(),e.show(),g(i,!0),(o=this.focusTraps.get(t))==null||o.activate())}close(t){var o;if(this.destroyed)return;const e=this.popovers.get(t),i=this.markers.get(t);e&&i&&(e.hide(),g(i,!1),(o=this.focusTraps.get(t))==null||o.deactivate())}closeAll(){var t;if(!this.destroyed){for(const[e,i]of this.popovers)if(i.isVisible()){i.hide();const o=this.markers.get(e);o&&g(o,!1),(t=this.focusTraps.get(e))==null||t.deactivate()}}}setZoom(t){var e;this.destroyed||(e=this.zoomPan)==null||e.setZoom(t)}getZoom(){var t;return((t=this.zoomPan)==null?void 0:t.getZoom())||1}resetZoom(){var t;this.destroyed||(t=this.zoomPan)==null||t.resetZoom()}goToScene(t){if(this.destroyed||this.isTransitioning||!this.scenesMap.size||t===this.currentSceneId)return;const e=this.scenesMap.get(t);if(!e)return;const i=this.config.sceneTransition||"fade";this.isTransitioning=!0,this.zoomPan&&this.zoomPan.getZoom()>1&&this.zoomPan.resetZoom();let o=!1;if(i==="slide"){for(const r of this.config.hotspots)if(r.navigateTo===t){const s=this.normalizedHotspots.get(r.id);s&&s.x<=50&&(o=!0);break}}this.syncCurrentSceneHotspots(),this.currentSceneId=t,this.performSceneTransition(e,i,o,()=>{var s,n;this.isTransitioning=!1,$t(`Navigated to ${e.alt||t}`),(n=(s=this.config).onSceneChange)==null||n.call(s,t,e);const r=e.hotspots[0];if(r){const c=this.markers.get(r.id);c&&document.activeElement&&this.containerEl.contains(document.activeElement)&&c.focus()}})}getCurrentScene(){return this.currentSceneId}getScenes(){return Array.from(this.scenesMap.keys())}enterFullscreen(){var t;this.destroyed||(t=this.fullscreenControl)==null||t.enter()}exitFullscreen(){var t;this.destroyed||(t=this.fullscreenControl)==null||t.exit()}isFullscreen(){var t;return((t=this.fullscreenControl)==null?void 0:t.isFullscreen())??!1}addHotspot(t){this.destroyed||(this.config.hotspots.push(t),this.addHotspotInternal(t),this.syncCurrentSceneHotspots())}removeHotspot(t){if(this.destroyed)return;const e=this.hotspotCleanups.get(t);e&&(e.forEach(s=>s()),this.hotspotCleanups.delete(t));const i=this.focusTraps.get(t);i&&(i.destroy(),this.focusTraps.delete(t));const o=this.markers.get(t),r=this.popovers.get(t);r&&(r.destroy(),this.popovers.delete(t)),o&&(I(o),this.markers.delete(t)),this.normalizedHotspots.delete(t),this.config.hotspots=this.config.hotspots.filter(s=>s.id!==t),this.syncCurrentSceneHotspots()}updateHotspot(t,e){if(this.destroyed)return;const i=this.config.hotspots.findIndex(l=>l.id===t);if(i===-1)return;const o=this.markers.get(t),r=(o==null?void 0:o.nextElementSibling)||null,n={...this.config.hotspots[i],...e};this.removeHotspot(t),this.config.hotspots.splice(i,0,n),this.addHotspotInternal(n);const c=this.markers.get(t);c&&r&&this.markersEl.contains(r)&&this.markersEl.insertBefore(c,r),this.syncCurrentSceneHotspots()}update(t){this.destroyed||(this.destroyInternal(),q(),this.config=X({...this.config,...t}),j(this.config),this.config.scenes&&this.config.scenes.length>0&&this.initScenes(),this.buildDOM(),this.applyTheme(),this.setupImage(),this.initHotspots(),this.config.zoom&&this.initZoom(),this.initKeyboard(),this.initFullscreen(),this.setupResponsive())}destroy(){this.destroyed||(this.destroyed=!0,this.destroyInternal(),this.rootEl.innerHTML="")}destroyInternal(){var t,e,i,o,r,s,n;this.imageLoaded=!1;for(const c of this.activeTimers)clearTimeout(c);this.activeTimers.clear();for(const c of this.hotspotCleanups.values())c.forEach(l=>l());this.hotspotCleanups.clear(),this.cleanups.forEach(c=>c()),this.cleanups=[];for(const[,c]of this.popovers)c.destroy();this.popovers.clear();for(const[,c]of this.markers)I(c);this.markers.clear(),this.normalizedHotspots.clear();for(const[,c]of this.focusTraps)c.destroy();this.focusTraps.clear(),this.scenesMap.clear(),this.preloadedScenes.clear(),this.sceneHotspotOverrides.clear(),this.currentSceneId=void 0,this.isTransitioning=!1,this.transitionTimer!==void 0&&(clearTimeout(this.transitionTimer),this.transitionTimer=void 0),(t=this.fullscreenControl)==null||t.destroy(),this.fullscreenControl=null,(e=this.keyboardHandler)==null||e.destroy(),this.keyboardHandler=null,(i=this.zoomPan)==null||i.destroy(),this.zoomPan=null,(o=this.zoomControls)==null||o.destroy(),this.zoomControls=null,(r=this.scrollHint)==null||r.destroy(),this.scrollHint=null,(s=this.cloudimageHandler)==null||s.destroy(),this.cloudimageHandler=null,(n=this.resizeObserver)==null||n.disconnect(),this.resizeObserver=null,Xt()}};M.NAVIGATE_ARROW_SVG='<svg class="ci-hotspot-navigate-icon" 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>';let Y=M;const C={cursor:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12.586 12.586 19 19"/><path d="M3.688 3.037a.497.497 0 0 0-.651.651l6.5 15.999a.501.501 0 0 0 .947-.062l1.569-6.083a2 2 0 0 1 1.448-1.479l6.124-1.579a.5.5 0 0 0 .063-.947z"/></svg>',plus:'<svg 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>',undo:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 14 4 9l5-5"/><path d="M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11"/></svg>',redo:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 14 5-5-5-5"/><path d="M20 9H9.5A5.5 5.5 0 0 0 4 14.5A5.5 5.5 0 0 0 9.5 20H13"/></svg>',trash:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 11v6"/><path d="M14 11v6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/><path d="M3 6h18"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>',download:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 15V3"/><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/></svg>',upload:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v12"/><path d="m17 8-5-5-5 5"/><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/></svg>',copy:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>',image:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></svg>'};class Ut{constructor(t,e){this.parentEl=t,this.editor=e,this.toolbarEl=h("div","ci-editor-toolbar"),this.urlBarEl=h("div","ci-editor-url-bar"),this.build();const i=this.parentEl.firstChild;this.parentEl.insertBefore(this.toolbarEl,i),this.parentEl.insertBefore(this.urlBarEl,i)}build(){const t=h("div","ci-editor-toolbar-group");this.selectBtn=this.createBtn(C.cursor,"Select",()=>this.editor.setMode("select")),this.addBtn=this.createBtn(C.plus,"Add",()=>this.editor.setMode("add")),t.appendChild(this.selectBtn),t.appendChild(this.addBtn),this.toolbarEl.appendChild(t),this.toolbarEl.appendChild(this.createSeparator());const e=h("div","ci-editor-toolbar-group");this.undoBtn=this.createBtn(C.undo,"Undo",()=>this.editor.getUndoManager().undo()),this.redoBtn=this.createBtn(C.redo,"Redo",()=>this.editor.getUndoManager().redo()),this.deleteBtn=this.createBtn(C.trash,"Delete",()=>{const n=this.editor.getSelection().getSelectedId();n&&this.editor.removeHotspot(n)}),e.appendChild(this.undoBtn),e.appendChild(this.redoBtn),e.appendChild(this.deleteBtn),this.toolbarEl.appendChild(e),this.toolbarEl.appendChild(this.createSeparator());const i=h("div","ci-editor-toolbar-group");this.exportBtn=this.createBtn(C.download,"Export",()=>this.showExportJSON()),this.importBtn=this.createBtn(C.upload,"Import",()=>this.showImportModal()),this.copyBtn=this.createBtn(C.copy,"Copy JSON",()=>this.copyJSON()),i.appendChild(this.exportBtn),i.appendChild(this.importBtn),i.appendChild(this.copyBtn),this.toolbarEl.appendChild(i);const o=h("span","ci-editor-btn-icon");o.innerHTML=C.image;const r=h("input","ci-editor-toolbar-url");r.type="url",r.placeholder="Image URL...",r.value=this.editor.getSrc();const s=this.createBtn("","Load",()=>this.loadImageUrl(r));r.addEventListener("keydown",n=>{n.key==="Enter"&&(n.preventDefault(),this.loadImageUrl(r))}),this.urlBarEl.appendChild(o),this.urlBarEl.appendChild(r),this.urlBarEl.appendChild(s),this.updateState()}createBtn(t,e,i){const o=h("button","ci-editor-btn");return o.innerHTML=t,o.appendChild(document.createTextNode(` ${e}`)),o.title=e,o.setAttribute("aria-label",e),o.addEventListener("click",r=>{r.stopPropagation(),i()}),o}createSeparator(){return h("div","ci-editor-toolbar-separator")}updateState(){const t=this.editor.getMode();this.selectBtn.classList.toggle("ci-editor-btn--active",t==="select"),this.addBtn.classList.toggle("ci-editor-btn--active",t==="add"),this.selectBtn.setAttribute("aria-pressed",String(t==="select")),this.addBtn.setAttribute("aria-pressed",String(t==="add"));const e=this.editor.getUndoManager();this.undoBtn.disabled=!e.canUndo(),this.redoBtn.disabled=!e.canRedo(),this.deleteBtn.disabled=!this.editor.getSelection().getSelectedId()}showExportJSON(){const t=this.editor.exportJSON(),e=new Blob([t],{type:"application/json"}),i=URL.createObjectURL(e),o=h("a");o.href=i,o.download="hotspots.json",o.click(),URL.revokeObjectURL(i),this.editor.showToast("Exported hotspots.json")}async copyJSON(){try{await navigator.clipboard.writeText(this.editor.exportJSON()),this.editor.showToast("Copied JSON to clipboard")}catch{this.editor.showToast("Failed to copy")}}showImportModal(){const t=h("div","ci-editor-modal-overlay"),e=h("div","ci-editor-modal");e.setAttribute("role","dialog"),e.setAttribute("aria-modal","true");const i="ci-editor-import-title";e.setAttribute("aria-labelledby",i);const o=h("h3");o.id=i,o.textContent="Import Hotspots JSON";const r=h("textarea");r.placeholder=`[
|
|
2
|
+
{ "id": "h1", "x": "50%", "y": "50%", "label": "My Hotspot" }
|
|
3
|
+
]`;const s=h("div","ci-editor-modal-error");s.style.display="none";const n=h("div","ci-editor-modal-actions"),c=h("button","ci-editor-btn");c.textContent="Cancel";const l=h("button","ci-editor-btn ci-editor-btn--primary");l.textContent="Import",n.appendChild(c),n.appendChild(l),e.appendChild(o),e.appendChild(r),e.appendChild(s),e.appendChild(n),t.appendChild(e),document.body.appendChild(t);const d=O(e,this.importBtn),u=()=>{d.destroy(),t.remove()};c.addEventListener("click",u),t.addEventListener("click",p=>{p.target===t&&u()}),t.addEventListener("keydown",p=>{p.key==="Escape"&&u()}),l.addEventListener("click",()=>{try{this.editor.importJSON(r.value),u(),this.editor.showToast("Imported hotspots")}catch(p){s.style.display="block",s.textContent=p instanceof Error?p.message:"Invalid JSON"}}),r.focus(),d.activate()}loadImageUrl(t){const e=t.value.trim();e&&(this.editor.setSrc(e),this.editor.showToast("Image updated"))}destroy(){this.toolbarEl.remove(),this.urlBarEl.remove()}}class _t{constructor(t){this.editor=t,this.selectedId=null,this.cleanups=[],this.bindCanvasClicks()}bindCanvasClicks(){const t=f(this.editor.getCanvasEl(),"click",e=>{if(this.editor.getMode()!=="select")return;const i=e.target,o=i.closest("[data-hotspot-id]");if(o){e.stopPropagation();const r=o.getAttribute("data-hotspot-id");r&&this.select(r)}else{const r=i.closest(".ci-editor-toolbar"),s=i.closest(".ci-editor-sidebar");!r&&!s&&this.deselect()}});this.cleanups.push(t)}select(t){this.selectedId!==t&&(this.deselect(),this.selectedId=t,this.applySelectedClass(t,!0),this.editor.events.emit("hotspot:select",t),this.editor.getToolbar().updateState())}deselect(){if(!this.selectedId)return;const t=this.selectedId;this.applySelectedClass(t,!1),this.selectedId=null,this.editor.events.emit("hotspot:deselect",t),this.editor.getToolbar().updateState()}getSelectedId(){return this.selectedId}refreshMarkerVisuals(){this.selectedId&&this.applySelectedClass(this.selectedId,!0)}applySelectedClass(t,e){const o=this.editor.getCanvasEl().querySelector(`[data-hotspot-id="${t}"]`);o&&o.classList.toggle("ci-hotspot-marker--editor-selected",e)}destroy(){this.cleanups.forEach(t=>t()),this.cleanups=[]}}class qt{constructor(t,e){this.parentEl=t,this.editor=e,this.fieldCounter=0,this.panelEl=h("div","ci-editor-panel"),this.parentEl.appendChild(this.panelEl),this.editor.events.on("hotspot:select",()=>this.refresh()),this.editor.events.on("hotspot:deselect",()=>this.refresh()),this.refresh()}refresh(){const t=this.editor.getSelection().getSelectedId();if(!t){this.renderHotspotList();return}const e=this.editor.getHotspot(t);if(!e){this.renderHotspotList();return}this.renderForm(e)}renderHotspotList(){this.panelEl.innerHTML="";const t=h("div","ci-editor-panel-title");t.textContent="Hotspots",this.panelEl.appendChild(t);const e=this.editor.getHotspots();if(e.length===0){const o=h("div","ci-editor-panel-empty");o.textContent="No hotspots yet. Use the Add tool to place hotspots on the image.",this.panelEl.appendChild(o);return}const i=h("ul","ci-editor-hotspot-list");i.setAttribute("role","listbox"),i.setAttribute("aria-label","Hotspot list");for(const o of e){const r=h("li","ci-editor-hotspot-item");r.setAttribute("data-list-id",o.id),r.setAttribute("role","option"),r.setAttribute("tabindex","0");const s=h("span","ci-editor-hotspot-item-label");s.textContent=o.label||o.id;const n=h("span","ci-editor-hotspot-item-coords");n.textContent=`${this.fmtCoord(o.x)}, ${this.fmtCoord(o.y)}`,r.appendChild(s),r.appendChild(n);const c=()=>this.editor.getSelection().select(o.id);r.addEventListener("click",c),r.addEventListener("keydown",l=>{(l.key==="Enter"||l.key===" ")&&(l.preventDefault(),c())}),i.appendChild(r)}this.panelEl.appendChild(i)}renderForm(t){this.panelEl.innerHTML="",this.fieldCounter=0;const e=h("div","ci-editor-panel-title");e.textContent=`Edit: ${t.label||t.id}`,this.panelEl.appendChild(e),this.panelEl.appendChild(this.createTextField("Label",t.label||"",c=>{this.editor.updateHotspot(t.id,{label:c})}));const i=h("div","ci-editor-field-row");i.appendChild(this.createTextField("X",String(t.x),c=>{this.editor.updateHotspot(t.id,{x:c})})),i.appendChild(this.createTextField("Y",String(t.y),c=>{this.editor.updateHotspot(t.id,{y:c})})),this.panelEl.appendChild(i),this.panelEl.appendChild(this.createSelect("Trigger",t.trigger||"click",["hover","click","load"],c=>{this.editor.updateHotspot(t.id,{trigger:c})})),this.panelEl.appendChild(this.createSelect("Placement",t.placement||"top",["top","bottom","left","right","auto"],c=>{this.editor.updateHotspot(t.id,{placement:c})}));const o=t.data||{};this.panelEl.appendChild(this.createTextField("Title",o.title||"",c=>{this.editor.updateHotspot(t.id,{data:{...t.data,title:c}})})),this.panelEl.appendChild(this.createTextField("Price",o.price||"",c=>{this.editor.updateHotspot(t.id,{data:{...t.data,price:c}})})),this.panelEl.appendChild(this.createTextArea("Description",o.description||"",c=>{this.editor.updateHotspot(t.id,{data:{...t.data,description:c}})})),this.panelEl.appendChild(this.createTextField("Image URL",o.image||"",c=>{this.editor.updateHotspot(t.id,{data:{...t.data,image:c}})})),this.panelEl.appendChild(this.createTextField("Link URL",o.url||"",c=>{this.editor.updateHotspot(t.id,{data:{...t.data,url:c}})})),this.panelEl.appendChild(this.createTextField("CTA Text",o.ctaText||"",c=>{this.editor.updateHotspot(t.id,{data:{...t.data,ctaText:c}})}));const r=h("div","ci-editor-panel-actions"),s=h("button","ci-editor-btn ci-editor-btn--danger");s.textContent="Delete Hotspot",s.addEventListener("click",()=>this.editor.removeHotspot(t.id));const n=h("button","ci-editor-btn");n.textContent="Back to List",n.addEventListener("click",()=>this.editor.getSelection().deselect()),r.appendChild(n),r.appendChild(s),this.panelEl.appendChild(r)}nextFieldId(t){return`ci-editor-field-${t.toLowerCase().replace(/\s+/g,"-")}-${++this.fieldCounter}`}createTextField(t,e,i){const o=this.nextFieldId(t),r=h("div","ci-editor-field"),s=h("label","",{for:o});s.textContent=t;const n=h("input","",{id:o});return n.type="text",n.value=e,n.addEventListener("change",()=>i(n.value)),r.appendChild(s),r.appendChild(n),r}createTextArea(t,e,i){const o=this.nextFieldId(t),r=h("div","ci-editor-field"),s=h("label","",{for:o});s.textContent=t;const n=h("textarea","",{id:o});return n.value=e,n.addEventListener("change",()=>i(n.value)),r.appendChild(s),r.appendChild(n),r}createSelect(t,e,i,o){const r=this.nextFieldId(t),s=h("div","ci-editor-field"),n=h("label","",{for:r});n.textContent=t;const c=h("select","",{id:r});for(const l of i){const d=h("option");d.value=l,d.textContent=l,l===e&&(d.selected=!0),c.appendChild(d)}return c.addEventListener("change",()=>o(c.value)),s.appendChild(n),s.appendChild(c),s}fmtCoord(t){return typeof t=="string"?t:`${Math.round(t*100)/100}%`}}class Gt{constructor(t){this.editor=t,this.cleanups=[],this.dragging=!1,this.dragId=null,this.startX=0,this.startY=0,this.markerEl=null,this.origLeft="",this.origTop="",this.rafId=null,this.bind()}bind(){this.unbind();const t=this.editor.getCanvasEl(),e=c=>{if(this.editor.getMode()!=="select")return;const d=c.target.closest("[data-hotspot-id]");if(!d)return;const u=d.getAttribute("data-hotspot-id");u&&(c.preventDefault(),this.dragging=!1,this.dragId=u,this.startX=c.clientX,this.startY=c.clientY,this.markerEl=d,this.origLeft=d.style.left,this.origTop=d.style.top,d.setPointerCapture(c.pointerId))},i=c=>{if(!this.dragId||!this.markerEl)return;const l=c.clientX-this.startX,d=c.clientY-this.startY;if(!this.dragging&&Math.abs(l)+Math.abs(d)<3||(this.dragging=!0,this.rafId!==null))return;const u=c.clientX,p=c.clientY;this.rafId=requestAnimationFrame(()=>{if(this.rafId=null,!this.markerEl)return;const m=t.querySelector(".ci-hotspot-image");if(!m)return;const b=m.getBoundingClientRect(),k=(u-b.left)/b.width*100,x=(p-b.top)/b.height*100,H=Math.max(0,Math.min(100,k)),w=Math.max(0,Math.min(100,x));this.markerEl.style.left=`${H}%`,this.markerEl.style.top=`${w}%`})},o=c=>{if(this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null),!!this.dragId){if(this.dragging&&this.markerEl){const l=t.querySelector(".ci-hotspot-image");if(l){const d=l.getBoundingClientRect(),u=(c.clientX-d.left)/d.width*100,p=(c.clientY-d.top)/d.height*100,m=Math.max(0,Math.min(100,Math.round(u*100)/100)),b=Math.max(0,Math.min(100,Math.round(p*100)/100));this.editor.updateHotspot(this.dragId,{x:`${m}%`,y:`${b}%`})}}this.dragId=null,this.dragging=!1,this.markerEl=null}},r=f(t,"pointerdown",e),s=f(t,"pointermove",i),n=f(t,"pointerup",o);this.cleanups.push(r,s,n)}unbind(){this.cleanups.forEach(t=>t()),this.cleanups=[]}destroy(){this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null),this.unbind()}}class Jt{constructor(t,e){this.editor=t,this.undoStack=[],this.redoStack=[],this.maxHistory=e}saveInitial(){this.undoStack=[this.editor.createSnapshot()],this.redoStack=[],this.notifyChange()}save(){this.undoStack.push(this.editor.createSnapshot()),this.undoStack.length>this.maxHistory&&this.undoStack.shift(),this.redoStack=[],this.notifyChange()}undo(){if(this.undoStack.length<=1)return;const t=this.undoStack.pop();this.redoStack.push(t);const e=this.undoStack[this.undoStack.length-1];this.editor.restoreSnapshot(e),this.notifyChange()}redo(){if(this.redoStack.length===0)return;const t=this.redoStack.pop();this.undoStack.push(t),this.editor.restoreSnapshot(t),this.notifyChange()}canUndo(){return this.undoStack.length>1}canRedo(){return this.redoStack.length>0}notifyChange(){this.editor.events.emit("history:change"),this.editor.getToolbar().updateState()}}const Kt='.ci-editor{--ci-editor-panel-bg: #ffffff;--ci-editor-panel-color: #1a1a1a;--ci-editor-panel-border: 1px solid #e0e0e0;--ci-editor-panel-shadow: 0 2px 8px rgba(0, 0, 0, .1);--ci-editor-accent: #0058a3;--ci-editor-accent-hover: #004a8c;--ci-editor-danger: #d32f2f;--ci-editor-danger-hover: #b71c1c;--ci-editor-radius: 8px;--ci-editor-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--ci-editor-selected-ring: 0 0 0 3px rgba(0, 88, 163, .5);--ci-editor-toolbar-bg: #f5f5f5;display:flex;flex-direction:column;font-family:var(--ci-editor-font);color:var(--ci-editor-panel-color);line-height:1.5}.ci-editor *,.ci-editor *:before,.ci-editor *:after{box-sizing:border-box}.ci-editor-body{display:flex;gap:0;min-height:400px}.ci-editor-canvas{flex:1;position:relative;overflow:hidden;background:#f0f0f0;border:var(--ci-editor-panel-border);border-radius:var(--ci-editor-radius);cursor:default}.ci-editor-canvas--add-mode{cursor:crosshair}.ci-editor-sidebar{width:280px;flex-shrink:0;border-left:var(--ci-editor-panel-border);background:var(--ci-editor-panel-bg);overflow-y:auto}.ci-editor-toolbar{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--ci-editor-toolbar-bg);border:var(--ci-editor-panel-border);border-radius:var(--ci-editor-radius) var(--ci-editor-radius) 0 0}.ci-editor-toolbar-group{display:flex;align-items:center;gap:4px}.ci-editor-toolbar-separator{width:1px;height:24px;background:#d0d0d0;margin:0 4px}.ci-editor-url-bar{display:flex;align-items:center;gap:8px;padding:6px 12px;background:var(--ci-editor-toolbar-bg);border:var(--ci-editor-panel-border);border-top:none}.ci-editor-toolbar-url{flex:1;min-width:200px;padding:6px 10px;border:1px solid #d0d0d0;border-radius:6px;font-family:var(--ci-editor-font);font-size:13px;color:var(--ci-editor-panel-color);background:#fff;transition:border-color .15s}.ci-editor-toolbar-url:focus{outline:none;border-color:var(--ci-editor-accent);box-shadow:0 0 0 2px #0058a326}.ci-editor-btn-icon{display:inline-flex;align-items:center;color:#666}.ci-editor-btn-icon svg{width:16px;height:16px}.ci-editor-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border:1px solid #d0d0d0;border-radius:6px;background:#fff;color:var(--ci-editor-panel-color);font-family:var(--ci-editor-font);font-size:13px;font-weight:500;cursor:pointer;transition:background .15s,border-color .15s,box-shadow .15s;white-space:nowrap;line-height:1}.ci-editor-btn:hover{background:#f5f5f5;border-color:#bbb}.ci-editor-btn:active{background:#ebebeb}.ci-editor-btn--active{background:var(--ci-editor-accent);color:#fff;border-color:var(--ci-editor-accent)}.ci-editor-btn--active:hover{background:var(--ci-editor-accent-hover);border-color:var(--ci-editor-accent-hover)}.ci-editor-btn--primary{background:var(--ci-editor-accent);color:#fff;border-color:var(--ci-editor-accent)}.ci-editor-btn--primary:hover{background:var(--ci-editor-accent-hover)}.ci-editor-btn--danger{color:var(--ci-editor-danger);border-color:var(--ci-editor-danger)}.ci-editor-btn--danger:hover{background:var(--ci-editor-danger);color:#fff}.ci-editor-btn:focus-visible{outline:3px solid var(--ci-editor-focus-ring, #4A90D9);outline-offset:2px}.ci-editor-btn:disabled{opacity:.4;cursor:default;pointer-events:none}.ci-editor-btn svg{width:14px;height:14px;flex-shrink:0}.ci-editor-badge{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 6px;border-radius:10px;background:var(--ci-editor-accent);color:#fff;font-size:11px;font-weight:600;line-height:1}.ci-editor-panel{padding:16px}.ci-editor-panel-title{margin:0 0 12px;font-size:14px;font-weight:600}.ci-editor-panel-empty{padding:32px 16px;text-align:center;color:#888;font-size:13px}.ci-editor-field{margin-bottom:12px}.ci-editor-field label{display:block;margin-bottom:4px;font-size:12px;font-weight:500;color:#666}.ci-editor-field input[type=text],.ci-editor-field input[type=number],.ci-editor-field input[type=url],.ci-editor-field textarea,.ci-editor-field select{width:100%;padding:6px 10px;border:1px solid #d0d0d0;border-radius:6px;font-family:var(--ci-editor-font);font-size:13px;color:var(--ci-editor-panel-color);background:#fff;transition:border-color .15s}.ci-editor-field input:focus,.ci-editor-field textarea:focus,.ci-editor-field select:focus{outline:none;border-color:var(--ci-editor-accent);box-shadow:0 0 0 2px #0058a326}.ci-editor-field textarea{resize:vertical;min-height:60px}.ci-editor-field-row{display:flex;gap:8px}.ci-editor-field-row .ci-editor-field{flex:1}.ci-editor-panel-actions{display:flex;gap:8px;margin-top:16px;padding-top:12px;border-top:1px solid #e0e0e0}.ci-editor-hotspot-list{list-style:none;margin:0;padding:0}.ci-editor-hotspot-item{display:flex;align-items:center;gap:8px;padding:8px 16px;cursor:pointer;border-bottom:1px solid #f0f0f0;font-size:13px;transition:background .1s}.ci-editor-hotspot-item:hover{background:#f5f5f5}.ci-editor-hotspot-item--selected{background:#0058a314;border-left:3px solid var(--ci-editor-accent);padding-left:13px}.ci-editor-hotspot-item-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ci-editor-hotspot-item-coords{font-size:11px;color:#999;flex-shrink:0}.ci-hotspot-marker--editor-selected{box-shadow:var(--ci-editor-selected-ring)!important;z-index:3!important}.ci-editor-json{position:relative}.ci-editor-json pre{margin:0;padding:12px;background:#1e1e1e;color:#d4d4d4;border-radius:var(--ci-editor-radius);font-family:SF Mono,Consolas,Liberation Mono,Menlo,monospace;font-size:12px;line-height:1.5;overflow-x:auto;max-height:300px;overflow-y:auto;white-space:pre-wrap;word-break:break-all}.ci-editor-json-actions{display:flex;gap:8px;margin-top:8px}.ci-editor-status{display:flex;align-items:center;justify-content:space-between;padding:4px 12px;background:var(--ci-editor-toolbar-bg);border:var(--ci-editor-panel-border);border-top:none;border-radius:0 0 var(--ci-editor-radius) var(--ci-editor-radius);font-size:12px;color:#666}.ci-editor-toast{position:fixed;bottom:20px;left:50%;transform:translate(-50%) translateY(8px);padding:8px 20px;background:#333;color:#fff;border-radius:20px;font-size:13px;font-family:var(--ci-editor-font);z-index:10001;opacity:0;pointer-events:none;transition:opacity .2s,transform .2s}.ci-editor-toast--visible{opacity:1;transform:translate(-50%) translateY(0);pointer-events:auto}.ci-editor-modal-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#0006;display:flex;align-items:center;justify-content:center;z-index:10000}.ci-editor-modal{background:var(--ci-editor-panel-bg);border-radius:12px;box-shadow:0 16px 48px #0003;padding:24px;width:480px;max-width:90vw;max-height:80vh;overflow-y:auto}.ci-editor-modal h3{margin:0 0 16px;font-size:16px;font-weight:600}.ci-editor-modal textarea{width:100%;min-height:200px;padding:12px;border:1px solid #d0d0d0;border-radius:8px;font-family:SF Mono,Consolas,monospace;font-size:12px;resize:vertical}.ci-editor-modal textarea:focus{outline:none;border-color:var(--ci-editor-accent);box-shadow:0 0 0 2px #0058a326}.ci-editor-modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}.ci-editor-modal-error{color:var(--ci-editor-danger);font-size:12px;margin-top:8px}.ci-editor--dark{--ci-editor-panel-bg: #1e1e1e;--ci-editor-panel-color: #e0e0e0;--ci-editor-panel-border: 1px solid #3a3a3a;--ci-editor-panel-shadow: 0 2px 8px rgba(0, 0, 0, .3);--ci-editor-accent: #4a9eff;--ci-editor-accent-hover: #3a8eef;--ci-editor-danger: #ef5350;--ci-editor-danger-hover: #e53935;--ci-editor-selected-ring: 0 0 0 3px rgba(74, 158, 255, .5);--ci-editor-toolbar-bg: #252525}.ci-editor--dark .ci-editor-canvas{background:#2a2a2a}.ci-editor--dark .ci-editor-toolbar-separator{background:#444}.ci-editor--dark .ci-editor-btn{background:#2a2a2a;color:#e0e0e0;border-color:#444}.ci-editor--dark .ci-editor-btn:hover{background:#333;border-color:#555}.ci-editor--dark .ci-editor-btn:active{background:#3a3a3a}.ci-editor--dark .ci-editor-btn--active{background:var(--ci-editor-accent);color:#fff;border-color:var(--ci-editor-accent)}.ci-editor--dark .ci-editor-btn--active:hover{background:var(--ci-editor-accent-hover);border-color:var(--ci-editor-accent-hover)}.ci-editor--dark .ci-editor-btn--primary{background:var(--ci-editor-accent);color:#fff;border-color:var(--ci-editor-accent)}.ci-editor--dark .ci-editor-btn:disabled{opacity:.3}.ci-editor--dark .ci-editor-toolbar-url{background:#2a2a2a;color:#e0e0e0;border-color:#444}.ci-editor--dark .ci-editor-btn-icon,.ci-editor--dark .ci-editor-field label{color:#999}.ci-editor--dark .ci-editor-field input[type=text],.ci-editor--dark .ci-editor-field input[type=number],.ci-editor--dark .ci-editor-field input[type=url],.ci-editor--dark .ci-editor-field textarea,.ci-editor--dark .ci-editor-field select{background:#2a2a2a;color:#e0e0e0;border-color:#444}.ci-editor--dark .ci-editor-panel-empty{color:#777}.ci-editor--dark .ci-editor-hotspot-item{border-bottom-color:#333}.ci-editor--dark .ci-editor-hotspot-item:hover{background:#2a2a2a}.ci-editor--dark .ci-editor-hotspot-item--selected{background:#4a9eff1a}.ci-editor--dark .ci-editor-hotspot-item-coords{color:#777}.ci-editor--dark .ci-editor-status{color:#888}.ci-editor--dark .ci-editor-panel-actions{border-top-color:#3a3a3a}.ci-editor--dark .ci-editor-toast{background:#e0e0e0;color:#1e1e1e}.ci-editor--dark .ci-editor-modal{background:#1e1e1e}.ci-editor--dark .ci-editor-modal textarea{background:#2a2a2a;color:#e0e0e0;border-color:#444}@media (max-width: 768px){.ci-editor-body{flex-direction:column}.ci-editor-sidebar{width:100%;border-left:none;border-top:var(--ci-editor-panel-border);max-height:300px}.ci-editor-toolbar{flex-wrap:wrap}}';class Qt{constructor(t,e){if(this.viewer=null,this.hotspots=[],this.mode="select",this.nextId=1,this.events=new rt,this.cleanups=[],this.toastEl=null,this.toastTimer=null,this.destroyed=!1,this.rootEl=typeof t=="string"?document.querySelector(t):t,!this.rootEl)throw new Error("CIHotspotEditor: element not found");this.config={defaultTrigger:"click",defaultPlacement:"top",maxHistory:50,...e},this.hotspots=e.hotspots?structuredClone(e.hotspots):[];for(const i of this.hotspots){const o=parseInt(i.id.replace(/\D/g,""),10);!isNaN(o)&&o>=this.nextId&&(this.nextId=o+1)}Q(ot),this.injectEditorStyles(),this.buildDOM(),this.initModules(),this.rebuildViewer(),this.updateStatus()}injectEditorStyles(){const t="ci-editor-styles";if(document.getElementById(t))return;const e=document.createElement("style");e.id=t,e.textContent=Kt,document.head.appendChild(e)}buildDOM(){this.editorEl=h("div","ci-editor"),this.config.theme==="dark"&&this.editorEl.classList.add("ci-editor--dark"),this.canvasEl=h("div","ci-editor-canvas"),this.sidebarEl=h("div","ci-editor-sidebar"),this.statusEl=h("div","ci-editor-status");const t=h("div","ci-editor-body");t.appendChild(this.canvasEl),t.appendChild(this.sidebarEl),this.editorEl.appendChild(t),this.editorEl.appendChild(this.statusEl),this.rootEl.innerHTML="",this.rootEl.appendChild(this.editorEl)}initModules(){this.undoManager=new Jt(this,this.config.maxHistory),this.selection=new _t(this),this.toolbar=new Ut(this.editorEl,this),this.propertyPanel=new qt(this.sidebarEl,this),this.dragManager=new Gt(this);const t=f(this.canvasEl,"click",i=>{var c;if(this.mode!=="add"||i.target.closest(".ci-hotspot-marker"))return;const r=(c=this.canvasEl.querySelector(".ci-hotspot-image"))==null?void 0:c.getBoundingClientRect();if(!r)return;const s=(i.clientX-r.left)/r.width*100,n=(i.clientY-r.top)/r.height*100;s<0||s>100||n<0||n>100||this.addHotspot({x:`${Math.round(s*100)/100}%`,y:`${Math.round(n*100)/100}%`})});this.cleanups.push(t);const e=f(document,"keydown",i=>{const o=i.target.tagName;if(o==="INPUT"||o==="TEXTAREA"||o==="SELECT")return;const r=i.metaKey||i.ctrlKey,s=this.editorEl.contains(document.activeElement)||this.editorEl.contains(i.target);if(r&&i.key==="z"&&!i.shiftKey&&s)i.preventDefault(),this.undoManager.undo();else if(r&&i.key==="z"&&i.shiftKey&&s)i.preventDefault(),this.undoManager.redo();else if(r&&i.key==="y"&&s)i.preventDefault(),this.undoManager.redo();else if((i.key==="Delete"||i.key==="Backspace")&&s){const n=this.selection.getSelectedId();n&&(i.preventDefault(),this.removeHotspot(n))}else i.key==="Escape"&&s?this.mode==="add"?this.setMode("select"):this.selection.deselect():i.key==="a"&&!r&&s?this.setMode(this.mode==="add"?"select":"add"):i.key==="v"&&!r&&s&&this.setMode("select")});this.cleanups.push(e),this.undoManager.saveInitial()}rebuildViewer(){var t,e;this.destroyed||(this.viewer&&(this.viewer.destroy(),this.viewer=null),this.viewer=new Y(this.canvasEl,{src:this.config.src,alt:this.config.alt||"Editor image",hotspots:this.hotspots,trigger:"click",pulse:!1,lazyLoad:!1,...this.config.cloudimage?{cloudimage:this.config.cloudimage}:{}}),(t=this.selection)==null||t.refreshMarkerVisuals(),(e=this.dragManager)==null||e.bind())}addHotspot(t={}){if(this.destroyed)return;const e=`hotspot-${this.nextId++}`,i={...t,id:e,x:t.x??"50%",y:t.y??"50%",label:t.label||`Hotspot ${this.hotspots.length+1}`,trigger:t.trigger||this.config.defaultTrigger,placement:t.placement||this.config.defaultPlacement,data:t.data||{}};return this.hotspots.push(i),this.rebuildViewer(),this.selection.select(e),this.undoManager.save(),this.notifyChange("hotspot:add"),this.updateStatus(),i}removeHotspot(t){if(this.destroyed)return;const e=this.hotspots.findIndex(i=>i.id===t);e!==-1&&(this.hotspots.splice(e,1),this.selection.getSelectedId()===t&&this.selection.deselect(),this.rebuildViewer(),this.undoManager.save(),this.notifyChange("hotspot:remove"),this.updateStatus())}updateHotspot(t,e){if(this.destroyed)return;const i=this.hotspots.findIndex(o=>o.id===t);i!==-1&&(this.hotspots[i]={...this.hotspots[i],...e},this.rebuildViewer(),this.undoManager.save(),this.notifyChange("hotspot:update"),this.updateStatus())}getHotspots(){return structuredClone(this.hotspots)}getHotspot(t){const e=this.hotspots.find(i=>i.id===t);return e?structuredClone(e):void 0}setHotspots(t){this.destroyed||(this.hotspots=structuredClone(t),this.selection.deselect(),this.rebuildViewer(),this.updateStatus())}getMode(){return this.mode}setMode(t){this.destroyed||(this.mode=t,this.canvasEl.classList.toggle("ci-editor-canvas--add-mode",t==="add"),this.events.emit("mode:change",t),this.toolbar.updateState(),this.updateStatus())}getCanvasEl(){return this.canvasEl}getViewer(){return this.viewer}getSrc(){return this.config.src}setSrc(t){this.destroyed||(this.config.src=t,this.rebuildViewer())}getSelection(){return this.selection}getToolbar(){return this.toolbar}getUndoManager(){return this.undoManager}createSnapshot(){return{hotspots:structuredClone(this.hotspots),selectedId:this.selection.getSelectedId()}}restoreSnapshot(t){this.destroyed||(this.hotspots=structuredClone(t.hotspots),this.rebuildViewer(),t.selectedId&&this.hotspots.find(e=>e.id===t.selectedId)?this.selection.select(t.selectedId):this.selection.deselect(),this.notifyChange("change"),this.updateStatus())}exportJSON(){return JSON.stringify(this.hotspots,null,2)}importJSON(t){if(this.destroyed)return;const e=JSON.parse(t);if(!Array.isArray(e))throw new Error("Expected an array of hotspots");for(const i of e)if(!i.id||i.x==null||i.y==null)throw new Error("Each hotspot must have id, x, and y");this.hotspots=e;for(const i of this.hotspots){const o=parseInt(i.id.replace(/\D/g,""),10);!isNaN(o)&&o>=this.nextId&&(this.nextId=o+1)}this.selection.deselect(),this.rebuildViewer(),this.undoManager.save(),this.notifyChange("change"),this.updateStatus()}notifyChange(t){var e,i,o;this.events.emit(t),this.events.emit("change"),(i=(e=this.config).onChange)==null||i.call(e,this.getHotspots()),(o=this.propertyPanel)==null||o.refresh()}updateStatus(){var r;const t=this.hotspots.length,e=(r=this.selection)==null?void 0:r.getSelectedId(),i=this.mode==="add"?"Add mode":"Select mode",o=[`${t} hotspot${t!==1?"s":""}`,i];e&&o.push(`Selected: ${e}`),this.statusEl.textContent=o.join(" | ")}showToast(t,e=2e3){this.destroyed||(this.toastEl||(this.toastEl=h("div","ci-editor-toast"),this.editorEl.appendChild(this.toastEl)),this.toastEl.textContent=t,this.toastEl.classList.add("ci-editor-toast--visible"),this.toastTimer&&clearTimeout(this.toastTimer),this.toastTimer=setTimeout(()=>{var i;(i=this.toastEl)==null||i.classList.remove("ci-editor-toast--visible"),this.toastTimer=null},e))}destroy(){var t;this.destroyed||(this.destroyed=!0,this.cleanups.forEach(e=>e()),this.cleanups=[],this.dragManager.destroy(),this.selection.destroy(),this.toolbar.destroy(),(t=this.viewer)==null||t.destroy(),this.events.removeAll(),this.toastTimer&&(clearTimeout(this.toastTimer),this.toastTimer=null),this.toastEl=null,this.rootEl.innerHTML="")}}exports.CIHotspotEditor=Qt;
|
|
4
|
+
//# sourceMappingURL=js-cloudimage-hotspot-editor.cjs.js.map
|