js-cloudimage-before-after 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +305 -0
- package/dist/a11y/aria.d.ts +4 -0
- package/dist/a11y/keyboard.d.ts +22 -0
- package/dist/animation/entrance.d.ts +18 -0
- package/dist/core/ci-before-after.d.ts +64 -0
- package/dist/core/config.d.ts +3 -0
- package/dist/core/types.d.ts +127 -0
- package/dist/fullscreen/fullscreen.d.ts +16 -0
- package/dist/index.d.ts +10 -0
- package/dist/js-cloudimage-before-after.cjs.js +2 -0
- package/dist/js-cloudimage-before-after.cjs.js.map +1 -0
- package/dist/js-cloudimage-before-after.esm.js +1210 -0
- package/dist/js-cloudimage-before-after.esm.js.map +1 -0
- package/dist/js-cloudimage-before-after.min.js +2 -0
- package/dist/js-cloudimage-before-after.min.js.map +1 -0
- package/dist/labels/labels.d.ts +6 -0
- package/dist/react/ci-before-after-viewer.d.ts +3 -0
- package/dist/react/index.cjs +2 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.js +179 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/types.d.ts +11 -0
- package/dist/react/use-ci-before-after.d.ts +5 -0
- package/dist/slider/gestures.d.ts +31 -0
- package/dist/slider/handle.d.ts +2 -0
- package/dist/slider/slider.d.ts +11 -0
- package/dist/utils/cloudimage.d.ts +2 -0
- package/dist/utils/dom.d.ts +8 -0
- package/dist/utils/events.d.ts +12 -0
- package/dist/zoom/controls.d.ts +12 -0
- package/dist/zoom/gestures.d.ts +21 -0
- package/dist/zoom/scroll-hint.d.ts +7 -0
- package/dist/zoom/zoom-pan.d.ts +40 -0
- package/package.json +69 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"js-cloudimage-before-after.min.js","sources":["../src/core/config.ts","../src/utils/dom.ts","../src/utils/events.ts","../src/utils/cloudimage.ts","../src/slider/slider.ts","../src/slider/handle.ts","../src/slider/gestures.ts","../src/zoom/zoom-pan.ts","../src/zoom/gestures.ts","../src/zoom/controls.ts","../src/zoom/scroll-hint.ts","../src/labels/labels.ts","../src/fullscreen/fullscreen.ts","../src/animation/entrance.ts","../src/a11y/keyboard.ts","../src/a11y/aria.ts","../src/core/ci-before-after.ts","../src/index.ts"],"sourcesContent":["import type {\n CIBeforeAfterConfig,\n ResolvedConfig,\n InteractionMode,\n Orientation,\n HandleStyle,\n Theme,\n LabelPosition,\n ZoomControlsPosition,\n} from './types';\n\nconst VALID_MODES: InteractionMode[] = ['drag', 'hover', 'click'];\nconst VALID_ORIENTATIONS: Orientation[] = ['horizontal', 'vertical'];\nconst VALID_THEMES: Theme[] = ['light', 'dark'];\nconst VALID_HANDLE_STYLES: HandleStyle[] = ['arrows', 'circle', 'line'];\nconst VALID_LABEL_POSITIONS: LabelPosition[] = ['top', 'bottom'];\nconst VALID_ZOOM_POSITIONS: ZoomControlsPosition[] = [\n 'top-left', 'top-center', 'top-right',\n 'bottom-left', 'bottom-center', 'bottom-right',\n];\n\nconst DEFAULTS: Omit<ResolvedConfig, 'beforeSrc' | 'afterSrc'> = {\n beforeAlt: 'Before',\n afterAlt: 'After',\n mode: 'drag',\n orientation: 'horizontal',\n initialPosition: 50,\n zoom: false,\n zoomMax: 4,\n zoomMin: 1,\n theme: 'light',\n handleStyle: 'arrows',\n labelsEnabled: true,\n labelBefore: 'Before',\n labelAfter: 'After',\n labelPosition: 'top',\n animateEnabled: false,\n animateDuration: 800,\n animateDelay: 0,\n animateEasing: 'ease-out',\n animateOnce: true,\n fullscreenButton: true,\n lazyLoad: true,\n zoomControls: true,\n zoomControlsPosition: 'bottom-right',\n scrollHint: true,\n keyboardStep: 1,\n keyboardLargeStep: 10,\n};\n\nexport function resolveConfig(config: CIBeforeAfterConfig): ResolvedConfig {\n const labels = config.labels;\n let labelsEnabled = true;\n let labelBefore = 'Before';\n let labelAfter = 'After';\n\n if (labels === false) {\n labelsEnabled = false;\n } else if (typeof labels === 'object') {\n labelBefore = labels.before ?? 'Before';\n labelAfter = labels.after ?? 'After';\n }\n\n const animate = config.animate;\n let animateEnabled = false;\n let animateDuration = 800;\n let animateDelay = 0;\n let animateEasing = 'ease-out';\n\n if (animate === true) {\n animateEnabled = true;\n } else if (typeof animate === 'object') {\n animateEnabled = true;\n animateDuration = Math.max(0, animate.duration ?? 800);\n animateDelay = Math.max(0, animate.delay ?? 0);\n animateEasing = animate.easing ?? 'ease-out';\n }\n\n const zoom = config.zoom ?? DEFAULTS.zoom;\n\n return {\n beforeSrc: config.beforeSrc,\n afterSrc: config.afterSrc,\n beforeAlt: config.beforeAlt ?? DEFAULTS.beforeAlt,\n afterAlt: config.afterAlt ?? DEFAULTS.afterAlt,\n mode: validateEnumWithDefault(config.mode, VALID_MODES, DEFAULTS.mode, 'mode'),\n orientation: validateEnumWithDefault(config.orientation, VALID_ORIENTATIONS, DEFAULTS.orientation, 'orientation'),\n initialPosition: clampPosition(config.initialPosition ?? DEFAULTS.initialPosition),\n zoom,\n zoomMax: Math.max(1, config.zoomMax ?? DEFAULTS.zoomMax),\n zoomMin: Math.max(1, Math.min(config.zoomMin ?? DEFAULTS.zoomMin, config.zoomMax ?? DEFAULTS.zoomMax)),\n theme: validateEnumWithDefault(config.theme, VALID_THEMES, DEFAULTS.theme, 'theme'),\n handleStyle: validateEnumWithDefault(config.handleStyle, VALID_HANDLE_STYLES, DEFAULTS.handleStyle, 'handleStyle'),\n labelsEnabled,\n labelBefore,\n labelAfter,\n labelPosition: validateEnumWithDefault(config.labelPosition, VALID_LABEL_POSITIONS, DEFAULTS.labelPosition, 'labelPosition'),\n animateEnabled,\n animateDuration,\n animateDelay,\n animateEasing,\n animateOnce: config.animateOnce ?? DEFAULTS.animateOnce,\n fullscreenButton: config.fullscreenButton ?? DEFAULTS.fullscreenButton,\n lazyLoad: config.lazyLoad ?? DEFAULTS.lazyLoad,\n zoomControls: config.zoomControls ?? (zoom ? DEFAULTS.zoomControls : false),\n zoomControlsPosition: validateEnumWithDefault(config.zoomControlsPosition, VALID_ZOOM_POSITIONS, DEFAULTS.zoomControlsPosition, 'zoomControlsPosition'),\n scrollHint: config.scrollHint ?? (zoom ? DEFAULTS.scrollHint : false),\n keyboardStep: Math.max(0.5, config.keyboardStep ?? DEFAULTS.keyboardStep),\n keyboardLargeStep: Math.max(1, config.keyboardLargeStep ?? DEFAULTS.keyboardLargeStep),\n onSlide: config.onSlide,\n onZoom: config.onZoom,\n onFullscreenChange: config.onFullscreenChange,\n onReady: config.onReady,\n cloudimage: config.cloudimage,\n };\n}\n\nfunction validateEnum<T extends string>(value: string, allowed: T[], name: string): T | undefined {\n if ((allowed as string[]).includes(value)) return value as T;\n console.warn(`CIBeforeAfter: Invalid ${name} \"${value}\". Allowed: ${allowed.join(', ')}`);\n return undefined;\n}\n\nfunction validateEnumWithDefault<T extends string>(value: T | undefined, allowed: T[], defaultValue: T, name: string): T {\n if (value === undefined) return defaultValue;\n if ((allowed as string[]).includes(value)) return value;\n console.warn(`CIBeforeAfter: Invalid ${name} \"${value}\". Allowed: ${allowed.join(', ')}. Using default \"${defaultValue}\".`);\n return defaultValue;\n}\n\nexport function parseDataAttributes(el: HTMLElement): CIBeforeAfterConfig {\n const get = (name: string): string | null => el.getAttribute(`data-ci-before-after-${name}`);\n const getBool = (name: string): boolean | undefined => {\n const val = get(name);\n if (val === null) return undefined;\n return val === 'true';\n };\n const getNum = (name: string): number | undefined => {\n const val = get(name);\n if (val === null) return undefined;\n const n = parseFloat(val);\n return isNaN(n) ? undefined : n;\n };\n\n const beforeSrc = get('before-src');\n const afterSrc = get('after-src');\n\n if (!beforeSrc || !afterSrc) {\n throw new Error('CIBeforeAfter: data-ci-before-after-before-src and data-ci-before-after-after-src are required');\n }\n\n const config: CIBeforeAfterConfig = {\n beforeSrc,\n afterSrc,\n };\n\n const beforeAlt = get('before-alt');\n if (beforeAlt !== null) config.beforeAlt = beforeAlt;\n\n const afterAlt = get('after-alt');\n if (afterAlt !== null) config.afterAlt = afterAlt;\n\n const mode = get('mode');\n if (mode) config.mode = validateEnum(mode, VALID_MODES, 'mode');\n\n const orientation = get('orientation');\n if (orientation) config.orientation = validateEnum(orientation, VALID_ORIENTATIONS, 'orientation');\n\n const initialPosition = getNum('initial-position');\n if (initialPosition !== undefined) config.initialPosition = initialPosition;\n\n const zoom = getBool('zoom');\n if (zoom !== undefined) config.zoom = zoom;\n\n const zoomMax = getNum('zoom-max');\n if (zoomMax !== undefined) config.zoomMax = zoomMax;\n\n const zoomMin = getNum('zoom-min');\n if (zoomMin !== undefined) config.zoomMin = zoomMin;\n\n const theme = get('theme');\n if (theme) config.theme = validateEnum(theme, VALID_THEMES, 'theme');\n\n const handleStyle = get('handle-style');\n if (handleStyle) config.handleStyle = validateEnum(handleStyle, VALID_HANDLE_STYLES, 'handleStyle');\n\n const labelsAttr = getBool('labels');\n const labelBefore = get('label-before');\n const labelAfter = get('label-after');\n\n if (labelsAttr === false) {\n config.labels = false;\n } else if (labelBefore !== null || labelAfter !== null) {\n config.labels = {\n before: labelBefore ?? undefined,\n after: labelAfter ?? undefined,\n };\n } else if (labelsAttr === true) {\n config.labels = true;\n }\n\n const labelPosition = get('label-position');\n if (labelPosition) config.labelPosition = validateEnum(labelPosition, VALID_LABEL_POSITIONS, 'labelPosition');\n\n const animateAttr = getBool('animate');\n const animateDuration = getNum('animate-duration');\n const animateDelay = getNum('animate-delay');\n const animateEasing = get('animate-easing');\n\n if (animateDuration !== undefined || animateDelay !== undefined || (animateEasing !== null && animateEasing !== undefined)) {\n config.animate = {\n duration: animateDuration,\n delay: animateDelay,\n easing: animateEasing ?? undefined,\n };\n } else if (animateAttr !== undefined) {\n config.animate = animateAttr;\n }\n\n const animateOnce = getBool('animate-once');\n if (animateOnce !== undefined) config.animateOnce = animateOnce;\n\n const fullscreenButton = getBool('fullscreen-button');\n if (fullscreenButton !== undefined) config.fullscreenButton = fullscreenButton;\n\n const lazyLoad = getBool('lazy-load');\n if (lazyLoad !== undefined) config.lazyLoad = lazyLoad;\n\n const zoomControls = getBool('zoom-controls');\n if (zoomControls !== undefined) config.zoomControls = zoomControls;\n\n const zoomControlsPosition = get('zoom-controls-position');\n if (zoomControlsPosition) config.zoomControlsPosition = validateEnum(zoomControlsPosition, VALID_ZOOM_POSITIONS, 'zoomControlsPosition');\n\n const scrollHint = getBool('scroll-hint');\n if (scrollHint !== undefined) config.scrollHint = scrollHint;\n\n const keyboardStep = getNum('keyboard-step');\n if (keyboardStep !== undefined) config.keyboardStep = keyboardStep;\n\n const keyboardLargeStep = getNum('keyboard-large-step');\n if (keyboardLargeStep !== undefined) config.keyboardLargeStep = keyboardLargeStep;\n\n const ciToken = get('ci-token');\n if (ciToken) {\n config.cloudimage = {\n token: ciToken,\n apiVersion: get('ci-api-version') ?? undefined,\n domain: get('ci-domain') ?? undefined,\n limitFactor: getNum('ci-limit-factor'),\n params: get('ci-params') ?? undefined,\n };\n }\n\n return config;\n}\n\nfunction clampPosition(value: number): number {\n if (!isFinite(value)) return 50;\n return Math.max(0, Math.min(100, value));\n}\n","const STYLE_ID = 'ci-before-after-styles';\n\nexport function injectStyles(css: string): void {\n if (!isBrowser()) return;\n if (document.getElementById(STYLE_ID)) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = css;\n document.head.appendChild(style);\n}\n\nexport function createElement<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n className?: string,\n attrs?: Record<string, string>,\n): HTMLElementTagNameMap[K] {\n const el = document.createElement(tag);\n if (className) el.className = className;\n if (attrs) {\n for (const [key, value] of Object.entries(attrs)) {\n el.setAttribute(key, value);\n }\n }\n return el;\n}\n\nexport function resolveElement(target: HTMLElement | string): HTMLElement {\n if (typeof target === 'string') {\n const el = document.querySelector<HTMLElement>(target);\n if (!el) {\n throw new Error(`CIBeforeAfter: Element not found for selector \"${target}\"`);\n }\n return el;\n }\n return target;\n}\n\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\nexport function supportsFullscreen(): boolean {\n if (!isBrowser()) return false;\n const doc = document as Document & {\n webkitFullscreenEnabled?: boolean;\n };\n return !!(doc.fullscreenEnabled || doc.webkitFullscreenEnabled);\n}\n\nexport function requestFullscreen(el: HTMLElement): Promise<void> {\n const elem = el as HTMLElement & {\n webkitRequestFullscreen?: () => Promise<void>;\n };\n if (elem.requestFullscreen) return elem.requestFullscreen();\n if (elem.webkitRequestFullscreen) return elem.webkitRequestFullscreen();\n return Promise.reject(new Error('Fullscreen API not supported'));\n}\n\nexport function exitFullscreen(): Promise<void> {\n const doc = document as Document & {\n webkitExitFullscreen?: () => Promise<void>;\n };\n if (doc.exitFullscreen) return doc.exitFullscreen();\n if (doc.webkitExitFullscreen) return doc.webkitExitFullscreen();\n return Promise.reject(new Error('Fullscreen API not supported'));\n}\n\nexport function getFullscreenElement(): Element | null {\n const doc = document as Document & {\n webkitFullscreenElement?: Element;\n };\n return doc.fullscreenElement || doc.webkitFullscreenElement || null;\n}\n","type EventCleanup = () => void;\n\nexport class EventManager {\n private cleanups: EventCleanup[] = [];\n\n on<K extends keyof HTMLElementEventMap>(\n el: HTMLElement | Window | Document,\n event: K,\n handler: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n ): void {\n el.addEventListener(event, handler as EventListener, options);\n this.cleanups.push(() => el.removeEventListener(event, handler as EventListener, options));\n }\n\n onPassive<K extends keyof HTMLElementEventMap>(\n el: HTMLElement | Window | Document,\n event: K,\n handler: (e: HTMLElementEventMap[K]) => void,\n ): void {\n this.on(el, event, handler, { passive: true });\n }\n\n onNonPassive<K extends keyof HTMLElementEventMap>(\n el: HTMLElement | Window | Document,\n event: K,\n handler: (e: HTMLElementEventMap[K]) => void,\n ): void {\n this.on(el, event, handler, { passive: false });\n }\n\n destroy(): void {\n for (const cleanup of this.cleanups) {\n cleanup();\n }\n this.cleanups = [];\n }\n}\n\nexport function getPointerPosition(\n e: MouseEvent | TouchEvent,\n rect: DOMRect,\n): { x: number; y: number } {\n let clientX: number;\n let clientY: number;\n\n if ('touches' in e) {\n const touch = e.touches[0] || e.changedTouches?.[0];\n if (!touch) return { x: 0, y: 0 };\n clientX = touch.clientX;\n clientY = touch.clientY;\n } else {\n clientX = e.clientX;\n clientY = e.clientY;\n }\n\n return {\n x: clientX - rect.left,\n y: clientY - rect.top,\n };\n}\n\nexport function getPositionPercent(\n e: MouseEvent | TouchEvent,\n rect: DOMRect,\n orientation: 'horizontal' | 'vertical',\n): number {\n const { x, y } = getPointerPosition(e, rect);\n const dimension = orientation === 'horizontal' ? rect.width : rect.height;\n if (dimension === 0) return 50;\n const offset = orientation === 'horizontal' ? x : y;\n return Math.max(0, Math.min(100, (offset / dimension) * 100));\n}\n","import type { CloudimageConfig } from '../core/types';\n\nconst TOKEN_PATTERN = /^[a-zA-Z0-9_-]+$/;\nconst DOMAIN_PATTERN = /^[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/;\nconst API_VERSION_PATTERN = /^v\\d+$/;\n\nfunction validateCloudimageConfig(config: CloudimageConfig): void {\n if (!TOKEN_PATTERN.test(config.token)) {\n throw new Error(`CIBeforeAfter: Invalid cloudimage token \"${config.token}\". Must match [a-zA-Z0-9_-]+`);\n }\n if (config.domain && !DOMAIN_PATTERN.test(config.domain)) {\n throw new Error(`CIBeforeAfter: Invalid cloudimage domain \"${config.domain}\".`);\n }\n if (config.apiVersion && !API_VERSION_PATTERN.test(config.apiVersion)) {\n throw new Error(`CIBeforeAfter: Invalid cloudimage apiVersion \"${config.apiVersion}\". Must be \"v\" followed by digits.`);\n }\n}\n\nexport function buildCloudimageUrl(\n src: string,\n containerWidth: number,\n config: CloudimageConfig,\n): string {\n validateCloudimageConfig(config);\n\n const {\n token,\n apiVersion = 'v7',\n domain = 'cloudimg.io',\n limitFactor = 100,\n params = '',\n devicePixelRatioList = [1, 1.5, 2],\n } = config;\n\n const dpr = typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1;\n const dprList = devicePixelRatioList.length > 0 ? devicePixelRatioList : [1];\n const closestDpr = dprList.reduce((prev, curr) =>\n Math.abs(curr - dpr) < Math.abs(prev - dpr) ? curr : prev,\n );\n\n const safeLimitFactor = limitFactor > 0 ? limitFactor : 100;\n const rawWidth = containerWidth * closestDpr;\n const roundedWidth = Math.ceil(rawWidth / safeLimitFactor) * safeLimitFactor;\n\n const baseUrl = `https://${token}.${domain}/${apiVersion}`;\n // Params are expected to be valid query string segments (e.g. \"q=80&org_if_sml=1\")\n const paramStr = params\n ? `?${params}&w=${roundedWidth}`\n : `?w=${roundedWidth}`;\n\n if (src.startsWith('http://') || src.startsWith('https://')) {\n return `${baseUrl}/${src}${paramStr}`;\n }\n\n return `${baseUrl}/${src}${paramStr}`;\n}\n","import type { Orientation } from '../core/types';\n\nexport interface ClipZoomInfo {\n level: number;\n panX: number;\n panY: number;\n containerWidth: number;\n containerHeight: number;\n}\n\nexport function updateClipPath(\n clipEl: HTMLElement,\n position: number,\n orientation: Orientation,\n zoom?: ClipZoomInfo,\n): void {\n let adjusted = position;\n\n if (zoom && zoom.level > 1) {\n if (orientation === 'horizontal') {\n adjusted = position / zoom.level - zoom.panX * 100 / (zoom.level * zoom.containerWidth);\n } else {\n adjusted = position / zoom.level - zoom.panY * 100 / (zoom.level * zoom.containerHeight);\n }\n adjusted = Math.max(0, Math.min(100, adjusted));\n }\n\n const value = orientation === 'horizontal'\n ? `inset(0 0 0 ${adjusted}%)`\n : `inset(${adjusted}% 0 0 0)`;\n clipEl.style.clipPath = value;\n // Safari < 14 prefix (QUAL-03)\n clipEl.style.setProperty('-webkit-clip-path', value);\n}\n\nexport function updateHandlePosition(\n handleEl: HTMLElement,\n position: number,\n orientation: Orientation,\n): void {\n if (orientation === 'horizontal') {\n handleEl.style.left = `${position}%`;\n handleEl.style.top = '';\n } else {\n handleEl.style.top = `${position}%`;\n handleEl.style.left = '';\n }\n}\n\nexport function clampPosition(value: number): number {\n if (!isFinite(value)) return 50;\n return Math.max(0, Math.min(100, value));\n}\n","import type { HandleStyle, Orientation } from '../core/types';\nimport { createElement } from '../utils/dom';\n\nconst CHEVRON_LEFT = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m15 18-6-6 6-6\"/></svg>';\nconst CHEVRON_RIGHT = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m9 18 6-6-6-6\"/></svg>';\nconst CHEVRON_UP = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m18 15-6-6-6 6\"/></svg>';\nconst CHEVRON_DOWN = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m6 9 6 6 6-6\"/></svg>';\nconst MOVE_HORIZONTAL = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"18 8 22 12 18 16\"/><polyline points=\"6 8 2 12 6 16\"/><line x1=\"2\" x2=\"22\" y1=\"12\" y2=\"12\"/></svg>';\nconst MOVE_VERTICAL = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"8 18 12 22 16 18\"/><polyline points=\"8 6 12 2 16 6\"/><line x1=\"12\" x2=\"12\" y1=\"2\" y2=\"22\"/></svg>';\n\nexport function createHandle(\n style: HandleStyle,\n orientation: Orientation,\n position: number,\n): HTMLElement {\n const handle = createElement('div', `ci-before-after-handle ci-before-after-handle--${style}`, {\n role: 'slider',\n 'aria-valuenow': String(Math.round(position)),\n 'aria-valuemin': '0',\n 'aria-valuemax': '100',\n 'aria-label': 'Image comparison slider. Use arrow keys to adjust the before and after split position.',\n 'aria-orientation': orientation,\n tabindex: '0',\n });\n\n if (orientation === 'horizontal') {\n handle.style.left = `${position}%`;\n } else {\n handle.style.top = `${position}%`;\n }\n\n switch (style) {\n case 'arrows':\n buildArrowsHandle(handle, orientation);\n break;\n case 'circle':\n buildCircleHandle(handle, orientation);\n break;\n case 'line':\n buildLineHandle(handle);\n break;\n }\n\n return handle;\n}\n\nfunction buildArrowsHandle(handle: HTMLElement, orientation: Orientation): void {\n const line1 = createElement('div', 'ci-before-after-handle-line');\n const grip = createElement('div', 'ci-before-after-handle-grip');\n const line2 = createElement('div', 'ci-before-after-handle-line');\n\n if (orientation === 'horizontal') {\n grip.innerHTML = CHEVRON_LEFT + CHEVRON_RIGHT;\n } else {\n grip.innerHTML = CHEVRON_UP + CHEVRON_DOWN;\n }\n\n handle.append(line1, grip, line2);\n}\n\nfunction buildCircleHandle(handle: HTMLElement, orientation: Orientation): void {\n const grip = createElement('div', 'ci-before-after-handle-grip');\n\n if (orientation === 'horizontal') {\n grip.innerHTML = MOVE_HORIZONTAL;\n } else {\n grip.innerHTML = MOVE_VERTICAL;\n }\n\n handle.append(grip);\n}\n\nfunction buildLineHandle(handle: HTMLElement): void {\n const line1 = createElement('div', 'ci-before-after-handle-line');\n const grip = createElement('div', 'ci-before-after-handle-grip ci-before-after-handle-grip--pill');\n const line2 = createElement('div', 'ci-before-after-handle-line');\n\n handle.append(line1, grip, line2);\n}\n","import type { InteractionMode, Orientation } from '../core/types';\nimport { EventManager, getPositionPercent } from '../utils/events';\n\nexport interface SliderGesturesCallbacks {\n onPositionChange: (position: number) => void;\n onDragStart: () => void;\n onDragEnd: () => void;\n}\n\nexport class SliderGestures {\n private events = new EventManager();\n private containerRect: DOMRect | null = null;\n private rafId: number | null = null;\n private pendingPosition: number | null = null;\n private abortController: AbortController | null = null;\n\n constructor(\n private container: HTMLElement,\n private handle: HTMLElement,\n private mode: InteractionMode,\n private orientation: Orientation,\n private callbacks: SliderGesturesCallbacks,\n ) {\n this.bind();\n }\n\n private bind(): void {\n switch (this.mode) {\n case 'drag':\n this.bindDrag();\n break;\n case 'hover':\n this.bindHover();\n break;\n case 'click':\n this.bindClick();\n break;\n }\n }\n\n private bindDrag(): void {\n this.events.on(this.handle, 'mousedown', (e: MouseEvent) => {\n e.preventDefault();\n this.startDrag();\n });\n\n this.events.on(this.handle, 'touchstart', (e: TouchEvent) => {\n e.preventDefault();\n this.handle.focus();\n this.startTouchDrag();\n }, { passive: false });\n }\n\n private startDrag(): void {\n this.cleanupWindowListeners();\n this.abortController = new AbortController();\n const signal = this.abortController.signal;\n\n this.containerRect = this.container.getBoundingClientRect();\n this.callbacks.onDragStart();\n\n const onMouseMove = (e: MouseEvent) => {\n if (!this.containerRect) return;\n const position = getPositionPercent(e, this.containerRect, this.orientation);\n this.schedulePositionUpdate(position);\n };\n\n const onMouseUp = () => {\n this.flushPositionUpdate();\n this.callbacks.onDragEnd();\n this.containerRect = null;\n this.cleanupWindowListeners();\n };\n\n window.addEventListener('mousemove', onMouseMove, { signal });\n window.addEventListener('mouseup', onMouseUp, { signal });\n }\n\n private startTouchDrag(): void {\n this.cleanupWindowListeners();\n this.abortController = new AbortController();\n const signal = this.abortController.signal;\n\n this.containerRect = this.container.getBoundingClientRect();\n this.callbacks.onDragStart();\n\n const onTouchMove = (e: TouchEvent) => {\n if (!this.containerRect) return;\n if (e.touches.length !== 1) return;\n e.preventDefault();\n const position = getPositionPercent(e, this.containerRect, this.orientation);\n this.schedulePositionUpdate(position);\n };\n\n const onTouchEnd = () => {\n this.flushPositionUpdate();\n this.callbacks.onDragEnd();\n this.containerRect = null;\n this.cleanupWindowListeners();\n };\n\n window.addEventListener('touchmove', onTouchMove, { passive: false, signal });\n window.addEventListener('touchend', onTouchEnd, { signal });\n window.addEventListener('touchcancel', onTouchEnd, { signal });\n }\n\n private schedulePositionUpdate(position: number): void {\n this.pendingPosition = position;\n if (this.rafId === null) {\n this.rafId = requestAnimationFrame(() => {\n this.rafId = null;\n if (this.pendingPosition !== null) {\n this.callbacks.onPositionChange(this.pendingPosition);\n this.pendingPosition = null;\n }\n });\n }\n }\n\n private flushPositionUpdate(): void {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n if (this.pendingPosition !== null) {\n this.callbacks.onPositionChange(this.pendingPosition);\n this.pendingPosition = null;\n }\n }\n\n private cleanupWindowListeners(): void {\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n }\n\n private bindHover(): void {\n this.events.on(this.container, 'mousemove', (e: MouseEvent) => {\n const rect = this.container.getBoundingClientRect();\n const position = getPositionPercent(e, rect, this.orientation);\n this.schedulePositionUpdate(position);\n });\n }\n\n private bindClick(): void {\n this.events.on(this.container, 'click', (e: MouseEvent) => {\n if (this.handle.contains(e.target as Node)) return;\n const rect = this.container.getBoundingClientRect();\n const position = getPositionPercent(e, rect, this.orientation);\n this.callbacks.onPositionChange(position);\n });\n }\n\n updateMode(mode: InteractionMode): void {\n this.events.destroy();\n this.cleanupWindowListeners();\n this.flushPositionUpdate();\n this.mode = mode;\n this.bind();\n }\n\n updateOrientation(orientation: Orientation): void {\n this.orientation = orientation;\n }\n\n destroy(): void {\n this.cleanupWindowListeners();\n // Discard pending position instead of flushing — avoid firing onSlide during teardown\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n this.pendingPosition = null;\n this.events.destroy();\n this.containerRect = null;\n }\n}\n","import type { ResolvedConfig } from '../core/types';\n\nexport class ZoomPanController {\n private zoomLevel = 1;\n private panX = 0;\n private panY = 0;\n private containerWidth = 0;\n private containerHeight = 0;\n private transitioning = false;\n private transitionEndCleanup: (() => void) | null = null;\n private resizeObserver: ResizeObserver | null = null;\n\n private onTransformChange?: () => void;\n\n constructor(\n private viewport: HTMLElement,\n private container: HTMLElement,\n private config: ResolvedConfig,\n private onZoomChange?: (level: number) => void,\n onTransformChange?: () => void,\n ) {\n this.onTransformChange = onTransformChange;\n this.updateContainerSize();\n this.observeResize();\n }\n\n private observeResize(): void {\n if (typeof ResizeObserver === 'undefined') return;\n this.resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect;\n this.containerWidth = width;\n this.containerHeight = height;\n }\n });\n this.resizeObserver.observe(this.container);\n }\n\n getZoom(): number {\n return this.zoomLevel;\n }\n\n getContainerSize(): { width: number; height: number } {\n return { width: this.containerWidth, height: this.containerHeight };\n }\n\n setZoom(level: number, centerX?: number, centerY?: number): void {\n const clamped = Math.max(this.config.zoomMin, Math.min(this.config.zoomMax, level));\n if (clamped === this.zoomLevel) return;\n\n const oldZoom = this.zoomLevel;\n this.zoomLevel = clamped;\n\n // Adjust pan to keep the center point fixed\n if (centerX !== undefined && centerY !== undefined) {\n this.panX = centerX - (centerX - this.panX) * (clamped / oldZoom);\n this.panY = centerY - (centerY - this.panY) * (clamped / oldZoom);\n }\n\n this.clampPan();\n this.applyTransform(true);\n this.onZoomChange?.(this.zoomLevel);\n }\n\n zoomIn(): void {\n this.setZoom(\n this.zoomLevel * 1.5,\n this.containerWidth / 2,\n this.containerHeight / 2,\n );\n }\n\n zoomOut(): void {\n this.setZoom(\n this.zoomLevel / 1.5,\n this.containerWidth / 2,\n this.containerHeight / 2,\n );\n }\n\n resetZoom(): void {\n this.zoomLevel = Math.max(1, this.config.zoomMin);\n this.panX = 0;\n this.panY = 0;\n this.applyTransform(true);\n this.onZoomChange?.(this.zoomLevel);\n }\n\n getPan(): { x: number; y: number } {\n return { x: this.panX, y: this.panY };\n }\n\n setPan(x: number, y: number): void {\n this.panX = x;\n this.panY = y;\n this.clampPan();\n this.applyTransform(false);\n }\n\n pan(dx: number, dy: number): void {\n if (this.zoomLevel <= 1) return;\n this.panX += dx;\n this.panY += dy;\n this.clampPan();\n this.applyTransform(false);\n }\n\n handleWheel(e: WheelEvent): void {\n if (!e.ctrlKey && !e.metaKey) return;\n\n e.preventDefault();\n\n const rect = this.container.getBoundingClientRect();\n const centerX = e.clientX - rect.left;\n const centerY = e.clientY - rect.top;\n\n const delta = e.deltaY > 0 ? 0.9 : 1.1;\n this.setZoom(this.zoomLevel * delta, centerX, centerY);\n }\n\n toggleZoom(centerX: number, centerY: number): void {\n const resetLevel = Math.max(1, this.config.zoomMin);\n if (this.zoomLevel > resetLevel) {\n this.resetZoom();\n } else {\n this.setZoom(Math.max(2, resetLevel * 1.5), centerX, centerY);\n }\n }\n\n updateConfig(config: ResolvedConfig): void {\n this.config = config;\n // Re-clamp zoom level to new min/max bounds\n const clamped = Math.max(config.zoomMin, Math.min(config.zoomMax, this.zoomLevel));\n if (clamped !== this.zoomLevel) {\n this.zoomLevel = clamped;\n this.onZoomChange?.(this.zoomLevel);\n }\n this.clampPan();\n this.applyTransform(false);\n }\n\n private updateContainerSize(): void {\n const rect = this.container.getBoundingClientRect();\n this.containerWidth = rect.width;\n this.containerHeight = rect.height;\n }\n\n private clampPan(): void {\n if (this.zoomLevel <= 1) {\n this.panX = 0;\n this.panY = 0;\n return;\n }\n\n const maxPanX = this.containerWidth * (this.zoomLevel - 1);\n const maxPanY = this.containerHeight * (this.zoomLevel - 1);\n\n this.panX = Math.max(-maxPanX, Math.min(0, this.panX));\n this.panY = Math.max(-maxPanY, Math.min(0, this.panY));\n }\n\n private applyTransform(animate: boolean): void {\n // Clean up previous transitionend listener to prevent accumulation\n if (this.transitionEndCleanup) {\n this.transitionEndCleanup();\n this.transitionEndCleanup = null;\n }\n\n if (animate) {\n this.viewport.style.transition = 'transform 300ms ease';\n this.transitioning = true;\n const onEnd = (e: TransitionEvent) => {\n if (e.target !== this.viewport) return; // Ignore bubbled events from children\n this.viewport.style.transition = '';\n this.transitioning = false;\n this.transitionEndCleanup = null;\n this.viewport.removeEventListener('transitionend', onEnd);\n };\n this.viewport.addEventListener('transitionend', onEnd);\n this.transitionEndCleanup = () => {\n this.viewport.removeEventListener('transitionend', onEnd);\n this.viewport.style.transition = '';\n this.transitioning = false;\n };\n } else if (!this.transitioning) {\n this.viewport.style.transition = '';\n }\n\n this.viewport.style.transform =\n `scale(${this.zoomLevel}) translate(${this.panX / this.zoomLevel}px, ${this.panY / this.zoomLevel}px)`;\n\n this.onTransformChange?.();\n }\n\n destroy(): void {\n if (this.transitionEndCleanup) {\n this.transitionEndCleanup();\n this.transitionEndCleanup = null;\n }\n this.viewport.style.transform = '';\n this.viewport.style.transition = '';\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n }\n}\n","import { EventManager } from '../utils/events';\nimport type { ZoomPanController } from './zoom-pan';\n\nconst PAN_THRESHOLD = 3;\n\nexport class ZoomGestures {\n private events = new EventManager();\n private isPanning = false;\n private lastPanX = 0;\n private lastPanY = 0;\n private initialPinchDistance = 0;\n private initialPinchZoom = 1;\n private abortController: AbortController | null = null;\n\n constructor(\n private container: HTMLElement,\n private handle: HTMLElement,\n private zoomPan: ZoomPanController,\n private scrollHintCallback?: () => void,\n ) {\n this.bind();\n }\n\n private bind(): void {\n // Ctrl+Wheel zoom\n this.events.onNonPassive(this.container, 'wheel', (e: WheelEvent) => {\n if (e.ctrlKey || e.metaKey) {\n this.zoomPan.handleWheel(e);\n } else if (this.zoomPan.getZoom() > 1) {\n // Allow scroll pass-through when zoomed\n } else {\n this.scrollHintCallback?.();\n }\n });\n\n // Double-click to toggle zoom (not on handle)\n this.events.on(this.container, 'dblclick', (e: MouseEvent) => {\n if (this.handle.contains(e.target as Node)) return;\n const rect = this.container.getBoundingClientRect();\n this.zoomPan.toggleZoom(e.clientX - rect.left, e.clientY - rect.top);\n });\n\n // Pan via mouse drag (only when zoomed, not on handle)\n this.events.on(this.container, 'mousedown', (e: MouseEvent) => {\n if (this.handle.contains(e.target as Node)) return;\n if (this.zoomPan.getZoom() <= 1) return;\n e.preventDefault();\n this.startPan(e.clientX, e.clientY);\n });\n\n // Touch gestures (pinch + pan)\n this.events.on(this.container, 'touchstart', (e: TouchEvent) => {\n if (this.handle.contains(e.target as Node)) return;\n\n if (e.touches.length === 2) {\n e.preventDefault();\n this.startPinch(e);\n } else if (e.touches.length === 1 && this.zoomPan.getZoom() > 1) {\n e.preventDefault();\n this.startTouchPan(e);\n }\n }, { passive: false });\n\n // Safari GestureEvent\n if (typeof window !== 'undefined' && 'GestureEvent' in window) {\n let gestureCenterX = 0;\n let gestureCenterY = 0;\n\n this.events.onNonPassive(this.container, 'gesturestart' as keyof HTMLElementEventMap, (e: Event) => {\n e.preventDefault();\n this.initialPinchZoom = this.zoomPan.getZoom();\n const ge = e as GestureEvent & { clientX: number; clientY: number };\n const rect = this.container.getBoundingClientRect();\n gestureCenterX = ge.clientX - rect.left;\n gestureCenterY = ge.clientY - rect.top;\n });\n\n this.events.onNonPassive(this.container, 'gesturechange' as keyof HTMLElementEventMap, (e: Event) => {\n e.preventDefault();\n const ge = e as GestureEvent & { clientX: number; clientY: number };\n const rect = this.container.getBoundingClientRect();\n this.zoomPan.setZoom(\n this.initialPinchZoom * ge.scale,\n ge.clientX - rect.left,\n ge.clientY - rect.top,\n );\n });\n }\n }\n\n private startPan(clientX: number, clientY: number): void {\n this.cleanupWindowListeners();\n this.abortController = new AbortController();\n const signal = this.abortController.signal;\n\n this.isPanning = false;\n this.lastPanX = clientX;\n this.lastPanY = clientY;\n const startX = clientX;\n const startY = clientY;\n\n const onMouseMove = (e: MouseEvent) => {\n const dx = e.clientX - this.lastPanX;\n const dy = e.clientY - this.lastPanY;\n\n // Only start panning after exceeding threshold (BUG-09)\n if (!this.isPanning) {\n const totalDx = e.clientX - startX;\n const totalDy = e.clientY - startY;\n if (Math.hypot(totalDx, totalDy) < PAN_THRESHOLD) return;\n this.isPanning = true;\n this.container.style.cursor = 'grabbing';\n }\n\n this.lastPanX = e.clientX;\n this.lastPanY = e.clientY;\n this.zoomPan.pan(dx, dy);\n };\n\n const onMouseUp = () => {\n this.isPanning = false;\n this.container.style.cursor = '';\n this.cleanupWindowListeners();\n };\n\n window.addEventListener('mousemove', onMouseMove, { signal });\n window.addEventListener('mouseup', onMouseUp, { signal });\n }\n\n private startTouchPan(e: TouchEvent): void {\n this.cleanupWindowListeners();\n this.abortController = new AbortController();\n const signal = this.abortController.signal;\n\n const touch = e.touches[0];\n this.lastPanX = touch.clientX;\n this.lastPanY = touch.clientY;\n\n const onTouchMove = (e: TouchEvent) => {\n if (e.touches.length !== 1) return;\n e.preventDefault();\n const touch = e.touches[0];\n const dx = touch.clientX - this.lastPanX;\n const dy = touch.clientY - this.lastPanY;\n this.lastPanX = touch.clientX;\n this.lastPanY = touch.clientY;\n this.zoomPan.pan(dx, dy);\n };\n\n const onTouchEnd = () => {\n this.cleanupWindowListeners();\n };\n\n window.addEventListener('touchmove', onTouchMove, { passive: false, signal });\n window.addEventListener('touchend', onTouchEnd, { signal });\n window.addEventListener('touchcancel', onTouchEnd, { signal });\n }\n\n private startPinch(e: TouchEvent): void {\n if (e.touches.length < 2) return;\n\n this.cleanupWindowListeners();\n this.abortController = new AbortController();\n const signal = this.abortController.signal;\n const [t1, t2] = [e.touches[0], e.touches[1]];\n this.initialPinchDistance = Math.hypot(t2.clientX - t1.clientX, t2.clientY - t1.clientY);\n if (this.initialPinchDistance === 0) this.initialPinchDistance = 1;\n this.initialPinchZoom = this.zoomPan.getZoom();\n\n const rect = this.container.getBoundingClientRect();\n const centerX = (t1.clientX + t2.clientX) / 2 - rect.left;\n const centerY = (t1.clientY + t2.clientY) / 2 - rect.top;\n\n const onTouchMove = (e: TouchEvent) => {\n if (e.touches.length !== 2) return;\n e.preventDefault();\n const [t1, t2] = [e.touches[0], e.touches[1]];\n const dist = Math.hypot(t2.clientX - t1.clientX, t2.clientY - t1.clientY);\n const scale = dist / this.initialPinchDistance;\n this.zoomPan.setZoom(this.initialPinchZoom * scale, centerX, centerY);\n };\n\n const onTouchEnd = () => {\n this.cleanupWindowListeners();\n };\n\n window.addEventListener('touchmove', onTouchMove, { passive: false, signal });\n window.addEventListener('touchend', onTouchEnd, { signal });\n window.addEventListener('touchcancel', onTouchEnd, { signal });\n }\n\n private cleanupWindowListeners(): void {\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n }\n\n destroy(): void {\n this.cleanupWindowListeners();\n this.events.destroy();\n }\n}\n\ninterface GestureEvent extends Event {\n scale: number;\n}\n","import type { ZoomControlsPosition } from '../core/types';\nimport { createElement } from '../utils/dom';\nimport { EventManager } from '../utils/events';\n\nconst PLUS_ICON = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M5 12h14\"/><path d=\"M12 5v14\"/></svg>';\nconst MINUS_ICON = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M5 12h14\"/></svg>';\nconst RESET_ICON = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\"/><path d=\"M3 3v5h5\"/></svg>';\n\nexport interface ZoomControlsCallbacks {\n onZoomIn: () => void;\n onZoomOut: () => void;\n onReset: () => void;\n}\n\nexport interface ZoomControlsResult {\n element: HTMLElement;\n events: EventManager;\n}\n\nexport function createZoomControls(\n position: ZoomControlsPosition,\n callbacks: ZoomControlsCallbacks,\n): ZoomControlsResult {\n const events = new EventManager();\n const wrapper = createElement('div', `ci-before-after-zoom-controls ci-before-after-zoom-controls--${position}`);\n\n const zoomInBtn = createElement('button', 'ci-before-after-zoom-in', {\n type: 'button',\n 'aria-label': 'Zoom in',\n });\n zoomInBtn.innerHTML = PLUS_ICON;\n events.on(zoomInBtn, 'click', callbacks.onZoomIn);\n\n const zoomOutBtn = createElement('button', 'ci-before-after-zoom-out', {\n type: 'button',\n 'aria-label': 'Zoom out',\n });\n zoomOutBtn.innerHTML = MINUS_ICON;\n events.on(zoomOutBtn, 'click', callbacks.onZoomOut);\n\n const resetBtn = createElement('button', 'ci-before-after-zoom-reset', {\n type: 'button',\n 'aria-label': 'Reset zoom',\n });\n resetBtn.innerHTML = RESET_ICON;\n events.on(resetBtn, 'click', callbacks.onReset);\n\n wrapper.append(zoomInBtn, zoomOutBtn, resetBtn);\n return { element: wrapper, events };\n}\n","import { createElement } from '../utils/dom';\n\nexport class ScrollHint {\n private el: HTMLElement;\n private timeout: ReturnType<typeof setTimeout> | null = null;\n\n constructor(container: HTMLElement) {\n this.el = createElement('div', 'ci-before-after-scroll-hint', {\n 'aria-hidden': 'true',\n });\n\n const isMac = typeof navigator !== 'undefined' && /Mac|iPhone|iPad|iPod/.test(navigator.userAgent);\n this.el.textContent = isMac\n ? '\\u2318 + scroll or pinch to zoom'\n : 'Ctrl + scroll or pinch to zoom';\n\n container.appendChild(this.el);\n }\n\n show(): void {\n if (this.timeout) clearTimeout(this.timeout);\n\n this.el.classList.add('ci-before-after-scroll-hint--visible');\n\n this.timeout = setTimeout(() => {\n this.el.classList.remove('ci-before-after-scroll-hint--visible');\n this.timeout = null;\n }, 1500);\n }\n\n destroy(): void {\n if (this.timeout) clearTimeout(this.timeout);\n this.el.remove();\n }\n}\n","import type { LabelPosition, Orientation } from '../core/types';\nimport { createElement } from '../utils/dom';\n\nexport function createLabels(\n beforeText: string,\n afterText: string,\n position: LabelPosition,\n orientation: Orientation,\n): { before: HTMLElement; after: HTMLElement } {\n const posClass = `ci-before-after-label--${position}`;\n\n const beforeLabel = createElement('div',\n `ci-before-after-label ci-before-after-label-before ${posClass}`,\n { 'aria-hidden': 'true' },\n );\n beforeLabel.textContent = beforeText;\n\n const afterLabel = createElement('div',\n `ci-before-after-label ci-before-after-label-after ${posClass}`,\n { 'aria-hidden': 'true' },\n );\n afterLabel.textContent = afterText;\n\n return { before: beforeLabel, after: afterLabel };\n}\n\nexport function updateLabelVisibility(\n beforeLabel: HTMLElement | null,\n afterLabel: HTMLElement | null,\n position: number,\n orientation: Orientation,\n): void {\n if (!beforeLabel || !afterLabel) return;\n\n const fadeThreshold = 15;\n\n // Before label is near the left/top edge — fade when handle is close to 0%\n if (position < fadeThreshold) {\n beforeLabel.classList.add('ci-before-after-label--hidden');\n } else {\n beforeLabel.classList.remove('ci-before-after-label--hidden');\n }\n\n // After label is near the right/bottom edge — fade when handle is close to 100%\n if (position > 100 - fadeThreshold) {\n afterLabel.classList.add('ci-before-after-label--hidden');\n } else {\n afterLabel.classList.remove('ci-before-after-label--hidden');\n }\n}\n","import { createElement, supportsFullscreen, requestFullscreen, exitFullscreen, getFullscreenElement } from '../utils/dom';\nimport { EventManager } from '../utils/events';\n\nconst MAXIMIZE_ICON = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>';\nconst MINIMIZE_ICON = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"4 14 10 14 10 20\"/><polyline points=\"20 10 14 10 14 4\"/><line x1=\"14\" x2=\"21\" y1=\"10\" y2=\"3\"/><line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\"/></svg>';\n\nexport class FullscreenManager {\n private button: HTMLElement | null = null;\n private events = new EventManager();\n private isActive = false;\n\n constructor(\n private container: HTMLElement,\n private onFullscreenChange?: (isFullscreen: boolean) => void,\n ) {\n if (!supportsFullscreen()) return;\n this.createButton();\n this.bindEvents();\n }\n\n private createButton(): void {\n this.button = createElement('button', 'ci-before-after-fullscreen-btn', {\n type: 'button',\n 'aria-label': 'Enter fullscreen',\n 'aria-pressed': 'false',\n });\n this.button.innerHTML = MAXIMIZE_ICON;\n this.events.on(this.button, 'click', () => { this.toggle().catch(() => {}); });\n this.container.appendChild(this.button);\n }\n\n private bindEvents(): void {\n this.events.on(document as unknown as HTMLElement, 'fullscreenchange', () => this.handleChange());\n this.events.on(document as unknown as HTMLElement, 'webkitfullscreenchange' as keyof HTMLElementEventMap, () => this.handleChange());\n }\n\n private handleChange(): void {\n const fsElement = getFullscreenElement();\n const wasActive = this.isActive;\n this.isActive = fsElement === this.container;\n\n // Only fire callback and update UI when this instance's state actually changed\n if (wasActive === this.isActive) return;\n\n this.container.classList.toggle('ci-before-after-container--fullscreen', this.isActive);\n\n if (this.button) {\n this.button.innerHTML = this.isActive ? MINIMIZE_ICON : MAXIMIZE_ICON;\n this.button.setAttribute('aria-label', this.isActive ? 'Exit fullscreen' : 'Enter fullscreen');\n this.button.setAttribute('aria-pressed', String(this.isActive));\n }\n\n this.onFullscreenChange?.(this.isActive);\n }\n\n async enter(): Promise<void> {\n if (!supportsFullscreen()) return;\n await requestFullscreen(this.container);\n }\n\n async exit(): Promise<void> {\n if (!supportsFullscreen()) return;\n if (getFullscreenElement() === this.container) {\n await exitFullscreen();\n }\n }\n\n async toggle(): Promise<void> {\n if (this.isActive) {\n await this.exit();\n } else {\n await this.enter();\n }\n }\n\n getIsFullscreen(): boolean {\n return this.isActive;\n }\n\n destroy(): void {\n const wasActive = this.isActive;\n this.events.destroy();\n if (wasActive) {\n this.isActive = false;\n this.onFullscreenChange?.(false);\n exitFullscreen().catch(() => {});\n }\n this.container.classList.remove('ci-before-after-container--fullscreen');\n this.button?.remove();\n }\n}\n","export class EntranceAnimation {\n private observer: IntersectionObserver | null = null;\n private hasPlayed = false;\n private isAnimating = false;\n private delayTimer: ReturnType<typeof setTimeout> | null = null;\n private durationTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(\n private container: HTMLElement,\n private duration: number,\n private delay: number,\n private easing: string,\n private animateOnce: boolean,\n private onAnimate: (skipTransition: boolean) => void,\n ) {\n this.observe();\n }\n\n private observe(): void {\n if (typeof IntersectionObserver === 'undefined') return;\n\n this.observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n if (this.animateOnce && this.hasPlayed) continue;\n if (this.isAnimating) continue;\n this.play();\n }\n }\n },\n { threshold: 0.3 },\n );\n\n this.observer.observe(this.container);\n }\n\n private play(): void {\n this.hasPlayed = true;\n this.isAnimating = true;\n\n // Check for reduced motion preference\n if (typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches) {\n this.onAnimate(true);\n this.isAnimating = false;\n if (this.animateOnce) {\n this.observer?.disconnect();\n }\n return;\n }\n\n this.container.classList.add('ci-before-after-animate-entrance');\n this.container.style.setProperty('--ci-before-after-animate-duration', `${this.duration}ms`);\n this.container.style.setProperty('--ci-before-after-animate-easing', this.easing);\n\n this.delayTimer = setTimeout(() => {\n this.delayTimer = null;\n this.onAnimate(false);\n\n this.durationTimer = setTimeout(() => {\n this.durationTimer = null;\n this.container.classList.remove('ci-before-after-animate-entrance');\n this.isAnimating = false;\n if (this.animateOnce) {\n this.observer?.disconnect();\n }\n }, this.duration);\n }, this.delay);\n }\n\n getHasPlayed(): boolean {\n return this.hasPlayed;\n }\n\n destroy(): void {\n if (this.delayTimer) clearTimeout(this.delayTimer);\n if (this.durationTimer) clearTimeout(this.durationTimer);\n this.delayTimer = null;\n this.durationTimer = null;\n this.isAnimating = false;\n this.container.classList.remove('ci-before-after-animate-entrance');\n this.container.style.removeProperty('--ci-before-after-animate-duration');\n this.container.style.removeProperty('--ci-before-after-animate-easing');\n this.observer?.disconnect();\n this.observer = null;\n }\n}\n","import type { Orientation } from '../core/types';\nimport { EventManager } from '../utils/events';\n\nexport interface KeyboardCallbacks {\n onPositionChange: (position: number) => void;\n getPosition: () => number;\n onZoomIn?: () => void;\n onZoomOut?: () => void;\n onZoomReset?: () => void;\n}\n\nexport class KeyboardHandler {\n private events = new EventManager();\n\n constructor(\n private handle: HTMLElement,\n private orientation: Orientation,\n private step: number,\n private largeStep: number,\n private zoomEnabled: boolean,\n private callbacks: KeyboardCallbacks,\n ) {\n this.bind();\n }\n\n private bind(): void {\n this.events.on(this.handle, 'keydown', (e: KeyboardEvent) => {\n this.handleKeyDown(e);\n });\n }\n\n private handleKeyDown(e: KeyboardEvent): void {\n // Don't hijack browser shortcuts (Ctrl+Arrow = back/forward, Alt+Arrow = history)\n if (e.ctrlKey || e.altKey || e.metaKey) return;\n\n const current = this.callbacks.getPosition();\n const increment = e.shiftKey ? this.largeStep : this.step;\n let newPosition: number | null = null;\n\n if (this.orientation === 'horizontal') {\n switch (e.key) {\n case 'ArrowLeft':\n newPosition = current - increment;\n break;\n case 'ArrowRight':\n newPosition = current + increment;\n break;\n }\n } else {\n switch (e.key) {\n case 'ArrowUp':\n newPosition = current - increment;\n break;\n case 'ArrowDown':\n newPosition = current + increment;\n break;\n }\n }\n\n switch (e.key) {\n case 'Home':\n newPosition = 0;\n break;\n case 'End':\n newPosition = 100;\n break;\n }\n\n if (newPosition !== null) {\n e.preventDefault();\n newPosition = Math.max(0, Math.min(100, newPosition));\n this.callbacks.onPositionChange(newPosition);\n return;\n }\n\n // Zoom shortcuts\n if (this.zoomEnabled) {\n switch (e.key) {\n case '+':\n case '=':\n e.preventDefault();\n this.callbacks.onZoomIn?.();\n break;\n case '-':\n e.preventDefault();\n this.callbacks.onZoomOut?.();\n break;\n case '0':\n e.preventDefault();\n this.callbacks.onZoomReset?.();\n break;\n }\n }\n }\n\n updateConfig(orientation: Orientation, step: number, largeStep: number, zoomEnabled: boolean): void {\n this.orientation = orientation;\n this.step = step;\n this.largeStep = largeStep;\n this.zoomEnabled = zoomEnabled;\n }\n\n destroy(): void {\n this.events.destroy();\n }\n}\n","import type { Orientation } from '../core/types';\n\nexport function updateAriaValue(handle: HTMLElement, position: number): void {\n handle.setAttribute('aria-valuenow', String(Math.round(position)));\n}\n\nexport function updateAriaOrientation(handle: HTMLElement, orientation: Orientation): void {\n handle.setAttribute('aria-orientation', orientation);\n}\n\nexport function setContainerAria(container: HTMLElement): void {\n container.setAttribute('role', 'group');\n container.setAttribute('aria-label', 'Before and after image comparison');\n}\n","import type {\n CIBeforeAfterConfig,\n CIBeforeAfterInstance,\n CIBeforeAfterElements,\n ResolvedConfig,\n SliderState,\n} from './types';\nimport { resolveConfig } from './config';\nimport { createElement, resolveElement } from '../utils/dom';\nimport { EventManager } from '../utils/events';\nimport { buildCloudimageUrl } from '../utils/cloudimage';\nimport { updateClipPath, updateHandlePosition, clampPosition, type ClipZoomInfo } from '../slider/slider';\nimport { createHandle } from '../slider/handle';\nimport { SliderGestures } from '../slider/gestures';\nimport { ZoomPanController } from '../zoom/zoom-pan';\nimport { ZoomGestures } from '../zoom/gestures';\nimport { createZoomControls } from '../zoom/controls';\nimport { ScrollHint } from '../zoom/scroll-hint';\nimport { createLabels, updateLabelVisibility } from '../labels/labels';\nimport { FullscreenManager } from '../fullscreen/fullscreen';\nimport { EntranceAnimation } from '../animation/entrance';\nimport { KeyboardHandler } from '../a11y/keyboard';\nimport { updateAriaValue, setContainerAria } from '../a11y/aria';\n\nexport class CIBeforeAfterCore implements CIBeforeAfterInstance {\n private config: ResolvedConfig;\n private userConfig: CIBeforeAfterConfig;\n private state: SliderState;\n private elements!: CIBeforeAfterElements;\n private events = new EventManager();\n private imageEvents = new EventManager();\n private sliderGestures: SliderGestures | null = null;\n private zoomPan: ZoomPanController | null = null;\n private zoomGestures: ZoomGestures | null = null;\n private scrollHint: ScrollHint | null = null;\n private fullscreenManager: FullscreenManager | null = null;\n private entranceAnimation: EntranceAnimation | null = null;\n private keyboardHandler: KeyboardHandler | null = null;\n private resizeObserver: ResizeObserver | null = null;\n private zoomControlsEl: HTMLElement | null = null;\n private zoomControlsEvents: import('../utils/events').EventManager | null = null;\n private lazyLoadObserver: IntersectionObserver | null = null;\n private resizeDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n private animTransitionTimer: ReturnType<typeof setTimeout> | null = null;\n private suppressCallbacks = false;\n\n constructor(\n target: HTMLElement | string,\n userConfig: CIBeforeAfterConfig,\n ) {\n const container = resolveElement(target);\n this.userConfig = { ...userConfig };\n this.config = resolveConfig(userConfig);\n\n this.state = {\n position: this.config.initialPosition,\n isDragging: false,\n zoomLevel: 1,\n panX: 0,\n panY: 0,\n isReady: false,\n isFullscreen: false,\n };\n\n this.buildDOM(container);\n this.initModules();\n this.loadImages();\n }\n\n // --- Public API ---\n\n getElements() {\n return {\n container: this.elements.container,\n viewport: this.elements.viewport,\n beforeImage: this.elements.beforeImage,\n afterImage: this.elements.afterImage,\n handle: this.elements.handle,\n };\n }\n\n setPosition(percent: number): void {\n const clamped = clampPosition(percent);\n this.updatePosition(clamped);\n }\n\n getPosition(): number {\n return this.state.position;\n }\n\n setZoom(level: number): void {\n this.zoomPan?.setZoom(level);\n }\n\n getZoom(): number {\n return this.zoomPan?.getZoom() ?? 1;\n }\n\n resetZoom(): void {\n this.zoomPan?.resetZoom();\n }\n\n enterFullscreen(): void {\n this.fullscreenManager?.enter().catch(() => {});\n }\n\n exitFullscreen(): void {\n this.fullscreenManager?.exit().catch(() => {});\n }\n\n isFullscreen(): boolean {\n return this.fullscreenManager?.getIsFullscreen() ?? false;\n }\n\n update(newConfig: Partial<CIBeforeAfterConfig>): void {\n // BUG-01: Merge over stored user config, not just beforeSrc/afterSrc\n this.userConfig = { ...this.userConfig, ...newConfig };\n const oldConfig = this.config;\n this.config = resolveConfig(this.userConfig);\n\n // Update images if src changed — reset loading state and re-register handlers\n const beforeSrcChanged = this.config.beforeSrc !== oldConfig.beforeSrc;\n const afterSrcChanged = this.config.afterSrc !== oldConfig.afterSrc;\n\n // Detect cloudimage config changes\n const cloudimageChanged = !shallowEqual(this.config.cloudimage, oldConfig.cloudimage);\n\n if (beforeSrcChanged || afterSrcChanged || cloudimageChanged) {\n // Disconnect stale lazy-load observer that captured old src values\n if (this.lazyLoadObserver) {\n this.lazyLoadObserver.disconnect();\n this.lazyLoadObserver = null;\n }\n\n // Reset loading state for new images\n this.state.isReady = false;\n this.elements.container.classList.add('ci-before-after-loading');\n\n if (beforeSrcChanged || cloudimageChanged) {\n this.elements.beforeImage.src = this.resolveImageSrc(this.config.beforeSrc);\n }\n if (afterSrcChanged || cloudimageChanged) {\n this.elements.afterImage.src = this.resolveImageSrc(this.config.afterSrc);\n }\n\n this.registerImageLoadHandlers(beforeSrcChanged || cloudimageChanged, afterSrcChanged || cloudimageChanged);\n\n // Toggle ResizeObserver for cloudimage\n if (this.config.cloudimage && !oldConfig.cloudimage) {\n this.initResizeObserver();\n } else if (!this.config.cloudimage && oldConfig.cloudimage) {\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n }\n }\n\n // Update alt attributes\n if (this.config.beforeAlt !== oldConfig.beforeAlt) {\n this.elements.beforeImage.setAttribute('alt', this.config.beforeAlt);\n }\n if (this.config.afterAlt !== oldConfig.afterAlt) {\n this.elements.afterImage.setAttribute('alt', this.config.afterAlt);\n }\n\n // Update theme\n this.elements.container.classList.toggle('ci-before-after-theme-dark', this.config.theme === 'dark');\n\n // Update orientation classes\n this.elements.container.classList.toggle('ci-before-after-container--horizontal', this.config.orientation === 'horizontal');\n this.elements.container.classList.toggle('ci-before-after-container--vertical', this.config.orientation === 'vertical');\n\n // Update mode classes\n this.elements.container.classList.toggle('ci-before-after-container--hover-mode', this.config.mode === 'hover');\n this.elements.container.classList.toggle('ci-before-after-container--click-mode', this.config.mode === 'click');\n\n // Update zoom-related will-change class (QUAL-07)\n this.elements.viewport.classList.toggle('ci-before-after-viewport--zoomable', this.config.zoom);\n\n // Rebuild handle if style or orientation changed\n if (this.config.handleStyle !== oldConfig.handleStyle || this.config.orientation !== oldConfig.orientation) {\n this.rebuildHandle();\n }\n\n // Update slider gestures if mode or orientation changed (BUG-07)\n if (this.config.mode !== oldConfig.mode) {\n this.sliderGestures?.updateMode(this.config.mode);\n }\n if (this.config.orientation !== oldConfig.orientation) {\n this.sliderGestures?.updateOrientation(this.config.orientation);\n }\n\n // Update labels only when label config changed\n if (\n this.config.labelsEnabled !== oldConfig.labelsEnabled ||\n this.config.labelBefore !== oldConfig.labelBefore ||\n this.config.labelAfter !== oldConfig.labelAfter ||\n this.config.labelPosition !== oldConfig.labelPosition ||\n this.config.orientation !== oldConfig.orientation\n ) {\n this.rebuildLabels();\n }\n\n // Update zoom\n if (this.config.zoom !== oldConfig.zoom) {\n this.rebuildZoom();\n } else if (this.zoomPan) {\n this.zoomPan.updateConfig(this.config);\n\n // Handle scrollHint change independently of zoom toggle\n if (this.config.scrollHint !== oldConfig.scrollHint) {\n this.scrollHint?.destroy();\n this.scrollHint = null;\n if (this.config.scrollHint) {\n this.scrollHint = new ScrollHint(this.elements.container);\n }\n }\n\n // Handle zoomControls or zoomControlsPosition change\n if (\n this.config.zoomControls !== oldConfig.zoomControls ||\n this.config.zoomControlsPosition !== oldConfig.zoomControlsPosition\n ) {\n this.zoomControlsEvents?.destroy();\n this.zoomControlsEvents = null;\n this.zoomControlsEl?.remove();\n this.zoomControlsEl = null;\n this.elements.container.classList.remove('ci-before-after-container--zoom-top-right');\n this.elements.container.classList.remove('ci-before-after-container--zoom-top');\n this.elements.container.classList.remove('ci-before-after-container--zoom-left');\n\n if (this.config.zoomControls) {\n const controls = createZoomControls(\n this.config.zoomControlsPosition,\n {\n onZoomIn: () => this.zoomPan?.zoomIn(),\n onZoomOut: () => this.zoomPan?.zoomOut(),\n onReset: () => this.zoomPan?.resetZoom(),\n },\n );\n this.zoomControlsEl = controls.element;\n this.zoomControlsEvents = controls.events;\n this.elements.container.appendChild(this.zoomControlsEl);\n this.applyZoomPositionClasses();\n }\n }\n }\n\n // Update initial position\n if (this.config.initialPosition !== oldConfig.initialPosition) {\n this.updatePosition(this.config.initialPosition);\n }\n\n // Update fullscreen\n if (this.config.fullscreenButton !== oldConfig.fullscreenButton) {\n this.rebuildFullscreen();\n }\n\n // Update entrance animation\n if (this.config.animateEnabled !== oldConfig.animateEnabled) {\n this.entranceAnimation?.destroy();\n this.entranceAnimation = null;\n if (this.config.animateEnabled) {\n this.initEntranceAnimation();\n }\n }\n\n // Update keyboard handler\n this.keyboardHandler?.updateConfig(\n this.config.orientation,\n this.config.keyboardStep,\n this.config.keyboardLargeStep,\n this.config.zoom,\n );\n\n // Update position\n this.updatePosition(this.state.position);\n }\n\n destroy(): void {\n this.sliderGestures?.destroy();\n this.zoomGestures?.destroy();\n this.zoomPan?.destroy();\n this.zoomPan = null;\n this.scrollHint?.destroy();\n this.fullscreenManager?.destroy();\n this.entranceAnimation?.destroy();\n this.keyboardHandler?.destroy();\n this.events.destroy();\n this.imageEvents.destroy();\n this.resizeObserver?.disconnect();\n this.lazyLoadObserver?.disconnect();\n this.lazyLoadObserver = null;\n this.zoomControlsEvents?.destroy();\n this.zoomControlsEvents = null;\n this.zoomControlsEl?.remove();\n if (this.resizeDebounceTimer) clearTimeout(this.resizeDebounceTimer);\n if (this.animTransitionTimer) clearTimeout(this.animTransitionTimer);\n\n // SEC-03: Clear container instead of restoring unsanitized HTML\n this.elements.container.innerHTML = '';\n this.elements.container.removeAttribute('role');\n this.elements.container.removeAttribute('aria-label');\n this.elements.container.className = this.elements.container.className\n .split(' ')\n .filter((c) => !c.startsWith('ci-before-after'))\n .join(' ');\n }\n\n // --- Private Methods ---\n\n private buildDOM(container: HTMLElement): void {\n container.innerHTML = '';\n\n // Container setup\n const orientClass = `ci-before-after-container--${this.config.orientation}`;\n container.classList.add('ci-before-after-container', orientClass);\n\n if (this.config.mode === 'hover') container.classList.add('ci-before-after-container--hover-mode');\n if (this.config.mode === 'click') container.classList.add('ci-before-after-container--click-mode');\n if (this.config.theme === 'dark') container.classList.add('ci-before-after-theme-dark');\n\n container.classList.add('ci-before-after-loading');\n\n setContainerAria(container);\n\n // Viewport (receives zoom/pan transforms)\n const viewport = createElement('div', 'ci-before-after-viewport');\n // QUAL-07: Only set will-change when zoom is enabled\n if (this.config.zoom) viewport.classList.add('ci-before-after-viewport--zoomable');\n\n // Wrapper (contains images)\n const wrapper = createElement('div', 'ci-before-after-wrapper');\n\n // Before image (SPEC-01: add role=\"img\")\n const beforeImage = createElement('img', 'ci-before-after-image ci-before-after-before', {\n alt: this.config.beforeAlt,\n draggable: 'false',\n role: 'img',\n });\n\n // Clip wrapper for after image\n const clip = createElement('div', 'ci-before-after-clip');\n updateClipPath(clip, this.state.position, this.config.orientation);\n\n // After image (SPEC-01: add role=\"img\")\n const afterImage = createElement('img', 'ci-before-after-image ci-before-after-after', {\n alt: this.config.afterAlt,\n draggable: 'false',\n role: 'img',\n });\n\n clip.appendChild(afterImage);\n wrapper.append(beforeImage, clip);\n viewport.appendChild(wrapper);\n container.appendChild(viewport);\n\n // Handle (outside viewport for fixed positioning during zoom)\n const handle = createHandle(this.config.handleStyle, this.config.orientation, this.state.position);\n container.appendChild(handle);\n\n const handleGrip = handle.querySelector('.ci-before-after-handle-grip') as HTMLElement;\n\n // Labels\n let labelBefore: HTMLElement | null = null;\n let labelAfter: HTMLElement | null = null;\n\n if (this.config.labelsEnabled) {\n const labels = createLabels(\n this.config.labelBefore,\n this.config.labelAfter,\n this.config.labelPosition,\n this.config.orientation,\n );\n labelBefore = labels.before;\n labelAfter = labels.after;\n container.append(labelBefore, labelAfter);\n }\n\n this.elements = {\n container,\n viewport,\n wrapper,\n beforeImage,\n afterImage,\n clip,\n handle,\n handleGrip,\n labelBefore,\n labelAfter,\n };\n }\n\n private initModules(): void {\n // Slider gestures\n this.sliderGestures = new SliderGestures(\n this.elements.container,\n this.elements.handle,\n this.config.mode,\n this.config.orientation,\n {\n onPositionChange: (pos) => this.updatePosition(pos),\n onDragStart: () => this.onDragStart(),\n onDragEnd: () => this.onDragEnd(),\n },\n );\n\n // Keyboard navigation\n this.keyboardHandler = new KeyboardHandler(\n this.elements.handle,\n this.config.orientation,\n this.config.keyboardStep,\n this.config.keyboardLargeStep,\n this.config.zoom,\n {\n onPositionChange: (pos) => this.updatePosition(pos),\n getPosition: () => this.state.position,\n onZoomIn: () => this.zoomPan?.zoomIn(),\n onZoomOut: () => this.zoomPan?.zoomOut(),\n onZoomReset: () => this.zoomPan?.resetZoom(),\n },\n );\n\n // Zoom\n if (this.config.zoom) {\n this.initZoom();\n }\n\n // Fullscreen\n if (this.config.fullscreenButton) {\n this.elements.container.classList.add('ci-before-after-container--has-fullscreen');\n this.fullscreenManager = new FullscreenManager(\n this.elements.container,\n (isFullscreen) => {\n this.state.isFullscreen = isFullscreen;\n safeCall(this.config.onFullscreenChange, isFullscreen);\n },\n );\n }\n\n // Entrance animation\n if (this.config.animateEnabled) {\n this.initEntranceAnimation();\n }\n\n // ResizeObserver for cloudimage (QUAL-06: debounced)\n if (this.config.cloudimage) {\n this.initResizeObserver();\n }\n }\n\n private initZoom(): void {\n this.zoomPan = new ZoomPanController(\n this.elements.viewport,\n this.elements.container,\n this.config,\n (level) => {\n this.state.zoomLevel = level;\n this.syncClip();\n safeCall(this.config.onZoom, level);\n },\n () => this.syncClip(),\n );\n\n // Scroll hint\n if (this.config.scrollHint) {\n this.scrollHint = new ScrollHint(this.elements.container);\n }\n\n // Zoom gestures\n this.zoomGestures = new ZoomGestures(\n this.elements.container,\n this.elements.handle,\n this.zoomPan,\n () => this.scrollHint?.show(),\n );\n\n // Zoom controls\n if (this.config.zoomControls) {\n const controls = createZoomControls(\n this.config.zoomControlsPosition,\n {\n onZoomIn: () => this.zoomPan?.zoomIn(),\n onZoomOut: () => this.zoomPan?.zoomOut(),\n onReset: () => this.zoomPan?.resetZoom(),\n },\n );\n this.zoomControlsEl = controls.element;\n this.zoomControlsEvents = controls.events;\n this.elements.container.appendChild(this.zoomControlsEl);\n\n this.applyZoomPositionClasses();\n }\n }\n\n private applyZoomPositionClasses(): void {\n const pos = this.config.zoomControlsPosition;\n this.elements.container.classList.toggle('ci-before-after-container--zoom-top-right', pos === 'top-right');\n this.elements.container.classList.toggle('ci-before-after-container--zoom-top', pos.startsWith('top-'));\n this.elements.container.classList.toggle('ci-before-after-container--zoom-left', pos.endsWith('-left'));\n }\n\n private initEntranceAnimation(): void {\n // Clear any pending animation transition timer from a previous animation\n if (this.animTransitionTimer) {\n clearTimeout(this.animTransitionTimer);\n this.animTransitionTimer = null;\n this.elements.handle.style.transition = '';\n this.elements.clip.style.transition = '';\n }\n\n // Set initial position to edge for animation\n const startPosition = 0;\n this.suppressCallbacks = true;\n this.updatePosition(startPosition);\n this.suppressCallbacks = false;\n\n this.entranceAnimation = new EntranceAnimation(\n this.elements.container,\n this.config.animateDuration,\n this.config.animateDelay,\n this.config.animateEasing,\n this.config.animateOnce,\n (skipTransition: boolean) => {\n if (!skipTransition) {\n // Animate to initial position with CSS transitions\n this.elements.handle.style.transition =\n `left ${this.config.animateDuration}ms ${this.config.animateEasing}, top ${this.config.animateDuration}ms ${this.config.animateEasing}`;\n this.elements.clip.style.transition =\n `clip-path ${this.config.animateDuration}ms ${this.config.animateEasing}`;\n }\n\n this.updatePosition(this.config.initialPosition);\n\n if (!skipTransition) {\n this.animTransitionTimer = setTimeout(() => {\n this.animTransitionTimer = null;\n this.elements.handle.style.transition = '';\n this.elements.clip.style.transition = '';\n }, this.config.animateDuration);\n }\n },\n );\n }\n\n private loadImages(): void {\n const beforeSrc = this.resolveImageSrc(this.config.beforeSrc);\n const afterSrc = this.resolveImageSrc(this.config.afterSrc);\n\n if (this.config.lazyLoad && typeof IntersectionObserver !== 'undefined') {\n // BUG-06: Store observer for cleanup in destroy()\n this.lazyLoadObserver = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n this.elements.beforeImage.src = beforeSrc;\n this.elements.afterImage.src = afterSrc;\n this.lazyLoadObserver?.disconnect();\n this.lazyLoadObserver = null;\n }\n }\n },\n { threshold: 0 },\n );\n this.lazyLoadObserver.observe(this.elements.container);\n } else {\n this.elements.beforeImage.src = beforeSrc;\n this.elements.afterImage.src = afterSrc;\n }\n\n this.registerImageLoadHandlers(true, true);\n }\n\n /**\n * Register load/error handlers for images. Cleans up previous handlers first.\n * When only one image changed, the unchanged image is treated as already loaded.\n */\n private registerImageLoadHandlers(beforeChanged: boolean, afterChanged: boolean): void {\n // Clean up previous image event handlers\n this.imageEvents.destroy();\n\n let beforeLoaded = !beforeChanged;\n let afterLoaded = !afterChanged;\n\n const checkReady = () => {\n if (beforeLoaded && afterLoaded) {\n this.onImagesReady();\n }\n };\n\n const onBeforeLoad = () => {\n if (!beforeLoaded) {\n beforeLoaded = true;\n checkReady();\n }\n };\n const onAfterLoad = () => {\n if (!afterLoaded) {\n afterLoaded = true;\n checkReady();\n }\n };\n\n const onBeforeError = () => {\n console.warn(`CIBeforeAfter: Failed to load image \"${this.elements.beforeImage.src}\"`);\n if (!beforeLoaded) {\n beforeLoaded = true;\n checkReady();\n }\n };\n const onAfterError = () => {\n console.warn(`CIBeforeAfter: Failed to load image \"${this.elements.afterImage.src}\"`);\n if (!afterLoaded) {\n afterLoaded = true;\n checkReady();\n }\n };\n\n this.imageEvents.on(this.elements.beforeImage, 'load', onBeforeLoad);\n this.imageEvents.on(this.elements.afterImage, 'load', onAfterLoad);\n this.imageEvents.on(this.elements.beforeImage, 'error', onBeforeError);\n this.imageEvents.on(this.elements.afterImage, 'error', onAfterError);\n\n // Handle already cached images\n if (this.elements.beforeImage.complete && this.elements.beforeImage.src) onBeforeLoad();\n if (this.elements.afterImage.complete && this.elements.afterImage.src) onAfterLoad();\n }\n\n private onImagesReady(): void {\n if (this.state.isReady) return;\n this.state.isReady = true;\n\n // Set aspect ratio from before image\n const { naturalWidth, naturalHeight } = this.elements.beforeImage;\n if (naturalWidth && naturalHeight) {\n this.elements.wrapper.style.aspectRatio = `${naturalWidth} / ${naturalHeight}`;\n }\n\n this.elements.container.classList.remove('ci-before-after-loading');\n safeCall(this.config.onReady);\n }\n\n private getClipZoomInfo(): ClipZoomInfo | undefined {\n if (!this.zoomPan || this.zoomPan.getZoom() <= 1) return undefined;\n const pan = this.zoomPan.getPan();\n const size = this.zoomPan.getContainerSize();\n return {\n level: this.zoomPan.getZoom(),\n panX: pan.x,\n panY: pan.y,\n containerWidth: size.width,\n containerHeight: size.height,\n };\n }\n\n private syncClip(): void {\n updateClipPath(this.elements.clip, this.state.position, this.config.orientation, this.getClipZoomInfo());\n }\n\n private updatePosition(position: number): void {\n this.state.position = clampPosition(position);\n updateClipPath(this.elements.clip, this.state.position, this.config.orientation, this.getClipZoomInfo());\n updateHandlePosition(this.elements.handle, this.state.position, this.config.orientation);\n updateAriaValue(this.elements.handle, this.state.position);\n updateLabelVisibility(\n this.elements.labelBefore,\n this.elements.labelAfter,\n this.state.position,\n this.config.orientation,\n );\n // BUG-10: Only fire callback when not suppressed (e.g. during init/animation setup)\n if (!this.suppressCallbacks) {\n safeCall(this.config.onSlide, this.state.position);\n }\n }\n\n private onDragStart(): void {\n this.state.isDragging = true;\n this.elements.container.classList.add('ci-before-after-container--dragging');\n }\n\n private onDragEnd(): void {\n this.state.isDragging = false;\n this.elements.container.classList.remove('ci-before-after-container--dragging');\n }\n\n private resolveImageSrc(src: string): string {\n if (this.config.cloudimage) {\n const width = this.elements.container.getBoundingClientRect().width || 800;\n return buildCloudimageUrl(src, width, this.config.cloudimage);\n }\n return src;\n }\n\n private rebuildHandle(): void {\n const hadFocus = document.activeElement === this.elements.handle;\n this.elements.handle.remove();\n const handle = createHandle(this.config.handleStyle, this.config.orientation, this.state.position);\n this.elements.container.appendChild(handle);\n this.elements.handle = handle;\n this.elements.handleGrip = handle.querySelector('.ci-before-after-handle-grip') as HTMLElement;\n\n // Rebind modules that depend on handle\n this.sliderGestures?.destroy();\n this.sliderGestures = new SliderGestures(\n this.elements.container,\n this.elements.handle,\n this.config.mode,\n this.config.orientation,\n {\n onPositionChange: (pos) => this.updatePosition(pos),\n onDragStart: () => this.onDragStart(),\n onDragEnd: () => this.onDragEnd(),\n },\n );\n\n this.keyboardHandler?.destroy();\n this.keyboardHandler = new KeyboardHandler(\n this.elements.handle,\n this.config.orientation,\n this.config.keyboardStep,\n this.config.keyboardLargeStep,\n this.config.zoom,\n {\n onPositionChange: (pos) => this.updatePosition(pos),\n getPosition: () => this.state.position,\n onZoomIn: () => this.zoomPan?.zoomIn(),\n onZoomOut: () => this.zoomPan?.zoomOut(),\n onZoomReset: () => this.zoomPan?.resetZoom(),\n },\n );\n\n if (this.zoomGestures && this.zoomPan) {\n this.zoomGestures.destroy();\n this.zoomGestures = new ZoomGestures(\n this.elements.container,\n this.elements.handle,\n this.zoomPan,\n () => this.scrollHint?.show(),\n );\n }\n\n // Restore keyboard focus if it was on the old handle\n if (hadFocus) {\n this.elements.handle.focus();\n }\n }\n\n private rebuildLabels(): void {\n this.elements.labelBefore?.remove();\n this.elements.labelAfter?.remove();\n this.elements.labelBefore = null;\n this.elements.labelAfter = null;\n\n if (this.config.labelsEnabled) {\n const labels = createLabels(\n this.config.labelBefore,\n this.config.labelAfter,\n this.config.labelPosition,\n this.config.orientation,\n );\n this.elements.labelBefore = labels.before;\n this.elements.labelAfter = labels.after;\n this.elements.container.append(labels.before, labels.after);\n updateLabelVisibility(labels.before, labels.after, this.state.position, this.config.orientation);\n }\n }\n\n private rebuildZoom(): void {\n this.zoomGestures?.destroy();\n this.zoomGestures = null;\n this.scrollHint?.destroy();\n this.scrollHint = null;\n this.zoomControlsEvents?.destroy();\n this.zoomControlsEvents = null;\n this.zoomControlsEl?.remove();\n this.zoomControlsEl = null;\n this.zoomPan?.destroy();\n this.zoomPan = null;\n this.elements.container.classList.remove('ci-before-after-container--zoom-top-right');\n this.elements.container.classList.remove('ci-before-after-container--zoom-top');\n this.elements.container.classList.remove('ci-before-after-container--zoom-left');\n\n if (this.config.zoom) {\n this.initZoom();\n }\n }\n\n private rebuildFullscreen(): void {\n this.fullscreenManager?.destroy();\n this.fullscreenManager = null;\n this.elements.container.classList.remove('ci-before-after-container--has-fullscreen');\n\n if (this.config.fullscreenButton) {\n this.elements.container.classList.add('ci-before-after-container--has-fullscreen');\n this.fullscreenManager = new FullscreenManager(\n this.elements.container,\n (isFullscreen) => {\n this.state.isFullscreen = isFullscreen;\n safeCall(this.config.onFullscreenChange, isFullscreen);\n },\n );\n }\n }\n\n private initResizeObserver(): void {\n if (typeof ResizeObserver === 'undefined') return;\n\n this.resizeObserver = new ResizeObserver(() => {\n // QUAL-06: Debounce cloudimage resize requests\n if (this.resizeDebounceTimer) clearTimeout(this.resizeDebounceTimer);\n this.resizeDebounceTimer = setTimeout(() => {\n if (this.config.cloudimage) {\n const newBeforeSrc = this.resolveImageSrc(this.config.beforeSrc);\n const newAfterSrc = this.resolveImageSrc(this.config.afterSrc);\n // Only set src when URL actually changed to avoid unnecessary network requests\n if (this.elements.beforeImage.src !== newBeforeSrc) {\n this.elements.beforeImage.src = newBeforeSrc;\n }\n if (this.elements.afterImage.src !== newAfterSrc) {\n this.elements.afterImage.src = newAfterSrc;\n }\n }\n this.resizeDebounceTimer = null;\n }, 200);\n });\n\n this.resizeObserver.observe(this.elements.container);\n }\n}\n\nfunction safeCall<T extends unknown[]>(fn: ((...args: T) => void) | undefined, ...args: T): void {\n if (!fn) return;\n try {\n fn(...args);\n } catch (err) {\n console.error('CIBeforeAfter: callback error:', err);\n }\n}\n\nfunction shallowEqual<T extends object>(a: T | undefined, b: T | undefined): boolean {\n if (a === b) return true;\n if (!a || !b) return false;\n const keysA = Object.keys(a) as (keyof T)[];\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n for (const key of keysA) {\n if (a[key] !== b[key]) return false;\n }\n return true;\n}\n","import { CIBeforeAfterCore } from './core/ci-before-after';\nimport { parseDataAttributes } from './core/config';\nimport { isBrowser, injectStyles } from './utils/dom';\nimport type { CIBeforeAfterConfig, CIBeforeAfterInstance } from './core/types';\nimport cssText from './styles/index.css?inline';\n\nexport type {\n CIBeforeAfterConfig,\n CIBeforeAfterInstance,\n InteractionMode,\n Orientation,\n HandleStyle,\n Theme,\n LabelPosition,\n ZoomControlsPosition,\n AnimateConfig,\n CloudimageConfig,\n SliderState,\n} from './core/types';\n\n// QUAL-01: Export CIBeforeAfterCore for React wrapper\nexport { CIBeforeAfterCore };\n\nclass CIBeforeAfter extends CIBeforeAfterCore {\n static autoInit(root?: HTMLElement): CIBeforeAfterInstance[] {\n if (!isBrowser()) return [];\n injectStyles(cssText);\n\n const parent = root || document;\n const elements = parent.querySelectorAll<HTMLElement>('[data-ci-before-after-before-src]');\n const instances: CIBeforeAfterInstance[] = [];\n\n elements.forEach((el) => {\n const config = parseDataAttributes(el);\n instances.push(new CIBeforeAfter(el, config));\n });\n\n return instances;\n }\n\n constructor(target: HTMLElement | string, config: CIBeforeAfterConfig) {\n injectStyles(cssText);\n super(target, config);\n }\n}\n\nexport default CIBeforeAfter;\nexport { CIBeforeAfter };\n"],"names":["VALID_MODES","VALID_ORIENTATIONS","VALID_THEMES","VALID_HANDLE_STYLES","VALID_LABEL_POSITIONS","VALID_ZOOM_POSITIONS","DEFAULTS","resolveConfig","config","labels","labelsEnabled","labelBefore","labelAfter","animate","animateEnabled","animateDuration","animateDelay","animateEasing","zoom","validateEnumWithDefault","clampPosition","validateEnum","value","allowed","name","defaultValue","parseDataAttributes","el","get","getBool","val","getNum","n","beforeSrc","afterSrc","beforeAlt","afterAlt","mode","orientation","initialPosition","zoomMax","zoomMin","theme","handleStyle","labelsAttr","labelPosition","animateAttr","animateOnce","fullscreenButton","lazyLoad","zoomControls","zoomControlsPosition","scrollHint","keyboardStep","keyboardLargeStep","ciToken","STYLE_ID","injectStyles","css","isBrowser","style","createElement","tag","className","attrs","key","resolveElement","target","supportsFullscreen","doc","requestFullscreen","elem","exitFullscreen","getFullscreenElement","EventManager","event","handler","options","cleanup","getPointerPosition","e","rect","clientX","clientY","touch","_a","getPositionPercent","x","y","dimension","TOKEN_PATTERN","DOMAIN_PATTERN","API_VERSION_PATTERN","validateCloudimageConfig","buildCloudimageUrl","src","containerWidth","token","apiVersion","domain","limitFactor","params","devicePixelRatioList","dpr","closestDpr","prev","curr","safeLimitFactor","rawWidth","roundedWidth","baseUrl","paramStr","updateClipPath","clipEl","position","adjusted","updateHandlePosition","handleEl","CHEVRON_LEFT","CHEVRON_RIGHT","CHEVRON_UP","CHEVRON_DOWN","MOVE_HORIZONTAL","MOVE_VERTICAL","createHandle","handle","buildArrowsHandle","buildCircleHandle","buildLineHandle","line1","grip","line2","SliderGestures","container","callbacks","signal","onMouseMove","onMouseUp","onTouchMove","onTouchEnd","ZoomPanController","viewport","onZoomChange","onTransformChange","entries","entry","width","height","level","centerX","centerY","clamped","oldZoom","dx","dy","delta","resetLevel","maxPanX","maxPanY","onEnd","PAN_THRESHOLD","ZoomGestures","zoomPan","scrollHintCallback","ge","startX","startY","totalDx","totalDy","t1","t2","scale","PLUS_ICON","MINUS_ICON","RESET_ICON","createZoomControls","events","wrapper","zoomInBtn","zoomOutBtn","resetBtn","ScrollHint","isMac","createLabels","beforeText","afterText","posClass","beforeLabel","afterLabel","updateLabelVisibility","fadeThreshold","MAXIMIZE_ICON","MINIMIZE_ICON","FullscreenManager","onFullscreenChange","fsElement","wasActive","_b","EntranceAnimation","duration","delay","easing","onAnimate","KeyboardHandler","step","largeStep","zoomEnabled","current","increment","newPosition","_d","_c","_f","_e","updateAriaValue","setContainerAria","CIBeforeAfterCore","userConfig","percent","newConfig","oldConfig","beforeSrcChanged","afterSrcChanged","cloudimageChanged","shallowEqual","controls","_g","_h","_i","_j","_k","c","orientClass","beforeImage","clip","afterImage","handleGrip","pos","isFullscreen","safeCall","startPosition","skipTransition","beforeChanged","afterChanged","beforeLoaded","afterLoaded","checkReady","onBeforeLoad","onAfterLoad","onBeforeError","onAfterError","naturalWidth","naturalHeight","pan","size","hadFocus","newBeforeSrc","newAfterSrc","fn","args","err","a","b","keysA","keysB","CIBeforeAfter","root","cssText","elements","instances"],"mappings":"sOAWA,MAAMA,EAAiC,CAAC,OAAQ,QAAS,OAAO,EAC1DC,EAAoC,CAAC,aAAc,UAAU,EAC7DC,EAAwB,CAAC,QAAS,MAAM,EACxCC,EAAqC,CAAC,SAAU,SAAU,MAAM,EAChEC,EAAyC,CAAC,MAAO,QAAQ,EACzDC,EAA+C,CACnD,WAAY,aAAc,YAC1B,cAAe,gBAAiB,cAClC,EAEMC,EAA2D,CAC/D,UAAW,SACX,SAAU,QACV,KAAM,OACN,YAAa,aACb,gBAAiB,GACjB,KAAM,GACN,QAAS,EACT,QAAS,EACT,MAAO,QACP,YAAa,SAIb,cAAe,MAKf,YAAa,GACb,iBAAkB,GAClB,SAAU,GACV,aAAc,GACd,qBAAsB,eACtB,WAAY,GACZ,aAAc,EACd,kBAAmB,EACrB,EAEO,SAASC,EAAcC,EAA6C,CACzE,MAAMC,EAASD,EAAO,OACtB,IAAIE,EAAgB,GAChBC,EAAc,SACdC,EAAa,QAEbH,IAAW,GACbC,EAAgB,GACP,OAAOD,GAAW,WAC3BE,EAAcF,EAAO,QAAU,SAC/BG,EAAaH,EAAO,OAAS,SAG/B,MAAMI,EAAUL,EAAO,QACvB,IAAIM,EAAiB,GACjBC,EAAkB,IAClBC,EAAe,EACfC,EAAgB,WAEhBJ,IAAY,GACdC,EAAiB,GACR,OAAOD,GAAY,WAC5BC,EAAiB,GACjBC,EAAkB,KAAK,IAAI,EAAGF,EAAQ,UAAY,GAAG,EACrDG,EAAe,KAAK,IAAI,EAAGH,EAAQ,OAAS,CAAC,EAC7CI,EAAgBJ,EAAQ,QAAU,YAGpC,MAAMK,EAAOV,EAAO,MAAQF,EAAS,KAErC,MAAO,CACL,UAAWE,EAAO,UAClB,SAAUA,EAAO,SACjB,UAAWA,EAAO,WAAaF,EAAS,UACxC,SAAUE,EAAO,UAAYF,EAAS,SACtC,KAAMa,EAAwBX,EAAO,KAAMR,EAAaM,EAAS,KAAM,MAAM,EAC7E,YAAaa,EAAwBX,EAAO,YAAaP,EAAoBK,EAAS,YAAa,aAAa,EAChH,gBAAiBc,GAAcZ,EAAO,iBAAmBF,EAAS,eAAe,EACjF,KAAAY,EACA,QAAS,KAAK,IAAI,EAAGV,EAAO,SAAWF,EAAS,OAAO,EACvD,QAAS,KAAK,IAAI,EAAG,KAAK,IAAIE,EAAO,SAAWF,EAAS,QAASE,EAAO,SAAWF,EAAS,OAAO,CAAC,EACrG,MAAOa,EAAwBX,EAAO,MAAON,EAAcI,EAAS,MAAO,OAAO,EAClF,YAAaa,EAAwBX,EAAO,YAAaL,EAAqBG,EAAS,YAAa,aAAa,EACjH,cAAAI,EACA,YAAAC,EACA,WAAAC,EACA,cAAeO,EAAwBX,EAAO,cAAeJ,EAAuBE,EAAS,cAAe,eAAe,EAC3H,eAAAQ,EACA,gBAAAC,EACA,aAAAC,EACA,cAAAC,EACA,YAAaT,EAAO,aAAeF,EAAS,YAC5C,iBAAkBE,EAAO,kBAAoBF,EAAS,iBACtD,SAAUE,EAAO,UAAYF,EAAS,SACtC,aAAcE,EAAO,eAAiBU,EAAOZ,EAAS,aAAe,IACrE,qBAAsBa,EAAwBX,EAAO,qBAAsBH,EAAsBC,EAAS,qBAAsB,sBAAsB,EACtJ,WAAYE,EAAO,aAAeU,EAAOZ,EAAS,WAAa,IAC/D,aAAc,KAAK,IAAI,GAAKE,EAAO,cAAgBF,EAAS,YAAY,EACxE,kBAAmB,KAAK,IAAI,EAAGE,EAAO,mBAAqBF,EAAS,iBAAiB,EACrF,QAASE,EAAO,QAChB,OAAQA,EAAO,OACf,mBAAoBA,EAAO,mBAC3B,QAASA,EAAO,QAChB,WAAYA,EAAO,UAAA,CAEvB,CAEA,SAASa,EAA+BC,EAAeC,EAAcC,EAA6B,CAChG,GAAKD,EAAqB,SAASD,CAAK,EAAG,OAAOA,EAClD,QAAQ,KAAK,0BAA0BE,CAAI,KAAKF,CAAK,eAAeC,EAAQ,KAAK,IAAI,CAAC,EAAE,CAE1F,CAEA,SAASJ,EAA0CG,EAAsBC,EAAcE,EAAiBD,EAAiB,CACvH,OAAIF,IAAU,OAAkBG,EAC3BF,EAAqB,SAASD,CAAK,EAAUA,GAClD,QAAQ,KAAK,0BAA0BE,CAAI,KAAKF,CAAK,eAAeC,EAAQ,KAAK,IAAI,CAAC,oBAAoBE,CAAY,IAAI,EACnHA,EACT,CAEO,SAASC,GAAoBC,EAAsC,CACxE,MAAMC,EAAOJ,GAAgCG,EAAG,aAAa,wBAAwBH,CAAI,EAAE,EACrFK,EAAWL,GAAsC,CACrD,MAAMM,EAAMF,EAAIJ,CAAI,EACpB,GAAIM,IAAQ,KACZ,OAAOA,IAAQ,MACjB,EACMC,EAAUP,GAAqC,CACnD,MAAMM,EAAMF,EAAIJ,CAAI,EACpB,GAAIM,IAAQ,KAAM,OAClB,MAAME,GAAI,WAAWF,CAAG,EACxB,OAAO,MAAME,EAAC,EAAI,OAAYA,EAChC,EAEMC,EAAYL,EAAI,YAAY,EAC5BM,EAAWN,EAAI,WAAW,EAEhC,GAAI,CAACK,GAAa,CAACC,EACjB,MAAM,IAAI,MAAM,gGAAgG,EAGlH,MAAM1B,EAA8B,CAClC,UAAAyB,EACA,SAAAC,CAAA,EAGIC,EAAYP,EAAI,YAAY,EAC9BO,IAAc,OAAM3B,EAAO,UAAY2B,GAE3C,MAAMC,EAAWR,EAAI,WAAW,EAC5BQ,IAAa,OAAM5B,EAAO,SAAW4B,GAEzC,MAAMC,EAAOT,EAAI,MAAM,EACnBS,IAAM7B,EAAO,KAAOa,EAAagB,EAAMrC,EAAa,MAAM,GAE9D,MAAMsC,EAAcV,EAAI,aAAa,EACjCU,IAAa9B,EAAO,YAAca,EAAaiB,EAAarC,EAAoB,aAAa,GAEjG,MAAMsC,EAAkBR,EAAO,kBAAkB,EAC7CQ,IAAoB,SAAW/B,EAAO,gBAAkB+B,GAE5D,MAAMrB,EAAOW,EAAQ,MAAM,EACvBX,IAAS,SAAWV,EAAO,KAAOU,GAEtC,MAAMsB,EAAUT,EAAO,UAAU,EAC7BS,IAAY,SAAWhC,EAAO,QAAUgC,GAE5C,MAAMC,EAAUV,EAAO,UAAU,EAC7BU,IAAY,SAAWjC,EAAO,QAAUiC,GAE5C,MAAMC,EAAQd,EAAI,OAAO,EACrBc,IAAOlC,EAAO,MAAQa,EAAaqB,EAAOxC,EAAc,OAAO,GAEnE,MAAMyC,EAAcf,EAAI,cAAc,EAClCe,IAAanC,EAAO,YAAca,EAAasB,EAAaxC,EAAqB,aAAa,GAElG,MAAMyC,EAAaf,EAAQ,QAAQ,EAC7BlB,EAAciB,EAAI,cAAc,EAChChB,GAAagB,EAAI,aAAa,EAEhCgB,IAAe,GACjBpC,EAAO,OAAS,GACPG,IAAgB,MAAQC,KAAe,KAChDJ,EAAO,OAAS,CACd,OAAQG,GAAe,OACvB,MAAOC,IAAc,MAAA,EAEdgC,IAAe,KACxBpC,EAAO,OAAS,IAGlB,MAAMqC,GAAgBjB,EAAI,gBAAgB,EACtCiB,KAAerC,EAAO,cAAgBa,EAAawB,GAAezC,EAAuB,eAAe,GAE5G,MAAM0C,GAAcjB,EAAQ,SAAS,EAC/Bd,GAAkBgB,EAAO,kBAAkB,EAC3Cf,GAAee,EAAO,eAAe,EACrCd,EAAgBW,EAAI,gBAAgB,EAEtCb,KAAoB,QAAaC,KAAiB,QAAcC,GAAkB,KACpFT,EAAO,QAAU,CACf,SAAUO,GACV,MAAOC,GACP,OAAQC,GAAiB,MAAA,EAElB6B,KAAgB,SACzBtC,EAAO,QAAUsC,IAGnB,MAAMC,GAAclB,EAAQ,cAAc,EACtCkB,KAAgB,SAAWvC,EAAO,YAAcuC,IAEpD,MAAMC,GAAmBnB,EAAQ,mBAAmB,EAChDmB,KAAqB,SAAWxC,EAAO,iBAAmBwC,IAE9D,MAAMC,GAAWpB,EAAQ,WAAW,EAChCoB,KAAa,SAAWzC,EAAO,SAAWyC,IAE9C,MAAMC,GAAerB,EAAQ,eAAe,EACxCqB,KAAiB,SAAW1C,EAAO,aAAe0C,IAEtD,MAAMC,GAAuBvB,EAAI,wBAAwB,EACrDuB,KAAsB3C,EAAO,qBAAuBa,EAAa8B,GAAsB9C,EAAsB,sBAAsB,GAEvI,MAAM+C,GAAavB,EAAQ,aAAa,EACpCuB,KAAe,SAAW5C,EAAO,WAAa4C,IAElD,MAAMC,GAAetB,EAAO,eAAe,EACvCsB,KAAiB,SAAW7C,EAAO,aAAe6C,IAEtD,MAAMC,GAAoBvB,EAAO,qBAAqB,EAClDuB,KAAsB,SAAW9C,EAAO,kBAAoB8C,IAEhE,MAAMC,GAAU3B,EAAI,UAAU,EAC9B,OAAI2B,KACF/C,EAAO,WAAa,CAClB,MAAO+C,GACP,WAAY3B,EAAI,gBAAgB,GAAK,OACrC,OAAQA,EAAI,WAAW,GAAK,OAC5B,YAAaG,EAAO,iBAAiB,EACrC,OAAQH,EAAI,WAAW,GAAK,MAAA,GAIzBpB,CACT,CAEA,SAASY,GAAcE,EAAuB,CAC5C,OAAK,SAASA,CAAK,EACZ,KAAK,IAAI,EAAG,KAAK,IAAI,IAAKA,CAAK,CAAC,EADV,EAE/B,CCpQA,MAAMkC,EAAW,yBAEV,SAASC,EAAaC,EAAmB,CAE9C,GADI,CAACC,KACD,SAAS,eAAeH,CAAQ,EAAG,OACvC,MAAMI,EAAQ,SAAS,cAAc,OAAO,EAC5CA,EAAM,GAAKJ,EACXI,EAAM,YAAcF,EACpB,SAAS,KAAK,YAAYE,CAAK,CACjC,CAEO,SAASC,EACdC,EACAC,EACAC,EAC0B,CAC1B,MAAMrC,EAAK,SAAS,cAAcmC,CAAG,EAErC,GADIC,MAAc,UAAYA,GAC1BC,EACF,SAAW,CAACC,EAAK3C,CAAK,IAAK,OAAO,QAAQ0C,CAAK,EAC7CrC,EAAG,aAAasC,EAAK3C,CAAK,EAG9B,OAAOK,CACT,CAEO,SAASuC,GAAeC,EAA2C,CACxE,GAAI,OAAOA,GAAW,SAAU,CAC9B,MAAMxC,EAAK,SAAS,cAA2BwC,CAAM,EACrD,GAAI,CAACxC,EACH,MAAM,IAAI,MAAM,kDAAkDwC,CAAM,GAAG,EAE7E,OAAOxC,CACT,CACA,OAAOwC,CACT,CAEO,SAASR,GAAqB,CACnC,OAAO,OAAO,OAAW,KAAe,OAAO,SAAa,GAC9D,CAEO,SAASS,GAA8B,CAC5C,GAAI,CAACT,EAAA,EAAa,MAAO,GACzB,MAAMU,EAAM,SAGZ,MAAO,CAAC,EAAEA,EAAI,mBAAqBA,EAAI,wBACzC,CAEO,SAASC,GAAkB3C,EAAgC,CAChE,MAAM4C,EAAO5C,EAGb,OAAI4C,EAAK,kBAA0BA,EAAK,kBAAA,EACpCA,EAAK,wBAAgCA,EAAK,wBAAA,EACvC,QAAQ,OAAO,IAAI,MAAM,8BAA8B,CAAC,CACjE,CAEO,SAASC,GAAgC,CAC9C,MAAMH,EAAM,SAGZ,OAAIA,EAAI,eAAuBA,EAAI,eAAA,EAC/BA,EAAI,qBAA6BA,EAAI,qBAAA,EAClC,QAAQ,OAAO,IAAI,MAAM,8BAA8B,CAAC,CACjE,CAEO,SAASI,GAAuC,CACrD,MAAMJ,EAAM,SAGZ,OAAOA,EAAI,mBAAqBA,EAAI,yBAA2B,IACjE,CCtEO,MAAMK,CAAa,CAAnB,aAAA,CACL,KAAQ,SAA2B,CAAA,CAAC,CAEpC,GACE/C,EACAgD,EACAC,EACAC,EACM,CACNlD,EAAG,iBAAiBgD,EAAOC,EAA0BC,CAAO,EAC5D,KAAK,SAAS,KAAK,IAAMlD,EAAG,oBAAoBgD,EAAOC,EAA0BC,CAAO,CAAC,CAC3F,CAEA,UACElD,EACAgD,EACAC,EACM,CACN,KAAK,GAAGjD,EAAIgD,EAAOC,EAAS,CAAE,QAAS,GAAM,CAC/C,CAEA,aACEjD,EACAgD,EACAC,EACM,CACN,KAAK,GAAGjD,EAAIgD,EAAOC,EAAS,CAAE,QAAS,GAAO,CAChD,CAEA,SAAgB,CACd,UAAWE,KAAW,KAAK,SACzBA,EAAA,EAEF,KAAK,SAAW,CAAA,CAClB,CACF,CAEO,SAASC,GACdC,EACAC,EAC0B,OAC1B,IAAIC,EACAC,EAEJ,GAAI,YAAaH,EAAG,CAClB,MAAMI,EAAQJ,EAAE,QAAQ,CAAC,KAAKK,EAAAL,EAAE,iBAAF,YAAAK,EAAmB,IACjD,GAAI,CAACD,EAAO,MAAO,CAAE,EAAG,EAAG,EAAG,CAAA,EAC9BF,EAAUE,EAAM,QAChBD,EAAUC,EAAM,OAClB,MACEF,EAAUF,EAAE,QACZG,EAAUH,EAAE,QAGd,MAAO,CACL,EAAGE,EAAUD,EAAK,KAClB,EAAGE,EAAUF,EAAK,GAAA,CAEtB,CAEO,SAASK,EACdN,EACAC,EACA3C,EACQ,CACR,KAAM,CAAE,EAAAiD,EAAG,EAAAC,CAAA,EAAMT,GAAmBC,EAAGC,CAAI,EACrCQ,EAAYnD,IAAgB,aAAe2C,EAAK,MAAQA,EAAK,OACnE,OAAIQ,IAAc,EAAU,GAErB,KAAK,IAAI,EAAG,KAAK,IAAI,KADbnD,IAAgB,aAAeiD,EAAIC,GACPC,EAAa,GAAG,CAAC,CAC9D,CCtEA,MAAMC,GAAgB,mBAChBC,GAAiB,iCACjBC,GAAsB,SAE5B,SAASC,GAAyBrF,EAAgC,CAChE,GAAI,CAACkF,GAAc,KAAKlF,EAAO,KAAK,EAClC,MAAM,IAAI,MAAM,4CAA4CA,EAAO,KAAK,8BAA8B,EAExG,GAAIA,EAAO,QAAU,CAACmF,GAAe,KAAKnF,EAAO,MAAM,EACrD,MAAM,IAAI,MAAM,6CAA6CA,EAAO,MAAM,IAAI,EAEhF,GAAIA,EAAO,YAAc,CAACoF,GAAoB,KAAKpF,EAAO,UAAU,EAClE,MAAM,IAAI,MAAM,iDAAiDA,EAAO,UAAU,oCAAoC,CAE1H,CAEO,SAASsF,GACdC,EACAC,EACAxF,EACQ,CACRqF,GAAyBrF,CAAM,EAE/B,KAAM,CACJ,MAAAyF,EACA,WAAAC,EAAa,KACb,OAAAC,EAAS,cACT,YAAAC,EAAc,IACd,OAAAC,EAAS,GACT,qBAAAC,EAAuB,CAAC,EAAG,IAAK,CAAC,CAAA,EAC/B9F,EAEE+F,EAAM,OAAO,OAAW,KAAc,OAAO,kBAAoB,EAEjEC,GADUF,EAAqB,OAAS,EAAIA,EAAuB,CAAC,CAAC,GAChD,OAAO,CAACG,EAAMC,IACvC,KAAK,IAAIA,EAAOH,CAAG,EAAI,KAAK,IAAIE,EAAOF,CAAG,EAAIG,EAAOD,CAAA,EAGjDE,EAAkBP,EAAc,EAAIA,EAAc,IAClDQ,EAAWZ,EAAiBQ,EAC5BK,EAAe,KAAK,KAAKD,EAAWD,CAAe,EAAIA,EAEvDG,EAAU,WAAWb,CAAK,IAAIE,CAAM,IAAID,CAAU,GAElDa,EAAWV,EACb,IAAIA,CAAM,MAAMQ,CAAY,GAC5B,MAAMA,CAAY,GAEtB,OAAId,EAAI,WAAW,SAAS,GAAKA,EAAI,WAAW,UAAU,EACjD,GAAGe,CAAO,IAAIf,CAAG,GAAGgB,CAAQ,GAG9B,GAAGD,CAAO,IAAIf,CAAG,GAAGgB,CAAQ,EACrC,CC7CO,SAASC,EACdC,EACAC,EACA5E,EACApB,EACM,CACN,IAAIiG,EAAWD,EAEXhG,GAAQA,EAAK,MAAQ,IACnBoB,IAAgB,aAClB6E,EAAWD,EAAWhG,EAAK,MAAQA,EAAK,KAAO,KAAOA,EAAK,MAAQA,EAAK,gBAExEiG,EAAWD,EAAWhG,EAAK,MAAQA,EAAK,KAAO,KAAOA,EAAK,MAAQA,EAAK,iBAE1EiG,EAAW,KAAK,IAAI,EAAG,KAAK,IAAI,IAAKA,CAAQ,CAAC,GAGhD,MAAM7F,EAAQgB,IAAgB,aAC1B,eAAe6E,CAAQ,KACvB,SAASA,CAAQ,WACrBF,EAAO,MAAM,SAAW3F,EAExB2F,EAAO,MAAM,YAAY,oBAAqB3F,CAAK,CACrD,CAEO,SAAS8F,GACdC,EACAH,EACA5E,EACM,CACFA,IAAgB,cAClB+E,EAAS,MAAM,KAAO,GAAGH,CAAQ,IACjCG,EAAS,MAAM,IAAM,KAErBA,EAAS,MAAM,IAAM,GAAGH,CAAQ,IAChCG,EAAS,MAAM,KAAO,GAE1B,CAEO,SAASjG,EAAcE,EAAuB,CACnD,OAAK,SAASA,CAAK,EACZ,KAAK,IAAI,EAAG,KAAK,IAAI,IAAKA,CAAK,CAAC,EADV,EAE/B,CCjDA,MAAMgG,GAAe,wNACfC,GAAgB,uNAChBC,GAAa,wNACbC,GAAe,sNACfC,GAAkB,2SAClBC,GAAgB,2SAEf,SAASC,EACdhE,EACAtB,EACA4E,EACa,CACb,MAAMW,EAAShE,EAAc,MAAO,kDAAkDD,CAAK,GAAI,CAC7F,KAAM,SACN,gBAAiB,OAAO,KAAK,MAAMsD,CAAQ,CAAC,EAC5C,gBAAiB,IACjB,gBAAiB,MACjB,aAAc,yFACd,mBAAoB5E,EACpB,SAAU,GAAA,CACX,EAQD,OANIA,IAAgB,aAClBuF,EAAO,MAAM,KAAO,GAAGX,CAAQ,IAE/BW,EAAO,MAAM,IAAM,GAAGX,CAAQ,IAGxBtD,EAAA,CACN,IAAK,SACHkE,GAAkBD,EAAQvF,CAAW,EACrC,MACF,IAAK,SACHyF,GAAkBF,EAAQvF,CAAW,EACrC,MACF,IAAK,OACH0F,GAAgBH,CAAM,EACtB,KAAA,CAGJ,OAAOA,CACT,CAEA,SAASC,GAAkBD,EAAqBvF,EAAgC,CAC9E,MAAM2F,EAAQpE,EAAc,MAAO,6BAA6B,EAC1DqE,EAAOrE,EAAc,MAAO,6BAA6B,EACzDsE,EAAQtE,EAAc,MAAO,6BAA6B,EAE5DvB,IAAgB,aAClB4F,EAAK,UAAYZ,GAAeC,GAEhCW,EAAK,UAAYV,GAAaC,GAGhCI,EAAO,OAAOI,EAAOC,EAAMC,CAAK,CAClC,CAEA,SAASJ,GAAkBF,EAAqBvF,EAAgC,CAC9E,MAAM4F,EAAOrE,EAAc,MAAO,6BAA6B,EAE3DvB,IAAgB,aAClB4F,EAAK,UAAYR,GAEjBQ,EAAK,UAAYP,GAGnBE,EAAO,OAAOK,CAAI,CACpB,CAEA,SAASF,GAAgBH,EAA2B,CAClD,MAAMI,EAAQpE,EAAc,MAAO,6BAA6B,EAC1DqE,EAAOrE,EAAc,MAAO,+DAA+D,EAC3FsE,EAAQtE,EAAc,MAAO,6BAA6B,EAEhEgE,EAAO,OAAOI,EAAOC,EAAMC,CAAK,CAClC,CCrEO,MAAMC,CAAe,CAO1B,YACUC,EACAR,EACAxF,EACAC,EACAgG,EACR,CALQ,KAAA,UAAAD,EACA,KAAA,OAAAR,EACA,KAAA,KAAAxF,EACA,KAAA,YAAAC,EACA,KAAA,UAAAgG,EAXV,KAAQ,OAAS,IAAI5D,EACrB,KAAQ,cAAgC,KACxC,KAAQ,MAAuB,KAC/B,KAAQ,gBAAiC,KACzC,KAAQ,gBAA0C,KAShD,KAAK,KAAA,CACP,CAEQ,MAAa,CACnB,OAAQ,KAAK,KAAA,CACX,IAAK,OACH,KAAK,SAAA,EACL,MACF,IAAK,QACH,KAAK,UAAA,EACL,MACF,IAAK,QACH,KAAK,UAAA,EACL,KAAA,CAEN,CAEQ,UAAiB,CACvB,KAAK,OAAO,GAAG,KAAK,OAAQ,YAAc,GAAkB,CAC1D,EAAE,eAAA,EACF,KAAK,UAAA,CACP,CAAC,EAED,KAAK,OAAO,GAAG,KAAK,OAAQ,aAAe,GAAkB,CAC3D,EAAE,eAAA,EACF,KAAK,OAAO,MAAA,EACZ,KAAK,eAAA,CACP,EAAG,CAAE,QAAS,GAAO,CACvB,CAEQ,WAAkB,CACxB,KAAK,uBAAA,EACL,KAAK,gBAAkB,IAAI,gBAC3B,MAAM6D,EAAS,KAAK,gBAAgB,OAEpC,KAAK,cAAgB,KAAK,UAAU,sBAAA,EACpC,KAAK,UAAU,YAAA,EAEf,MAAMC,EAAexD,GAAkB,CACrC,GAAI,CAAC,KAAK,cAAe,OACzB,MAAMkC,EAAW5B,EAAmBN,EAAG,KAAK,cAAe,KAAK,WAAW,EAC3E,KAAK,uBAAuBkC,CAAQ,CACtC,EAEMuB,EAAY,IAAM,CACtB,KAAK,oBAAA,EACL,KAAK,UAAU,UAAA,EACf,KAAK,cAAgB,KACrB,KAAK,uBAAA,CACP,EAEA,OAAO,iBAAiB,YAAaD,EAAa,CAAE,OAAAD,EAAQ,EAC5D,OAAO,iBAAiB,UAAWE,EAAW,CAAE,OAAAF,EAAQ,CAC1D,CAEQ,gBAAuB,CAC7B,KAAK,uBAAA,EACL,KAAK,gBAAkB,IAAI,gBAC3B,MAAMA,EAAS,KAAK,gBAAgB,OAEpC,KAAK,cAAgB,KAAK,UAAU,sBAAA,EACpC,KAAK,UAAU,YAAA,EAEf,MAAMG,EAAe1D,GAAkB,CAErC,GADI,CAAC,KAAK,eACNA,EAAE,QAAQ,SAAW,EAAG,OAC5BA,EAAE,eAAA,EACF,MAAMkC,EAAW5B,EAAmBN,EAAG,KAAK,cAAe,KAAK,WAAW,EAC3E,KAAK,uBAAuBkC,CAAQ,CACtC,EAEMyB,EAAa,IAAM,CACvB,KAAK,oBAAA,EACL,KAAK,UAAU,UAAA,EACf,KAAK,cAAgB,KACrB,KAAK,uBAAA,CACP,EAEA,OAAO,iBAAiB,YAAaD,EAAa,CAAE,QAAS,GAAO,OAAAH,EAAQ,EAC5E,OAAO,iBAAiB,WAAYI,EAAY,CAAE,OAAAJ,EAAQ,EAC1D,OAAO,iBAAiB,cAAeI,EAAY,CAAE,OAAAJ,EAAQ,CAC/D,CAEQ,uBAAuBrB,EAAwB,CACrD,KAAK,gBAAkBA,EACnB,KAAK,QAAU,OACjB,KAAK,MAAQ,sBAAsB,IAAM,CACvC,KAAK,MAAQ,KACT,KAAK,kBAAoB,OAC3B,KAAK,UAAU,iBAAiB,KAAK,eAAe,EACpD,KAAK,gBAAkB,KAE3B,CAAC,EAEL,CAEQ,qBAA4B,CAC9B,KAAK,QAAU,OACjB,qBAAqB,KAAK,KAAK,EAC/B,KAAK,MAAQ,MAEX,KAAK,kBAAoB,OAC3B,KAAK,UAAU,iBAAiB,KAAK,eAAe,EACpD,KAAK,gBAAkB,KAE3B,CAEQ,wBAA+B,CACjC,KAAK,kBACP,KAAK,gBAAgB,MAAA,EACrB,KAAK,gBAAkB,KAE3B,CAEQ,WAAkB,CACxB,KAAK,OAAO,GAAG,KAAK,UAAW,YAAc,GAAkB,CAC7D,MAAMjC,EAAO,KAAK,UAAU,sBAAA,EACtBiC,EAAW5B,EAAmB,EAAGL,EAAM,KAAK,WAAW,EAC7D,KAAK,uBAAuBiC,CAAQ,CACtC,CAAC,CACH,CAEQ,WAAkB,CACxB,KAAK,OAAO,GAAG,KAAK,UAAW,QAAU,GAAkB,CACzD,GAAI,KAAK,OAAO,SAAS,EAAE,MAAc,EAAG,OAC5C,MAAMjC,EAAO,KAAK,UAAU,sBAAA,EACtBiC,EAAW5B,EAAmB,EAAGL,EAAM,KAAK,WAAW,EAC7D,KAAK,UAAU,iBAAiBiC,CAAQ,CAC1C,CAAC,CACH,CAEA,WAAW7E,EAA6B,CACtC,KAAK,OAAO,QAAA,EACZ,KAAK,uBAAA,EACL,KAAK,oBAAA,EACL,KAAK,KAAOA,EACZ,KAAK,KAAA,CACP,CAEA,kBAAkBC,EAAgC,CAChD,KAAK,YAAcA,CACrB,CAEA,SAAgB,CACd,KAAK,uBAAA,EAED,KAAK,QAAU,OACjB,qBAAqB,KAAK,KAAK,EAC/B,KAAK,MAAQ,MAEf,KAAK,gBAAkB,KACvB,KAAK,OAAO,QAAA,EACZ,KAAK,cAAgB,IACvB,CACF,CC/KO,MAAMsG,EAAkB,CAY7B,YACUC,EACAR,EACA7H,EACAsI,EACRC,EACA,CALQ,KAAA,SAAAF,EACA,KAAA,UAAAR,EACA,KAAA,OAAA7H,EACA,KAAA,aAAAsI,EAfV,KAAQ,UAAY,EACpB,KAAQ,KAAO,EACf,KAAQ,KAAO,EACf,KAAQ,eAAiB,EACzB,KAAQ,gBAAkB,EAC1B,KAAQ,cAAgB,GACxB,KAAQ,qBAA4C,KACpD,KAAQ,eAAwC,KAW9C,KAAK,kBAAoBC,EACzB,KAAK,oBAAA,EACL,KAAK,cAAA,CACP,CAEQ,eAAsB,CACxB,OAAO,eAAmB,MAC9B,KAAK,eAAiB,IAAI,eAAgBC,GAAY,CACpD,UAAWC,KAASD,EAAS,CAC3B,KAAM,CAAE,MAAAE,EAAO,OAAAC,CAAA,EAAWF,EAAM,YAChC,KAAK,eAAiBC,EACtB,KAAK,gBAAkBC,CACzB,CACF,CAAC,EACD,KAAK,eAAe,QAAQ,KAAK,SAAS,EAC5C,CAEA,SAAkB,CAChB,OAAO,KAAK,SACd,CAEA,kBAAsD,CACpD,MAAO,CAAE,MAAO,KAAK,eAAgB,OAAQ,KAAK,eAAA,CACpD,CAEA,QAAQC,EAAeC,EAAkBC,EAAwB,OAC/D,MAAMC,EAAU,KAAK,IAAI,KAAK,OAAO,QAAS,KAAK,IAAI,KAAK,OAAO,QAASH,CAAK,CAAC,EAClF,GAAIG,IAAY,KAAK,UAAW,OAEhC,MAAMC,EAAU,KAAK,UACrB,KAAK,UAAYD,EAGbF,IAAY,QAAaC,IAAY,SACvC,KAAK,KAAOD,GAAWA,EAAU,KAAK,OAASE,EAAUC,GACzD,KAAK,KAAOF,GAAWA,EAAU,KAAK,OAASC,EAAUC,IAG3D,KAAK,SAAA,EACL,KAAK,eAAe,EAAI,GACxBnE,EAAA,KAAK,eAAL,MAAAA,EAAA,UAAoB,KAAK,UAC3B,CAEA,QAAe,CACb,KAAK,QACH,KAAK,UAAY,IACjB,KAAK,eAAiB,EACtB,KAAK,gBAAkB,CAAA,CAE3B,CAEA,SAAgB,CACd,KAAK,QACH,KAAK,UAAY,IACjB,KAAK,eAAiB,EACtB,KAAK,gBAAkB,CAAA,CAE3B,CAEA,WAAkB,OAChB,KAAK,UAAY,KAAK,IAAI,EAAG,KAAK,OAAO,OAAO,EAChD,KAAK,KAAO,EACZ,KAAK,KAAO,EACZ,KAAK,eAAe,EAAI,GACxBA,EAAA,KAAK,eAAL,MAAAA,EAAA,UAAoB,KAAK,UAC3B,CAEA,QAAmC,CACjC,MAAO,CAAE,EAAG,KAAK,KAAM,EAAG,KAAK,IAAA,CACjC,CAEA,OAAOE,EAAWC,EAAiB,CACjC,KAAK,KAAOD,EACZ,KAAK,KAAOC,EACZ,KAAK,SAAA,EACL,KAAK,eAAe,EAAK,CAC3B,CAEA,IAAIiE,EAAYC,EAAkB,CAC5B,KAAK,WAAa,IACtB,KAAK,MAAQD,EACb,KAAK,MAAQC,EACb,KAAK,SAAA,EACL,KAAK,eAAe,EAAK,EAC3B,CAEA,YAAY,EAAqB,CAC/B,GAAI,CAAC,EAAE,SAAW,CAAC,EAAE,QAAS,OAE9B,EAAE,eAAA,EAEF,MAAMzE,EAAO,KAAK,UAAU,sBAAA,EACtBoE,EAAU,EAAE,QAAUpE,EAAK,KAC3BqE,EAAU,EAAE,QAAUrE,EAAK,IAE3B0E,EAAQ,EAAE,OAAS,EAAI,GAAM,IACnC,KAAK,QAAQ,KAAK,UAAYA,EAAON,EAASC,CAAO,CACvD,CAEA,WAAWD,EAAiBC,EAAuB,CACjD,MAAMM,EAAa,KAAK,IAAI,EAAG,KAAK,OAAO,OAAO,EAC9C,KAAK,UAAYA,EACnB,KAAK,UAAA,EAEL,KAAK,QAAQ,KAAK,IAAI,EAAGA,EAAa,GAAG,EAAGP,EAASC,CAAO,CAEhE,CAEA,aAAa9I,EAA8B,OACzC,KAAK,OAASA,EAEd,MAAM+I,EAAU,KAAK,IAAI/I,EAAO,QAAS,KAAK,IAAIA,EAAO,QAAS,KAAK,SAAS,CAAC,EAC7E+I,IAAY,KAAK,YACnB,KAAK,UAAYA,GACjBlE,EAAA,KAAK,eAAL,MAAAA,EAAA,UAAoB,KAAK,YAE3B,KAAK,SAAA,EACL,KAAK,eAAe,EAAK,CAC3B,CAEQ,qBAA4B,CAClC,MAAMJ,EAAO,KAAK,UAAU,sBAAA,EAC5B,KAAK,eAAiBA,EAAK,MAC3B,KAAK,gBAAkBA,EAAK,MAC9B,CAEQ,UAAiB,CACvB,GAAI,KAAK,WAAa,EAAG,CACvB,KAAK,KAAO,EACZ,KAAK,KAAO,EACZ,MACF,CAEA,MAAM4E,EAAU,KAAK,gBAAkB,KAAK,UAAY,GAClDC,EAAU,KAAK,iBAAmB,KAAK,UAAY,GAEzD,KAAK,KAAO,KAAK,IAAI,CAACD,EAAS,KAAK,IAAI,EAAG,KAAK,IAAI,CAAC,EACrD,KAAK,KAAO,KAAK,IAAI,CAACC,EAAS,KAAK,IAAI,EAAG,KAAK,IAAI,CAAC,CACvD,CAEQ,eAAejJ,EAAwB,OAO7C,GALI,KAAK,uBACP,KAAK,qBAAA,EACL,KAAK,qBAAuB,MAG1BA,EAAS,CACX,KAAK,SAAS,MAAM,WAAa,uBACjC,KAAK,cAAgB,GACrB,MAAMkJ,EAAS/E,GAAuB,CAChCA,EAAE,SAAW,KAAK,WACtB,KAAK,SAAS,MAAM,WAAa,GACjC,KAAK,cAAgB,GACrB,KAAK,qBAAuB,KAC5B,KAAK,SAAS,oBAAoB,gBAAiB+E,CAAK,EAC1D,EACA,KAAK,SAAS,iBAAiB,gBAAiBA,CAAK,EACrD,KAAK,qBAAuB,IAAM,CAChC,KAAK,SAAS,oBAAoB,gBAAiBA,CAAK,EACxD,KAAK,SAAS,MAAM,WAAa,GACjC,KAAK,cAAgB,EACvB,CACF,MAAY,KAAK,gBACf,KAAK,SAAS,MAAM,WAAa,IAGnC,KAAK,SAAS,MAAM,UAClB,SAAS,KAAK,SAAS,eAAe,KAAK,KAAO,KAAK,SAAS,OAAO,KAAK,KAAO,KAAK,SAAS,OAEnG1E,EAAA,KAAK,oBAAL,MAAAA,EAAA,UACF,CAEA,SAAgB,OACV,KAAK,uBACP,KAAK,qBAAA,EACL,KAAK,qBAAuB,MAE9B,KAAK,SAAS,MAAM,UAAY,GAChC,KAAK,SAAS,MAAM,WAAa,IACjCA,EAAA,KAAK,iBAAL,MAAAA,EAAqB,aACrB,KAAK,eAAiB,IACxB,CACF,CCzMA,MAAM2E,GAAgB,EAEf,MAAMC,CAAa,CASxB,YACU5B,EACAR,EACAqC,EACAC,EACR,CAJQ,KAAA,UAAA9B,EACA,KAAA,OAAAR,EACA,KAAA,QAAAqC,EACA,KAAA,mBAAAC,EAZV,KAAQ,OAAS,IAAIzF,EACrB,KAAQ,UAAY,GACpB,KAAQ,SAAW,EACnB,KAAQ,SAAW,EACnB,KAAQ,qBAAuB,EAC/B,KAAQ,iBAAmB,EAC3B,KAAQ,gBAA0C,KAQhD,KAAK,KAAA,CACP,CAEQ,MAAa,CAEnB,KAAK,OAAO,aAAa,KAAK,UAAW,QAAU,GAAkB,OAC/D,EAAE,SAAW,EAAE,QACjB,KAAK,QAAQ,YAAY,CAAC,EACjB,KAAK,QAAQ,QAAA,EAAY,IAGlCW,EAAA,KAAK,qBAAL,MAAAA,EAAA,UAEJ,CAAC,EAGD,KAAK,OAAO,GAAG,KAAK,UAAW,WAAa,GAAkB,CAC5D,GAAI,KAAK,OAAO,SAAS,EAAE,MAAc,EAAG,OAC5C,MAAMJ,EAAO,KAAK,UAAU,sBAAA,EAC5B,KAAK,QAAQ,WAAW,EAAE,QAAUA,EAAK,KAAM,EAAE,QAAUA,EAAK,GAAG,CACrE,CAAC,EAGD,KAAK,OAAO,GAAG,KAAK,UAAW,YAAc,GAAkB,CACzD,KAAK,OAAO,SAAS,EAAE,MAAc,GACrC,KAAK,QAAQ,QAAA,GAAa,IAC9B,EAAE,eAAA,EACF,KAAK,SAAS,EAAE,QAAS,EAAE,OAAO,EACpC,CAAC,EAGD,KAAK,OAAO,GAAG,KAAK,UAAW,aAAe,GAAkB,CAC1D,KAAK,OAAO,SAAS,EAAE,MAAc,IAErC,EAAE,QAAQ,SAAW,GACvB,EAAE,eAAA,EACF,KAAK,WAAW,CAAC,GACR,EAAE,QAAQ,SAAW,GAAK,KAAK,QAAQ,QAAA,EAAY,IAC5D,EAAE,eAAA,EACF,KAAK,cAAc,CAAC,GAExB,EAAG,CAAE,QAAS,GAAO,EAGjB,OAAO,OAAW,KAAe,iBAAkB,SAIrD,KAAK,OAAO,aAAa,KAAK,UAAW,eAA8C,GAAa,CAClG,EAAE,eAAA,EACF,KAAK,iBAAmB,KAAK,QAAQ,QAAA,EACrC,MAAMmF,EAAK,EACLnF,EAAO,KAAK,UAAU,sBAAA,EACXmF,EAAG,QAAUnF,EAAK,KAClBmF,EAAG,QAAUnF,EAAK,GACrC,CAAC,EAED,KAAK,OAAO,aAAa,KAAK,UAAW,gBAA+C,GAAa,CACnG,EAAE,eAAA,EACF,MAAMmF,EAAK,EACLnF,EAAO,KAAK,UAAU,sBAAA,EAC5B,KAAK,QAAQ,QACX,KAAK,iBAAmBmF,EAAG,MAC3BA,EAAG,QAAUnF,EAAK,KAClBmF,EAAG,QAAUnF,EAAK,GAAA,CAEtB,CAAC,EAEL,CAEQ,SAASC,EAAiBC,EAAuB,CACvD,KAAK,uBAAA,EACL,KAAK,gBAAkB,IAAI,gBAC3B,MAAMoD,EAAS,KAAK,gBAAgB,OAEpC,KAAK,UAAY,GACjB,KAAK,SAAWrD,EAChB,KAAK,SAAWC,EAChB,MAAMkF,EAASnF,EACToF,EAASnF,EAETqD,EAAexD,GAAkB,CACrC,MAAMyE,EAAKzE,EAAE,QAAU,KAAK,SACtB0E,EAAK1E,EAAE,QAAU,KAAK,SAG5B,GAAI,CAAC,KAAK,UAAW,CACnB,MAAMuF,EAAUvF,EAAE,QAAUqF,EACtBG,EAAUxF,EAAE,QAAUsF,EAC5B,GAAI,KAAK,MAAMC,EAASC,CAAO,EAAIR,GAAe,OAClD,KAAK,UAAY,GACjB,KAAK,UAAU,MAAM,OAAS,UAChC,CAEA,KAAK,SAAWhF,EAAE,QAClB,KAAK,SAAWA,EAAE,QAClB,KAAK,QAAQ,IAAIyE,EAAIC,CAAE,CACzB,EAEMjB,EAAY,IAAM,CACtB,KAAK,UAAY,GACjB,KAAK,UAAU,MAAM,OAAS,GAC9B,KAAK,uBAAA,CACP,EAEA,OAAO,iBAAiB,YAAaD,EAAa,CAAE,OAAAD,EAAQ,EAC5D,OAAO,iBAAiB,UAAWE,EAAW,CAAE,OAAAF,EAAQ,CAC1D,CAEQ,cAAc,EAAqB,CACzC,KAAK,uBAAA,EACL,KAAK,gBAAkB,IAAI,gBAC3B,MAAMA,EAAS,KAAK,gBAAgB,OAE9BnD,EAAQ,EAAE,QAAQ,CAAC,EACzB,KAAK,SAAWA,EAAM,QACtB,KAAK,SAAWA,EAAM,QAEtB,MAAMsD,EAAe1D,GAAkB,CACrC,GAAIA,EAAE,QAAQ,SAAW,EAAG,OAC5BA,EAAE,eAAA,EACF,MAAMI,EAAQJ,EAAE,QAAQ,CAAC,EACnByE,EAAKrE,EAAM,QAAU,KAAK,SAC1BsE,EAAKtE,EAAM,QAAU,KAAK,SAChC,KAAK,SAAWA,EAAM,QACtB,KAAK,SAAWA,EAAM,QACtB,KAAK,QAAQ,IAAIqE,EAAIC,CAAE,CACzB,EAEMf,EAAa,IAAM,CACvB,KAAK,uBAAA,CACP,EAEA,OAAO,iBAAiB,YAAaD,EAAa,CAAE,QAAS,GAAO,OAAAH,EAAQ,EAC5E,OAAO,iBAAiB,WAAYI,EAAY,CAAE,OAAAJ,EAAQ,EAC1D,OAAO,iBAAiB,cAAeI,EAAY,CAAE,OAAAJ,EAAQ,CAC/D,CAEQ,WAAW,EAAqB,CACtC,GAAI,EAAE,QAAQ,OAAS,EAAG,OAE1B,KAAK,uBAAA,EACL,KAAK,gBAAkB,IAAI,gBAC3B,MAAMA,EAAS,KAAK,gBAAgB,OAC9B,CAACkC,EAAIC,CAAE,EAAI,CAAC,EAAE,QAAQ,CAAC,EAAG,EAAE,QAAQ,CAAC,CAAC,EAC5C,KAAK,qBAAuB,KAAK,MAAMA,EAAG,QAAUD,EAAG,QAASC,EAAG,QAAUD,EAAG,OAAO,EACnF,KAAK,uBAAyB,IAAG,KAAK,qBAAuB,GACjE,KAAK,iBAAmB,KAAK,QAAQ,QAAA,EAErC,MAAMxF,EAAO,KAAK,UAAU,sBAAA,EACtBoE,GAAWoB,EAAG,QAAUC,EAAG,SAAW,EAAIzF,EAAK,KAC/CqE,GAAWmB,EAAG,QAAUC,EAAG,SAAW,EAAIzF,EAAK,IAE/CyD,EAAe1D,GAAkB,CACrC,GAAIA,EAAE,QAAQ,SAAW,EAAG,OAC5BA,EAAE,eAAA,EACF,KAAM,CAACyF,EAAIC,CAAE,EAAI,CAAC1F,EAAE,QAAQ,CAAC,EAAGA,EAAE,QAAQ,CAAC,CAAC,EAEtC2F,EADO,KAAK,MAAMD,EAAG,QAAUD,EAAG,QAASC,EAAG,QAAUD,EAAG,OAAO,EACnD,KAAK,qBAC1B,KAAK,QAAQ,QAAQ,KAAK,iBAAmBE,EAAOtB,EAASC,CAAO,CACtE,EAEMX,EAAa,IAAM,CACvB,KAAK,uBAAA,CACP,EAEA,OAAO,iBAAiB,YAAaD,EAAa,CAAE,QAAS,GAAO,OAAAH,EAAQ,EAC5E,OAAO,iBAAiB,WAAYI,EAAY,CAAE,OAAAJ,EAAQ,EAC1D,OAAO,iBAAiB,cAAeI,EAAY,CAAE,OAAAJ,EAAQ,CAC/D,CAEQ,wBAA+B,CACjC,KAAK,kBACP,KAAK,gBAAgB,MAAA,EACrB,KAAK,gBAAkB,KAE3B,CAEA,SAAgB,CACd,KAAK,uBAAA,EACL,KAAK,OAAO,QAAA,CACd,CACF,CCtMA,MAAMqC,GAAY,sOACZC,GAAa,kNACbC,GAAa,+QAaZ,SAASC,EACd7D,EACAoB,EACoB,CACpB,MAAM0C,EAAS,IAAItG,EACbuG,EAAUpH,EAAc,MAAO,gEAAgEqD,CAAQ,EAAE,EAEzGgE,EAAYrH,EAAc,SAAU,0BAA2B,CACnE,KAAM,SACN,aAAc,SAAA,CACf,EACDqH,EAAU,UAAYN,GACtBI,EAAO,GAAGE,EAAW,QAAS5C,EAAU,QAAQ,EAEhD,MAAM6C,EAAatH,EAAc,SAAU,2BAA4B,CACrE,KAAM,SACN,aAAc,UAAA,CACf,EACDsH,EAAW,UAAYN,GACvBG,EAAO,GAAGG,EAAY,QAAS7C,EAAU,SAAS,EAElD,MAAM8C,EAAWvH,EAAc,SAAU,6BAA8B,CACrE,KAAM,SACN,aAAc,YAAA,CACf,EACD,OAAAuH,EAAS,UAAYN,GACrBE,EAAO,GAAGI,EAAU,QAAS9C,EAAU,OAAO,EAE9C2C,EAAQ,OAAOC,EAAWC,EAAYC,CAAQ,EACvC,CAAE,QAASH,EAAS,OAAAD,CAAA,CAC7B,CC/CO,MAAMK,CAAW,CAItB,YAAYhD,EAAwB,CAFpC,KAAQ,QAAgD,KAGtD,KAAK,GAAKxE,EAAc,MAAO,8BAA+B,CAC5D,cAAe,MAAA,CAChB,EAED,MAAMyH,EAAQ,OAAO,UAAc,KAAe,uBAAuB,KAAK,UAAU,SAAS,EACjG,KAAK,GAAG,YAAcA,EAClB,8BACA,iCAEJjD,EAAU,YAAY,KAAK,EAAE,CAC/B,CAEA,MAAa,CACP,KAAK,SAAS,aAAa,KAAK,OAAO,EAE3C,KAAK,GAAG,UAAU,IAAI,sCAAsC,EAE5D,KAAK,QAAU,WAAW,IAAM,CAC9B,KAAK,GAAG,UAAU,OAAO,sCAAsC,EAC/D,KAAK,QAAU,IACjB,EAAG,IAAI,CACT,CAEA,SAAgB,CACV,KAAK,SAAS,aAAa,KAAK,OAAO,EAC3C,KAAK,GAAG,OAAA,CACV,CACF,CC/BO,SAASkD,EACdC,EACAC,EACAvE,EACA5E,EAC6C,CAC7C,MAAMoJ,EAAW,0BAA0BxE,CAAQ,GAE7CyE,EAAc9H,EAAc,MAChC,sDAAsD6H,CAAQ,GAC9D,CAAE,cAAe,MAAA,CAAO,EAE1BC,EAAY,YAAcH,EAE1B,MAAMI,EAAa/H,EAAc,MAC/B,qDAAqD6H,CAAQ,GAC7D,CAAE,cAAe,MAAA,CAAO,EAE1B,OAAAE,EAAW,YAAcH,EAElB,CAAE,OAAQE,EAAa,MAAOC,CAAA,CACvC,CAEO,SAASC,EACdF,EACAC,EACA1E,EACA5E,EACM,CACN,GAAI,CAACqJ,GAAe,CAACC,EAAY,OAEjC,MAAME,EAAgB,GAGlB5E,EAAW4E,EACbH,EAAY,UAAU,IAAI,+BAA+B,EAEzDA,EAAY,UAAU,OAAO,+BAA+B,EAI1DzE,EAAW,IAAM4E,EACnBF,EAAW,UAAU,IAAI,+BAA+B,EAExDA,EAAW,UAAU,OAAO,+BAA+B,CAE/D,CC9CA,MAAMG,EAAgB,gVAChBC,GAAgB,oVAEf,MAAMC,EAAkB,CAK7B,YACU5D,EACA6D,EACR,CAFQ,KAAA,UAAA7D,EACA,KAAA,mBAAA6D,EANV,KAAQ,OAA6B,KACrC,KAAQ,OAAS,IAAIxH,EACrB,KAAQ,SAAW,GAMZN,MACL,KAAK,aAAA,EACL,KAAK,WAAA,EACP,CAEQ,cAAqB,CAC3B,KAAK,OAASP,EAAc,SAAU,iCAAkC,CACtE,KAAM,SACN,aAAc,mBACd,eAAgB,OAAA,CACjB,EACD,KAAK,OAAO,UAAYkI,EACxB,KAAK,OAAO,GAAG,KAAK,OAAQ,QAAS,IAAM,CAAE,KAAK,SAAS,MAAM,IAAM,CAAC,CAAC,CAAG,CAAC,EAC7E,KAAK,UAAU,YAAY,KAAK,MAAM,CACxC,CAEQ,YAAmB,CACzB,KAAK,OAAO,GAAG,SAAoC,mBAAoB,IAAM,KAAK,cAAc,EAChG,KAAK,OAAO,GAAG,SAAoC,yBAAuD,IAAM,KAAK,cAAc,CACrI,CAEQ,cAAqB,OAC3B,MAAMI,EAAY1H,EAAA,EACZ2H,EAAY,KAAK,SACvB,KAAK,SAAWD,IAAc,KAAK,UAG/BC,IAAc,KAAK,WAEvB,KAAK,UAAU,UAAU,OAAO,wCAAyC,KAAK,QAAQ,EAElF,KAAK,SACP,KAAK,OAAO,UAAY,KAAK,SAAWJ,GAAgBD,EACxD,KAAK,OAAO,aAAa,aAAc,KAAK,SAAW,kBAAoB,kBAAkB,EAC7F,KAAK,OAAO,aAAa,eAAgB,OAAO,KAAK,QAAQ,CAAC,IAGhE1G,EAAA,KAAK,qBAAL,MAAAA,EAAA,UAA0B,KAAK,UACjC,CAEA,MAAM,OAAuB,CACtBjB,KACL,MAAME,GAAkB,KAAK,SAAS,CACxC,CAEA,MAAM,MAAsB,CACrBF,KACDK,EAAA,IAA2B,KAAK,WAClC,MAAMD,EAAA,CAEV,CAEA,MAAM,QAAwB,CACxB,KAAK,SACP,MAAM,KAAK,KAAA,EAEX,MAAM,KAAK,MAAA,CAEf,CAEA,iBAA2B,CACzB,OAAO,KAAK,QACd,CAEA,SAAgB,SACd,MAAM4H,EAAY,KAAK,SACvB,KAAK,OAAO,QAAA,EACRA,IACF,KAAK,SAAW,IAChB/G,EAAA,KAAK,qBAAL,MAAAA,EAAA,UAA0B,IAC1Bb,EAAA,EAAiB,MAAM,IAAM,CAAC,CAAC,GAEjC,KAAK,UAAU,UAAU,OAAO,uCAAuC,GACvE6H,EAAA,KAAK,SAAL,MAAAA,EAAa,QACf,CACF,CC1FO,MAAMC,EAAkB,CAO7B,YACUjE,EACAkE,EACAC,EACAC,EACA1J,EACA2J,EACR,CANQ,KAAA,UAAArE,EACA,KAAA,SAAAkE,EACA,KAAA,MAAAC,EACA,KAAA,OAAAC,EACA,KAAA,YAAA1J,EACA,KAAA,UAAA2J,EAZV,KAAQ,SAAwC,KAChD,KAAQ,UAAY,GACpB,KAAQ,YAAc,GACtB,KAAQ,WAAmD,KAC3D,KAAQ,cAAsD,KAU5D,KAAK,QAAA,CACP,CAEQ,SAAgB,CAClB,OAAO,qBAAyB,MAEpC,KAAK,SAAW,IAAI,qBACjB1D,GAAY,CACX,UAAWC,KAASD,EAClB,GAAIC,EAAM,eAAgB,CAExB,GADI,KAAK,aAAe,KAAK,WACzB,KAAK,YAAa,SACtB,KAAK,KAAA,CACP,CAEJ,EACA,CAAE,UAAW,EAAA,CAAI,EAGnB,KAAK,SAAS,QAAQ,KAAK,SAAS,EACtC,CAEQ,MAAa,SAKnB,GAJA,KAAK,UAAY,GACjB,KAAK,YAAc,GAGf,OAAO,OAAW,OAAe5D,EAAA,OAAO,aAAP,MAAAA,EAAA,YAAoB,oCAAoC,SAAS,CACpG,KAAK,UAAU,EAAI,EACnB,KAAK,YAAc,GACf,KAAK,eACPgH,EAAA,KAAK,WAAL,MAAAA,EAAe,cAEjB,MACF,CAEA,KAAK,UAAU,UAAU,IAAI,kCAAkC,EAC/D,KAAK,UAAU,MAAM,YAAY,qCAAsC,GAAG,KAAK,QAAQ,IAAI,EAC3F,KAAK,UAAU,MAAM,YAAY,mCAAoC,KAAK,MAAM,EAEhF,KAAK,WAAa,WAAW,IAAM,CACjC,KAAK,WAAa,KAClB,KAAK,UAAU,EAAK,EAEpB,KAAK,cAAgB,WAAW,IAAM,OACpC,KAAK,cAAgB,KACrB,KAAK,UAAU,UAAU,OAAO,kCAAkC,EAClE,KAAK,YAAc,GACf,KAAK,eACPhH,EAAA,KAAK,WAAL,MAAAA,EAAe,aAEnB,EAAG,KAAK,QAAQ,CAClB,EAAG,KAAK,KAAK,CACf,CAEA,cAAwB,CACtB,OAAO,KAAK,SACd,CAEA,SAAgB,OACV,KAAK,YAAY,aAAa,KAAK,UAAU,EAC7C,KAAK,eAAe,aAAa,KAAK,aAAa,EACvD,KAAK,WAAa,KAClB,KAAK,cAAgB,KACrB,KAAK,YAAc,GACnB,KAAK,UAAU,UAAU,OAAO,kCAAkC,EAClE,KAAK,UAAU,MAAM,eAAe,oCAAoC,EACxE,KAAK,UAAU,MAAM,eAAe,kCAAkC,GACtEA,EAAA,KAAK,WAAL,MAAAA,EAAe,aACf,KAAK,SAAW,IAClB,CACF,CC3EO,MAAMsH,EAAgB,CAG3B,YACU9E,EACAvF,EACAsK,EACAC,EACAC,EACAxE,EACR,CANQ,KAAA,OAAAT,EACA,KAAA,YAAAvF,EACA,KAAA,KAAAsK,EACA,KAAA,UAAAC,EACA,KAAA,YAAAC,EACA,KAAA,UAAAxE,EARV,KAAQ,OAAS,IAAI5D,EAUnB,KAAK,KAAA,CACP,CAEQ,MAAa,CACnB,KAAK,OAAO,GAAG,KAAK,OAAQ,UAAY,GAAqB,CAC3D,KAAK,cAAc,CAAC,CACtB,CAAC,CACH,CAEQ,cAAc,EAAwB,iBAE5C,GAAI,EAAE,SAAW,EAAE,QAAU,EAAE,QAAS,OAExC,MAAMqI,EAAU,KAAK,UAAU,YAAA,EACzBC,EAAY,EAAE,SAAW,KAAK,UAAY,KAAK,KACrD,IAAIC,EAA6B,KAEjC,GAAI,KAAK,cAAgB,aACvB,OAAQ,EAAE,IAAA,CACR,IAAK,YACHA,EAAcF,EAAUC,EACxB,MACF,IAAK,aACHC,EAAcF,EAAUC,EACxB,KAAA,KAGJ,QAAQ,EAAE,IAAA,CACR,IAAK,UACHC,EAAcF,EAAUC,EACxB,MACF,IAAK,YACHC,EAAcF,EAAUC,EACxB,KAAA,CAIN,OAAQ,EAAE,IAAA,CACR,IAAK,OACHC,EAAc,EACd,MACF,IAAK,MACHA,EAAc,IACd,KAAA,CAGJ,GAAIA,IAAgB,KAAM,CACxB,EAAE,eAAA,EACFA,EAAc,KAAK,IAAI,EAAG,KAAK,IAAI,IAAKA,CAAW,CAAC,EACpD,KAAK,UAAU,iBAAiBA,CAAW,EAC3C,MACF,CAGA,GAAI,KAAK,YACP,OAAQ,EAAE,IAAA,CACR,IAAK,IACL,IAAK,IACH,EAAE,eAAA,GACFZ,GAAAhH,EAAA,KAAK,WAAU,WAAf,MAAAgH,EAAA,KAAAhH,GACA,MACF,IAAK,IACH,EAAE,eAAA,GACF6H,GAAAC,EAAA,KAAK,WAAU,YAAf,MAAAD,EAAA,KAAAC,GACA,MACF,IAAK,IACH,EAAE,eAAA,GACFC,GAAAC,EAAA,KAAK,WAAU,cAAf,MAAAD,EAAA,KAAAC,GACA,KAAA,CAGR,CAEA,aAAa/K,EAA0BsK,EAAcC,EAAmBC,EAA4B,CAClG,KAAK,YAAcxK,EACnB,KAAK,KAAOsK,EACZ,KAAK,UAAYC,EACjB,KAAK,YAAcC,CACrB,CAEA,SAAgB,CACd,KAAK,OAAO,QAAA,CACd,CACF,CCvGO,SAASQ,GAAgBzF,EAAqBX,EAAwB,CAC3EW,EAAO,aAAa,gBAAiB,OAAO,KAAK,MAAMX,CAAQ,CAAC,CAAC,CACnE,CAMO,SAASqG,GAAiBlF,EAA8B,CAC7DA,EAAU,aAAa,OAAQ,OAAO,EACtCA,EAAU,aAAa,aAAc,mCAAmC,CAC1E,CCWO,MAAMmF,EAAmD,CAsB9D,YACErJ,EACAsJ,EACA,CApBF,KAAQ,OAAS,IAAI/I,EACrB,KAAQ,YAAc,IAAIA,EAC1B,KAAQ,eAAwC,KAChD,KAAQ,QAAoC,KAC5C,KAAQ,aAAoC,KAC5C,KAAQ,WAAgC,KACxC,KAAQ,kBAA8C,KACtD,KAAQ,kBAA8C,KACtD,KAAQ,gBAA0C,KAClD,KAAQ,eAAwC,KAChD,KAAQ,eAAqC,KAC7C,KAAQ,mBAAoE,KAC5E,KAAQ,iBAAgD,KACxD,KAAQ,oBAA4D,KACpE,KAAQ,oBAA4D,KACpE,KAAQ,kBAAoB,GAM1B,MAAM2D,EAAYnE,GAAeC,CAAM,EACvC,KAAK,WAAa,CAAE,GAAGsJ,CAAA,EACvB,KAAK,OAASlN,EAAckN,CAAU,EAEtC,KAAK,MAAQ,CACX,SAAU,KAAK,OAAO,gBACtB,WAAY,GACZ,UAAW,EACX,KAAM,EACN,KAAM,EACN,QAAS,GACT,aAAc,EAAA,EAGhB,KAAK,SAASpF,CAAS,EACvB,KAAK,YAAA,EACL,KAAK,WAAA,CACP,CAIA,aAAc,CACZ,MAAO,CACL,UAAW,KAAK,SAAS,UACzB,SAAU,KAAK,SAAS,SACxB,YAAa,KAAK,SAAS,YAC3B,WAAY,KAAK,SAAS,WAC1B,OAAQ,KAAK,SAAS,MAAA,CAE1B,CAEA,YAAYqF,EAAuB,CACjC,MAAMnE,EAAUnI,EAAcsM,CAAO,EACrC,KAAK,eAAenE,CAAO,CAC7B,CAEA,aAAsB,CACpB,OAAO,KAAK,MAAM,QACpB,CAEA,QAAQH,EAAqB,QAC3B/D,EAAA,KAAK,UAAL,MAAAA,EAAc,QAAQ+D,EACxB,CAEA,SAAkB,OAChB,QAAO/D,EAAA,KAAK,UAAL,YAAAA,EAAc,YAAa,CACpC,CAEA,WAAkB,QAChBA,EAAA,KAAK,UAAL,MAAAA,EAAc,WAChB,CAEA,iBAAwB,QACtBA,EAAA,KAAK,oBAAL,MAAAA,EAAwB,QAAQ,MAAM,IAAM,CAAC,EAC/C,CAEA,gBAAuB,QACrBA,EAAA,KAAK,oBAAL,MAAAA,EAAwB,OAAO,MAAM,IAAM,CAAC,EAC9C,CAEA,cAAwB,OACtB,QAAOA,EAAA,KAAK,oBAAL,YAAAA,EAAwB,oBAAqB,EACtD,CAEA,OAAOsI,EAA+C,qBAEpD,KAAK,WAAa,CAAE,GAAG,KAAK,WAAY,GAAGA,CAAA,EAC3C,MAAMC,EAAY,KAAK,OACvB,KAAK,OAASrN,EAAc,KAAK,UAAU,EAG3C,MAAMsN,EAAmB,KAAK,OAAO,YAAcD,EAAU,UACvDE,EAAkB,KAAK,OAAO,WAAaF,EAAU,SAGrDG,EAAoB,CAACC,GAAa,KAAK,OAAO,WAAYJ,EAAU,UAAU,EA8EpF,IA5EIC,GAAoBC,GAAmBC,KAErC,KAAK,mBACP,KAAK,iBAAiB,WAAA,EACtB,KAAK,iBAAmB,MAI1B,KAAK,MAAM,QAAU,GACrB,KAAK,SAAS,UAAU,UAAU,IAAI,yBAAyB,GAE3DF,GAAoBE,KACtB,KAAK,SAAS,YAAY,IAAM,KAAK,gBAAgB,KAAK,OAAO,SAAS,IAExED,GAAmBC,KACrB,KAAK,SAAS,WAAW,IAAM,KAAK,gBAAgB,KAAK,OAAO,QAAQ,GAG1E,KAAK,0BAA0BF,GAAoBE,EAAmBD,GAAmBC,CAAiB,EAGtG,KAAK,OAAO,YAAc,CAACH,EAAU,WACvC,KAAK,mBAAA,EACI,CAAC,KAAK,OAAO,YAAcA,EAAU,cAC9CvI,EAAA,KAAK,iBAAL,MAAAA,EAAqB,aACrB,KAAK,eAAiB,OAKtB,KAAK,OAAO,YAAcuI,EAAU,WACtC,KAAK,SAAS,YAAY,aAAa,MAAO,KAAK,OAAO,SAAS,EAEjE,KAAK,OAAO,WAAaA,EAAU,UACrC,KAAK,SAAS,WAAW,aAAa,MAAO,KAAK,OAAO,QAAQ,EAInE,KAAK,SAAS,UAAU,UAAU,OAAO,6BAA8B,KAAK,OAAO,QAAU,MAAM,EAGnG,KAAK,SAAS,UAAU,UAAU,OAAO,wCAAyC,KAAK,OAAO,cAAgB,YAAY,EAC1H,KAAK,SAAS,UAAU,UAAU,OAAO,sCAAuC,KAAK,OAAO,cAAgB,UAAU,EAGtH,KAAK,SAAS,UAAU,UAAU,OAAO,wCAAyC,KAAK,OAAO,OAAS,OAAO,EAC9G,KAAK,SAAS,UAAU,UAAU,OAAO,wCAAyC,KAAK,OAAO,OAAS,OAAO,EAG9G,KAAK,SAAS,SAAS,UAAU,OAAO,qCAAsC,KAAK,OAAO,IAAI,GAG1F,KAAK,OAAO,cAAgBA,EAAU,aAAe,KAAK,OAAO,cAAgBA,EAAU,cAC7F,KAAK,cAAA,EAIH,KAAK,OAAO,OAASA,EAAU,QACjCvB,EAAA,KAAK,iBAAL,MAAAA,EAAqB,WAAW,KAAK,OAAO,OAE1C,KAAK,OAAO,cAAgBuB,EAAU,eACxCT,EAAA,KAAK,iBAAL,MAAAA,EAAqB,kBAAkB,KAAK,OAAO,eAKnD,KAAK,OAAO,gBAAkBS,EAAU,eACxC,KAAK,OAAO,cAAgBA,EAAU,aACtC,KAAK,OAAO,aAAeA,EAAU,YACrC,KAAK,OAAO,gBAAkBA,EAAU,eACxC,KAAK,OAAO,cAAgBA,EAAU,cAEtC,KAAK,cAAA,EAIH,KAAK,OAAO,OAASA,EAAU,KACjC,KAAK,YAAA,UACI,KAAK,UACd,KAAK,QAAQ,aAAa,KAAK,MAAM,EAGjC,KAAK,OAAO,aAAeA,EAAU,cACvCV,EAAA,KAAK,aAAL,MAAAA,EAAiB,UACjB,KAAK,WAAa,KACd,KAAK,OAAO,aACd,KAAK,WAAa,IAAI7B,EAAW,KAAK,SAAS,SAAS,KAM1D,KAAK,OAAO,eAAiBuC,EAAU,cACvC,KAAK,OAAO,uBAAyBA,EAAU,yBAE/CP,EAAA,KAAK,qBAAL,MAAAA,EAAyB,UACzB,KAAK,mBAAqB,MAC1BD,EAAA,KAAK,iBAAL,MAAAA,EAAqB,SACrB,KAAK,eAAiB,KACtB,KAAK,SAAS,UAAU,UAAU,OAAO,2CAA2C,EACpF,KAAK,SAAS,UAAU,UAAU,OAAO,qCAAqC,EAC9E,KAAK,SAAS,UAAU,UAAU,OAAO,sCAAsC,EAE3E,KAAK,OAAO,eAAc,CAC5B,MAAMa,EAAWlD,EACf,KAAK,OAAO,qBACZ,CACE,SAAU,IAAA,OAAM,OAAA1F,EAAA,KAAK,UAAL,YAAAA,EAAc,UAC9B,UAAW,IAAA,OAAM,OAAAA,EAAA,KAAK,UAAL,YAAAA,EAAc,WAC/B,QAAS,IAAA,OAAM,OAAAA,EAAA,KAAK,UAAL,YAAAA,EAAc,YAAU,CACzC,EAEF,KAAK,eAAiB4I,EAAS,QAC/B,KAAK,mBAAqBA,EAAS,OACnC,KAAK,SAAS,UAAU,YAAY,KAAK,cAAc,EACvD,KAAK,yBAAA,CACP,CAKA,KAAK,OAAO,kBAAoBL,EAAU,iBAC5C,KAAK,eAAe,KAAK,OAAO,eAAe,EAI7C,KAAK,OAAO,mBAAqBA,EAAU,kBAC7C,KAAK,kBAAA,EAIH,KAAK,OAAO,iBAAmBA,EAAU,kBAC3CM,EAAA,KAAK,oBAAL,MAAAA,EAAwB,UACxB,KAAK,kBAAoB,KACrB,KAAK,OAAO,gBACd,KAAK,sBAAA,IAKTC,EAAA,KAAK,kBAAL,MAAAA,EAAsB,aACpB,KAAK,OAAO,YACZ,KAAK,OAAO,aACZ,KAAK,OAAO,kBACZ,KAAK,OAAO,MAId,KAAK,eAAe,KAAK,MAAM,QAAQ,CACzC,CAEA,SAAgB,4BACd9I,EAAA,KAAK,iBAAL,MAAAA,EAAqB,WACrBgH,EAAA,KAAK,eAAL,MAAAA,EAAmB,WACnBc,EAAA,KAAK,UAAL,MAAAA,EAAc,UACd,KAAK,QAAU,MACfD,EAAA,KAAK,aAAL,MAAAA,EAAiB,WACjBG,EAAA,KAAK,oBAAL,MAAAA,EAAwB,WACxBD,EAAA,KAAK,oBAAL,MAAAA,EAAwB,WACxBc,EAAA,KAAK,kBAAL,MAAAA,EAAsB,UACtB,KAAK,OAAO,QAAA,EACZ,KAAK,YAAY,QAAA,GACjBC,EAAA,KAAK,iBAAL,MAAAA,EAAqB,cACrBC,EAAA,KAAK,mBAAL,MAAAA,EAAuB,aACvB,KAAK,iBAAmB,MACxBC,EAAA,KAAK,qBAAL,MAAAA,EAAyB,UACzB,KAAK,mBAAqB,MAC1BC,EAAA,KAAK,iBAAL,MAAAA,EAAqB,SACjB,KAAK,qBAAqB,aAAa,KAAK,mBAAmB,EAC/D,KAAK,qBAAqB,aAAa,KAAK,mBAAmB,EAGnE,KAAK,SAAS,UAAU,UAAY,GACpC,KAAK,SAAS,UAAU,gBAAgB,MAAM,EAC9C,KAAK,SAAS,UAAU,gBAAgB,YAAY,EACpD,KAAK,SAAS,UAAU,UAAY,KAAK,SAAS,UAAU,UACzD,MAAM,GAAG,EACT,OAAQC,GAAM,CAACA,EAAE,WAAW,iBAAiB,CAAC,EAC9C,KAAK,GAAG,CACb,CAIQ,SAASlG,EAA8B,CAC7CA,EAAU,UAAY,GAGtB,MAAMmG,EAAc,8BAA8B,KAAK,OAAO,WAAW,GACzEnG,EAAU,UAAU,IAAI,4BAA6BmG,CAAW,EAE5D,KAAK,OAAO,OAAS,SAASnG,EAAU,UAAU,IAAI,uCAAuC,EAC7F,KAAK,OAAO,OAAS,SAASA,EAAU,UAAU,IAAI,uCAAuC,EAC7F,KAAK,OAAO,QAAU,QAAQA,EAAU,UAAU,IAAI,4BAA4B,EAEtFA,EAAU,UAAU,IAAI,yBAAyB,EAEjDkF,GAAiBlF,CAAS,EAG1B,MAAMQ,EAAWhF,EAAc,MAAO,0BAA0B,EAE5D,KAAK,OAAO,MAAMgF,EAAS,UAAU,IAAI,oCAAoC,EAGjF,MAAMoC,EAAUpH,EAAc,MAAO,yBAAyB,EAGxD4K,EAAc5K,EAAc,MAAO,+CAAgD,CACvF,IAAK,KAAK,OAAO,UACjB,UAAW,QACX,KAAM,KAAA,CACP,EAGK6K,EAAO7K,EAAc,MAAO,sBAAsB,EACxDmD,EAAe0H,EAAM,KAAK,MAAM,SAAU,KAAK,OAAO,WAAW,EAGjE,MAAMC,EAAa9K,EAAc,MAAO,8CAA+C,CACrF,IAAK,KAAK,OAAO,SACjB,UAAW,QACX,KAAM,KAAA,CACP,EAED6K,EAAK,YAAYC,CAAU,EAC3B1D,EAAQ,OAAOwD,EAAaC,CAAI,EAChC7F,EAAS,YAAYoC,CAAO,EAC5B5C,EAAU,YAAYQ,CAAQ,EAG9B,MAAMhB,EAASD,EAAa,KAAK,OAAO,YAAa,KAAK,OAAO,YAAa,KAAK,MAAM,QAAQ,EACjGS,EAAU,YAAYR,CAAM,EAE5B,MAAM+G,EAAa/G,EAAO,cAAc,8BAA8B,EAGtE,IAAIlH,EAAkC,KAClCC,EAAiC,KAErC,GAAI,KAAK,OAAO,cAAe,CAC7B,MAAMH,EAAS8K,EACb,KAAK,OAAO,YACZ,KAAK,OAAO,WACZ,KAAK,OAAO,cACZ,KAAK,OAAO,WAAA,EAEd5K,EAAcF,EAAO,OACrBG,EAAaH,EAAO,MACpB4H,EAAU,OAAO1H,EAAaC,CAAU,CAC1C,CAEA,KAAK,SAAW,CACd,UAAAyH,EACA,SAAAQ,EACA,QAAAoC,EACA,YAAAwD,EACA,WAAAE,EACA,KAAAD,EACA,OAAA7G,EACA,WAAA+G,EACA,YAAAjO,EACA,WAAAC,CAAA,CAEJ,CAEQ,aAAoB,CAE1B,KAAK,eAAiB,IAAIwH,EACxB,KAAK,SAAS,UACd,KAAK,SAAS,OACd,KAAK,OAAO,KACZ,KAAK,OAAO,YACZ,CACE,iBAAmByG,GAAQ,KAAK,eAAeA,CAAG,EAClD,YAAa,IAAM,KAAK,YAAA,EACxB,UAAW,IAAM,KAAK,UAAA,CAAU,CAClC,EAIF,KAAK,gBAAkB,IAAIlC,GACzB,KAAK,SAAS,OACd,KAAK,OAAO,YACZ,KAAK,OAAO,aACZ,KAAK,OAAO,kBACZ,KAAK,OAAO,KACZ,CACE,iBAAmBkC,GAAQ,KAAK,eAAeA,CAAG,EAClD,YAAa,IAAM,KAAK,MAAM,SAC9B,SAAU,IAAA,OAAM,OAAAxJ,EAAA,KAAK,UAAL,YAAAA,EAAc,UAC9B,UAAW,IAAA,OAAM,OAAAA,EAAA,KAAK,UAAL,YAAAA,EAAc,WAC/B,YAAa,IAAA,OAAM,OAAAA,EAAA,KAAK,UAAL,YAAAA,EAAc,YAAU,CAC7C,EAIE,KAAK,OAAO,MACd,KAAK,SAAA,EAIH,KAAK,OAAO,mBACd,KAAK,SAAS,UAAU,UAAU,IAAI,2CAA2C,EACjF,KAAK,kBAAoB,IAAI4G,GAC3B,KAAK,SAAS,UACb6C,GAAiB,CAChB,KAAK,MAAM,aAAeA,EAC1BC,EAAS,KAAK,OAAO,mBAAoBD,CAAY,CACvD,CAAA,GAKA,KAAK,OAAO,gBACd,KAAK,sBAAA,EAIH,KAAK,OAAO,YACd,KAAK,mBAAA,CAET,CAEQ,UAAiB,CA2BvB,GA1BA,KAAK,QAAU,IAAIlG,GACjB,KAAK,SAAS,SACd,KAAK,SAAS,UACd,KAAK,OACJQ,GAAU,CACT,KAAK,MAAM,UAAYA,EACvB,KAAK,SAAA,EACL2F,EAAS,KAAK,OAAO,OAAQ3F,CAAK,CACpC,EACA,IAAM,KAAK,SAAA,CAAS,EAIlB,KAAK,OAAO,aACd,KAAK,WAAa,IAAIiC,EAAW,KAAK,SAAS,SAAS,GAI1D,KAAK,aAAe,IAAIpB,EACtB,KAAK,SAAS,UACd,KAAK,SAAS,OACd,KAAK,QACL,IAAA,OAAM,OAAA5E,EAAA,KAAK,aAAL,YAAAA,EAAiB,OAAK,EAI1B,KAAK,OAAO,aAAc,CAC5B,MAAM4I,EAAWlD,EACf,KAAK,OAAO,qBACZ,CACE,SAAU,IAAA,OAAM,OAAA1F,EAAA,KAAK,UAAL,YAAAA,EAAc,UAC9B,UAAW,IAAA,OAAM,OAAAA,EAAA,KAAK,UAAL,YAAAA,EAAc,WAC/B,QAAS,IAAA,OAAM,OAAAA,EAAA,KAAK,UAAL,YAAAA,EAAc,YAAU,CACzC,EAEF,KAAK,eAAiB4I,EAAS,QAC/B,KAAK,mBAAqBA,EAAS,OACnC,KAAK,SAAS,UAAU,YAAY,KAAK,cAAc,EAEvD,KAAK,yBAAA,CACP,CACF,CAEQ,0BAAiC,CACvC,MAAMY,EAAM,KAAK,OAAO,qBACxB,KAAK,SAAS,UAAU,UAAU,OAAO,4CAA6CA,IAAQ,WAAW,EACzG,KAAK,SAAS,UAAU,UAAU,OAAO,sCAAuCA,EAAI,WAAW,MAAM,CAAC,EACtG,KAAK,SAAS,UAAU,UAAU,OAAO,uCAAwCA,EAAI,SAAS,OAAO,CAAC,CACxG,CAEQ,uBAA8B,CAEhC,KAAK,sBACP,aAAa,KAAK,mBAAmB,EACrC,KAAK,oBAAsB,KAC3B,KAAK,SAAS,OAAO,MAAM,WAAa,GACxC,KAAK,SAAS,KAAK,MAAM,WAAa,IAIxC,MAAMG,EAAgB,EACtB,KAAK,kBAAoB,GACzB,KAAK,eAAeA,CAAa,EACjC,KAAK,kBAAoB,GAEzB,KAAK,kBAAoB,IAAI1C,GAC3B,KAAK,SAAS,UACd,KAAK,OAAO,gBACZ,KAAK,OAAO,aACZ,KAAK,OAAO,cACZ,KAAK,OAAO,YACX2C,GAA4B,CACtBA,IAEH,KAAK,SAAS,OAAO,MAAM,WACzB,QAAQ,KAAK,OAAO,eAAe,MAAM,KAAK,OAAO,aAAa,SAAS,KAAK,OAAO,eAAe,MAAM,KAAK,OAAO,aAAa,GACvI,KAAK,SAAS,KAAK,MAAM,WACvB,aAAa,KAAK,OAAO,eAAe,MAAM,KAAK,OAAO,aAAa,IAG3E,KAAK,eAAe,KAAK,OAAO,eAAe,EAE1CA,IACH,KAAK,oBAAsB,WAAW,IAAM,CAC1C,KAAK,oBAAsB,KAC3B,KAAK,SAAS,OAAO,MAAM,WAAa,GACxC,KAAK,SAAS,KAAK,MAAM,WAAa,EACxC,EAAG,KAAK,OAAO,eAAe,EAElC,CAAA,CAEJ,CAEQ,YAAmB,CACzB,MAAMhN,EAAY,KAAK,gBAAgB,KAAK,OAAO,SAAS,EACtDC,EAAW,KAAK,gBAAgB,KAAK,OAAO,QAAQ,EAEtD,KAAK,OAAO,UAAY,OAAO,qBAAyB,KAE1D,KAAK,iBAAmB,IAAI,qBACzB8G,GAAY,OACX,UAAWC,KAASD,EACdC,EAAM,iBACR,KAAK,SAAS,YAAY,IAAMhH,EAChC,KAAK,SAAS,WAAW,IAAMC,GAC/BmD,EAAA,KAAK,mBAAL,MAAAA,EAAuB,aACvB,KAAK,iBAAmB,KAG9B,EACA,CAAE,UAAW,CAAA,CAAE,EAEjB,KAAK,iBAAiB,QAAQ,KAAK,SAAS,SAAS,IAErD,KAAK,SAAS,YAAY,IAAMpD,EAChC,KAAK,SAAS,WAAW,IAAMC,GAGjC,KAAK,0BAA0B,GAAM,EAAI,CAC3C,CAMQ,0BAA0BgN,EAAwBC,EAA6B,CAErF,KAAK,YAAY,QAAA,EAEjB,IAAIC,EAAe,CAACF,EAChBG,EAAc,CAACF,EAEnB,MAAMG,EAAa,IAAM,CACnBF,GAAgBC,GAClB,KAAK,cAAA,CAET,EAEME,EAAe,IAAM,CACpBH,IACHA,EAAe,GACfE,EAAA,EAEJ,EACME,EAAc,IAAM,CACnBH,IACHA,EAAc,GACdC,EAAA,EAEJ,EAEMG,EAAgB,IAAM,CAC1B,QAAQ,KAAK,wCAAwC,KAAK,SAAS,YAAY,GAAG,GAAG,EAChFL,IACHA,EAAe,GACfE,EAAA,EAEJ,EACMI,EAAe,IAAM,CACzB,QAAQ,KAAK,wCAAwC,KAAK,SAAS,WAAW,GAAG,GAAG,EAC/EL,IACHA,EAAc,GACdC,EAAA,EAEJ,EAEA,KAAK,YAAY,GAAG,KAAK,SAAS,YAAa,OAAQC,CAAY,EACnE,KAAK,YAAY,GAAG,KAAK,SAAS,WAAY,OAAQC,CAAW,EACjE,KAAK,YAAY,GAAG,KAAK,SAAS,YAAa,QAASC,CAAa,EACrE,KAAK,YAAY,GAAG,KAAK,SAAS,WAAY,QAASC,CAAY,EAG/D,KAAK,SAAS,YAAY,UAAY,KAAK,SAAS,YAAY,KAAKH,EAAA,EACrE,KAAK,SAAS,WAAW,UAAY,KAAK,SAAS,WAAW,KAAKC,EAAA,CACzE,CAEQ,eAAsB,CAC5B,GAAI,KAAK,MAAM,QAAS,OACxB,KAAK,MAAM,QAAU,GAGrB,KAAM,CAAE,aAAAG,EAAc,cAAAC,CAAA,EAAkB,KAAK,SAAS,YAClDD,GAAgBC,IAClB,KAAK,SAAS,QAAQ,MAAM,YAAc,GAAGD,CAAY,MAAMC,CAAa,IAG9E,KAAK,SAAS,UAAU,UAAU,OAAO,yBAAyB,EAClEb,EAAS,KAAK,OAAO,OAAO,CAC9B,CAEQ,iBAA4C,CAClD,GAAI,CAAC,KAAK,SAAW,KAAK,QAAQ,QAAA,GAAa,EAAG,OAClD,MAAMc,EAAM,KAAK,QAAQ,OAAA,EACnBC,EAAO,KAAK,QAAQ,iBAAA,EAC1B,MAAO,CACL,MAAO,KAAK,QAAQ,QAAA,EACpB,KAAMD,EAAI,EACV,KAAMA,EAAI,EACV,eAAgBC,EAAK,MACrB,gBAAiBA,EAAK,MAAA,CAE1B,CAEQ,UAAiB,CACvB9I,EAAe,KAAK,SAAS,KAAM,KAAK,MAAM,SAAU,KAAK,OAAO,YAAa,KAAK,gBAAA,CAAiB,CACzG,CAEQ,eAAeE,EAAwB,CAC7C,KAAK,MAAM,SAAW9F,EAAc8F,CAAQ,EAC5CF,EAAe,KAAK,SAAS,KAAM,KAAK,MAAM,SAAU,KAAK,OAAO,YAAa,KAAK,gBAAA,CAAiB,EACvGI,GAAqB,KAAK,SAAS,OAAQ,KAAK,MAAM,SAAU,KAAK,OAAO,WAAW,EACvFkG,GAAgB,KAAK,SAAS,OAAQ,KAAK,MAAM,QAAQ,EACzDzB,EACE,KAAK,SAAS,YACd,KAAK,SAAS,WACd,KAAK,MAAM,SACX,KAAK,OAAO,WAAA,EAGT,KAAK,mBACRkD,EAAS,KAAK,OAAO,QAAS,KAAK,MAAM,QAAQ,CAErD,CAEQ,aAAoB,CAC1B,KAAK,MAAM,WAAa,GACxB,KAAK,SAAS,UAAU,UAAU,IAAI,qCAAqC,CAC7E,CAEQ,WAAkB,CACxB,KAAK,MAAM,WAAa,GACxB,KAAK,SAAS,UAAU,UAAU,OAAO,qCAAqC,CAChF,CAEQ,gBAAgBhJ,EAAqB,CAC3C,GAAI,KAAK,OAAO,WAAY,CAC1B,MAAMmD,EAAQ,KAAK,SAAS,UAAU,sBAAA,EAAwB,OAAS,IACvE,OAAOpD,GAAmBC,EAAKmD,EAAO,KAAK,OAAO,UAAU,CAC9D,CACA,OAAOnD,CACT,CAEQ,eAAsB,SAC5B,MAAMgK,EAAW,SAAS,gBAAkB,KAAK,SAAS,OAC1D,KAAK,SAAS,OAAO,OAAA,EACrB,MAAMlI,EAASD,EAAa,KAAK,OAAO,YAAa,KAAK,OAAO,YAAa,KAAK,MAAM,QAAQ,EACjG,KAAK,SAAS,UAAU,YAAYC,CAAM,EAC1C,KAAK,SAAS,OAASA,EACvB,KAAK,SAAS,WAAaA,EAAO,cAAc,8BAA8B,GAG9ExC,EAAA,KAAK,iBAAL,MAAAA,EAAqB,UACrB,KAAK,eAAiB,IAAI+C,EACxB,KAAK,SAAS,UACd,KAAK,SAAS,OACd,KAAK,OAAO,KACZ,KAAK,OAAO,YACZ,CACE,iBAAmByG,GAAQ,KAAK,eAAeA,CAAG,EAClD,YAAa,IAAM,KAAK,YAAA,EACxB,UAAW,IAAM,KAAK,UAAA,CAAU,CAClC,GAGFxC,EAAA,KAAK,kBAAL,MAAAA,EAAsB,UACtB,KAAK,gBAAkB,IAAIM,GACzB,KAAK,SAAS,OACd,KAAK,OAAO,YACZ,KAAK,OAAO,aACZ,KAAK,OAAO,kBACZ,KAAK,OAAO,KACZ,CACE,iBAAmBkC,GAAQ,KAAK,eAAeA,CAAG,EAClD,YAAa,IAAM,KAAK,MAAM,SAC9B,SAAU,IAAA,OAAM,OAAAxJ,EAAA,KAAK,UAAL,YAAAA,EAAc,UAC9B,UAAW,IAAA,OAAM,OAAAA,EAAA,KAAK,UAAL,YAAAA,EAAc,WAC/B,YAAa,IAAA,OAAM,OAAAA,EAAA,KAAK,UAAL,YAAAA,EAAc,YAAU,CAC7C,EAGE,KAAK,cAAgB,KAAK,UAC5B,KAAK,aAAa,QAAA,EAClB,KAAK,aAAe,IAAI4E,EACtB,KAAK,SAAS,UACd,KAAK,SAAS,OACd,KAAK,QACL,IAAA,OAAM,OAAA5E,EAAA,KAAK,aAAL,YAAAA,EAAiB,OAAK,GAK5B0K,GACF,KAAK,SAAS,OAAO,MAAA,CAEzB,CAEQ,eAAsB,SAM5B,IALA1K,EAAA,KAAK,SAAS,cAAd,MAAAA,EAA2B,UAC3BgH,EAAA,KAAK,SAAS,aAAd,MAAAA,EAA0B,SAC1B,KAAK,SAAS,YAAc,KAC5B,KAAK,SAAS,WAAa,KAEvB,KAAK,OAAO,cAAe,CAC7B,MAAM5L,EAAS8K,EACb,KAAK,OAAO,YACZ,KAAK,OAAO,WACZ,KAAK,OAAO,cACZ,KAAK,OAAO,WAAA,EAEd,KAAK,SAAS,YAAc9K,EAAO,OACnC,KAAK,SAAS,WAAaA,EAAO,MAClC,KAAK,SAAS,UAAU,OAAOA,EAAO,OAAQA,EAAO,KAAK,EAC1DoL,EAAsBpL,EAAO,OAAQA,EAAO,MAAO,KAAK,MAAM,SAAU,KAAK,OAAO,WAAW,CACjG,CACF,CAEQ,aAAoB,gBAC1B4E,EAAA,KAAK,eAAL,MAAAA,EAAmB,UACnB,KAAK,aAAe,MACpBgH,EAAA,KAAK,aAAL,MAAAA,EAAiB,UACjB,KAAK,WAAa,MAClBc,EAAA,KAAK,qBAAL,MAAAA,EAAyB,UACzB,KAAK,mBAAqB,MAC1BD,EAAA,KAAK,iBAAL,MAAAA,EAAqB,SACrB,KAAK,eAAiB,MACtBG,EAAA,KAAK,UAAL,MAAAA,EAAc,UACd,KAAK,QAAU,KACf,KAAK,SAAS,UAAU,UAAU,OAAO,2CAA2C,EACpF,KAAK,SAAS,UAAU,UAAU,OAAO,qCAAqC,EAC9E,KAAK,SAAS,UAAU,UAAU,OAAO,sCAAsC,EAE3E,KAAK,OAAO,MACd,KAAK,SAAA,CAET,CAEQ,mBAA0B,QAChChI,EAAA,KAAK,oBAAL,MAAAA,EAAwB,UACxB,KAAK,kBAAoB,KACzB,KAAK,SAAS,UAAU,UAAU,OAAO,2CAA2C,EAEhF,KAAK,OAAO,mBACd,KAAK,SAAS,UAAU,UAAU,IAAI,2CAA2C,EACjF,KAAK,kBAAoB,IAAI4G,GAC3B,KAAK,SAAS,UACb6C,GAAiB,CAChB,KAAK,MAAM,aAAeA,EAC1BC,EAAS,KAAK,OAAO,mBAAoBD,CAAY,CACvD,CAAA,EAGN,CAEQ,oBAA2B,CAC7B,OAAO,eAAmB,MAE9B,KAAK,eAAiB,IAAI,eAAe,IAAM,CAEzC,KAAK,qBAAqB,aAAa,KAAK,mBAAmB,EACnE,KAAK,oBAAsB,WAAW,IAAM,CAC1C,GAAI,KAAK,OAAO,WAAY,CAC1B,MAAMkB,EAAe,KAAK,gBAAgB,KAAK,OAAO,SAAS,EACzDC,EAAc,KAAK,gBAAgB,KAAK,OAAO,QAAQ,EAEzD,KAAK,SAAS,YAAY,MAAQD,IACpC,KAAK,SAAS,YAAY,IAAMA,GAE9B,KAAK,SAAS,WAAW,MAAQC,IACnC,KAAK,SAAS,WAAW,IAAMA,EAEnC,CACA,KAAK,oBAAsB,IAC7B,EAAG,GAAG,CACR,CAAC,EAED,KAAK,eAAe,QAAQ,KAAK,SAAS,SAAS,EACrD,CACF,CAEA,SAASlB,EAA8BmB,KAA2CC,EAAe,CAC/F,GAAKD,EACL,GAAI,CACFA,EAAG,GAAGC,CAAI,CACZ,OAASC,EAAK,CACZ,QAAQ,MAAM,iCAAkCA,CAAG,CACrD,CACF,CAEA,SAASpC,GAA+BqC,EAAkBC,EAA2B,CACnF,GAAID,IAAMC,EAAG,MAAO,GACpB,GAAI,CAACD,GAAK,CAACC,EAAG,MAAO,GACrB,MAAMC,EAAQ,OAAO,KAAKF,CAAC,EACrBG,EAAQ,OAAO,KAAKF,CAAC,EAC3B,GAAIC,EAAM,SAAWC,EAAM,OAAQ,MAAO,GAC1C,UAAWvM,KAAOsM,EAChB,GAAIF,EAAEpM,CAAG,IAAMqM,EAAErM,CAAG,EAAG,MAAO,GAEhC,MAAO,EACT,ijWC1zBA,MAAMwM,UAAsBjD,EAAkB,CAC5C,OAAO,SAASkD,EAA6C,CAC3D,GAAI,CAAC/M,EAAA,EAAa,MAAO,CAAA,EACzBF,EAAakN,EAAO,EAGpB,MAAMC,GADSF,GAAQ,UACC,iBAA8B,mCAAmC,EACnFG,EAAqC,CAAA,EAE3C,OAAAD,EAAS,QAASjP,GAAO,CACvB,MAAMnB,EAASkB,GAAoBC,CAAE,EACrCkP,EAAU,KAAK,IAAIJ,EAAc9O,EAAInB,CAAM,CAAC,CAC9C,CAAC,EAEMqQ,CACT,CAEA,YAAY1M,EAA8B3D,EAA6B,CACrEiD,EAAakN,EAAO,EACpB,MAAMxM,EAAQ3D,CAAM,CACtB,CACF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { LabelPosition, Orientation } from '../core/types';
|
|
2
|
+
export declare function createLabels(beforeText: string, afterText: string, position: LabelPosition, orientation: Orientation): {
|
|
3
|
+
before: HTMLElement;
|
|
4
|
+
after: HTMLElement;
|
|
5
|
+
};
|
|
6
|
+
export declare function updateLabelVisibility(beforeLabel: HTMLElement | null, afterLabel: HTMLElement | null, position: number, orientation: Orientation): void;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { CIBeforeAfterViewerProps } from './types';
|
|
2
|
+
import type { CIBeforeAfterInstance } from '../core/types';
|
|
3
|
+
export declare const CIBeforeAfterViewer: import("react").ForwardRefExoticComponent<CIBeforeAfterViewerProps & import("react").RefAttributes<CIBeforeAfterInstance>>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var z=Object.create;var R=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var h=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty;var B=(e,o,l,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let a of A(o))!w.call(e,a)&&a!==l&&R(e,a,{get:()=>o[a],enumerable:!(i=P(o,a))||i.enumerable});return e};var b=(e,o,l)=>(l=e!=null?z(h(e)):{},B(o||!e||!e.__esModule?R(l,"default",{value:e,enumerable:!0}):l,e));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const F=require("react/jsx-runtime"),s=require("react"),Z=s.forwardRef(function(o,l){const{className:i,style:a,onSlide:c,onZoom:d,onFullscreenChange:y,onReady:p,...t}=o,m=s.useRef(null),n=s.useRef(null),f=s.useRef(null);return s.useImperativeHandle(l,()=>({getElements:()=>{if(!n.current)throw new Error("CIBeforeAfter: instance not yet initialized");return n.current.getElements()},setPosition:r=>{var u;return(u=n.current)==null?void 0:u.setPosition(r)},getPosition:()=>{var r;return((r=n.current)==null?void 0:r.getPosition())??50},setZoom:r=>{var u;return(u=n.current)==null?void 0:u.setZoom(r)},getZoom:()=>{var r;return((r=n.current)==null?void 0:r.getZoom())??1},resetZoom:()=>{var r;return(r=n.current)==null?void 0:r.resetZoom()},enterFullscreen:()=>{var r;return(r=n.current)==null?void 0:r.enterFullscreen()},exitFullscreen:()=>{var r;return(r=n.current)==null?void 0:r.exitFullscreen()},isFullscreen:()=>{var r;return((r=n.current)==null?void 0:r.isFullscreen())??!1},update:r=>{var u;return(u=n.current)==null?void 0:u.update(r)},destroy:()=>{var r;return(r=n.current)==null?void 0:r.destroy()}})),s.useEffect(()=>{if(!m.current)return;let r=!1,u=null;return import("./js-cloudimage-before-after").then(({CIBeforeAfterCore:C})=>{if(r||!m.current)return;const S={...t,onSlide:c,onZoom:d,onFullscreenChange:y,onReady:p};u=new C(m.current,S),n.current=u,f.current&&(u.update(f.current),f.current=null)},()=>{}),()=>{r=!0,u==null||u.destroy(),n.current=null}},[]),s.useEffect(()=>{const r={...t,onSlide:c,onZoom:d,onFullscreenChange:y,onReady:p};if(!n.current){f.current=r;return}n.current.update(r)},[t.beforeSrc,t.afterSrc,t.beforeAlt,t.afterAlt,t.mode,t.orientation,t.initialPosition,t.zoom,t.zoomMax,t.zoomMin,t.theme,t.handleStyle,t.labels,t.labelPosition,t.fullscreenButton,t.lazyLoad,t.zoomControls,t.zoomControlsPosition,t.scrollHint,t.keyboardStep,t.keyboardLargeStep,t.animate,t.animateOnce,t.cloudimage,c,d,y,p]),F.jsx("div",{ref:m,className:i,style:a})});function E(e){const o=s.useRef(null),l=s.useRef(null),i=s.useRef(null);return s.useEffect(()=>{if(!o.current)return;let a=!1,c=null;return import("./js-cloudimage-before-after").then(({CIBeforeAfterCore:d})=>{a||!o.current||(c=new d(o.current,e),l.current=c,i.current&&(c.update(i.current),i.current=null))},()=>{}),()=>{a=!0,c==null||c.destroy(),l.current=null}},[]),s.useEffect(()=>{if(!l.current){i.current=e;return}l.current.update(e)},[e.beforeSrc,e.afterSrc,e.beforeAlt,e.afterAlt,e.mode,e.orientation,e.initialPosition,e.zoom,e.zoomMax,e.zoomMin,e.theme,e.handleStyle,e.labels,e.labelPosition,e.fullscreenButton,e.lazyLoad,e.zoomControls,e.zoomControlsPosition,e.scrollHint,e.keyboardStep,e.keyboardLargeStep,e.animate,e.animateOnce,e.cloudimage,e.onSlide,e.onZoom,e.onFullscreenChange,e.onReady]),{containerRef:o,instance:l}}exports.CIBeforeAfterViewer=Z;exports.useCIBeforeAfter=E;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/react/ci-before-after-viewer.tsx","../../src/react/use-ci-before-after.ts"],"sourcesContent":["import { forwardRef, useRef, useEffect, useImperativeHandle } from 'react';\nimport type { CIBeforeAfterViewerProps, CIBeforeAfterViewerRef } from './types';\nimport type { CIBeforeAfterConfig, CIBeforeAfterInstance } from '../core/types';\n\nexport const CIBeforeAfterViewer = forwardRef<CIBeforeAfterViewerRef, CIBeforeAfterViewerProps>(\n function CIBeforeAfterViewer(props, ref) {\n const {\n className,\n style,\n onSlide,\n onZoom,\n onFullscreenChange,\n onReady,\n ...configProps\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const instanceRef = useRef<CIBeforeAfterInstance | null>(null);\n const pendingConfigRef = useRef<Partial<CIBeforeAfterConfig> | null>(null);\n\n useImperativeHandle(ref, () => ({\n getElements: () => {\n if (!instanceRef.current) throw new Error('CIBeforeAfter: instance not yet initialized');\n return instanceRef.current.getElements();\n },\n setPosition: (p: number) => instanceRef.current?.setPosition(p),\n getPosition: () => instanceRef.current?.getPosition() ?? 50,\n setZoom: (l: number) => instanceRef.current?.setZoom(l),\n getZoom: () => instanceRef.current?.getZoom() ?? 1,\n resetZoom: () => instanceRef.current?.resetZoom(),\n enterFullscreen: () => instanceRef.current?.enterFullscreen(),\n exitFullscreen: () => instanceRef.current?.exitFullscreen(),\n isFullscreen: () => instanceRef.current?.isFullscreen() ?? false,\n update: (c: Partial<CIBeforeAfterConfig>) => instanceRef.current?.update(c),\n destroy: () => instanceRef.current?.destroy(),\n }));\n\n useEffect(() => {\n if (!containerRef.current) return;\n\n let cancelled = false;\n let inst: CIBeforeAfterInstance | null = null;\n\n import('../core/ci-before-after').then(\n ({ CIBeforeAfterCore }) => {\n // BUG-04: Guard against mount/unmount race\n if (cancelled || !containerRef.current) return;\n\n const config: CIBeforeAfterConfig = {\n ...configProps,\n onSlide,\n onZoom,\n onFullscreenChange,\n onReady,\n };\n\n inst = new CIBeforeAfterCore(containerRef.current, config);\n instanceRef.current = inst;\n\n // Apply any config changes that arrived during async import\n if (pendingConfigRef.current) {\n inst.update(pendingConfigRef.current);\n pendingConfigRef.current = null;\n }\n },\n () => { /* dynamic import failed — component stays empty */ },\n );\n\n return () => {\n cancelled = true;\n inst?.destroy();\n instanceRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Update on prop changes\n useEffect(() => {\n const config: Partial<CIBeforeAfterConfig> = {\n ...configProps,\n onSlide,\n onZoom,\n onFullscreenChange,\n onReady,\n };\n\n if (!instanceRef.current) {\n // Instance not yet initialized — store for later application\n pendingConfigRef.current = config;\n return;\n }\n\n instanceRef.current.update(config);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n configProps.beforeSrc,\n configProps.afterSrc,\n configProps.beforeAlt,\n configProps.afterAlt,\n configProps.mode,\n configProps.orientation,\n configProps.initialPosition,\n configProps.zoom,\n configProps.zoomMax,\n configProps.zoomMin,\n configProps.theme,\n configProps.handleStyle,\n configProps.labels,\n configProps.labelPosition,\n configProps.fullscreenButton,\n configProps.lazyLoad,\n configProps.zoomControls,\n configProps.zoomControlsPosition,\n configProps.scrollHint,\n configProps.keyboardStep,\n configProps.keyboardLargeStep,\n configProps.animate,\n configProps.animateOnce,\n configProps.cloudimage,\n onSlide,\n onZoom,\n onFullscreenChange,\n onReady,\n ]);\n\n return <div ref={containerRef} className={className} style={style} />;\n },\n);\n","import { useRef, useEffect } from 'react';\nimport type { CIBeforeAfterConfig, CIBeforeAfterInstance } from '../core/types';\n\nexport function useCIBeforeAfter(config: CIBeforeAfterConfig) {\n const containerRef = useRef<HTMLDivElement>(null);\n const instance = useRef<CIBeforeAfterInstance | null>(null);\n const pendingConfigRef = useRef<Partial<CIBeforeAfterConfig> | null>(null);\n\n useEffect(() => {\n if (!containerRef.current) return;\n\n let cancelled = false;\n let inst: CIBeforeAfterInstance | null = null;\n\n import('../core/ci-before-after').then(\n ({ CIBeforeAfterCore }) => {\n // BUG-04: Guard against mount/unmount race\n if (cancelled || !containerRef.current) return;\n inst = new CIBeforeAfterCore(containerRef.current, config);\n instance.current = inst;\n\n // Apply any config changes that arrived during async import\n if (pendingConfigRef.current) {\n inst.update(pendingConfigRef.current);\n pendingConfigRef.current = null;\n }\n },\n () => { /* dynamic import failed — hook stays empty */ },\n );\n\n return () => {\n cancelled = true;\n inst?.destroy();\n instance.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Update config when props change\n useEffect(() => {\n if (!instance.current) {\n // Instance not yet initialized — store for later application\n pendingConfigRef.current = config;\n return;\n }\n instance.current.update(config);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n config.beforeSrc,\n config.afterSrc,\n config.beforeAlt,\n config.afterAlt,\n config.mode,\n config.orientation,\n config.initialPosition,\n config.zoom,\n config.zoomMax,\n config.zoomMin,\n config.theme,\n config.handleStyle,\n config.labels,\n config.labelPosition,\n config.fullscreenButton,\n config.lazyLoad,\n config.zoomControls,\n config.zoomControlsPosition,\n config.scrollHint,\n config.keyboardStep,\n config.keyboardLargeStep,\n config.animate,\n config.animateOnce,\n config.cloudimage,\n config.onSlide,\n config.onZoom,\n config.onFullscreenChange,\n config.onReady,\n ]);\n\n return { containerRef, instance };\n}\n"],"names":["CIBeforeAfterViewer","forwardRef","props","ref","className","style","onSlide","onZoom","onFullscreenChange","onReady","configProps","containerRef","useRef","instanceRef","pendingConfigRef","useImperativeHandle","p","_a","l","c","useEffect","cancelled","inst","CIBeforeAfterCore","config","jsx","useCIBeforeAfter","instance"],"mappings":"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"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { jsx as S } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as P, useRef as c, useImperativeHandle as h, useEffect as p } from "react";
|
|
3
|
+
const F = P(
|
|
4
|
+
function(s, u) {
|
|
5
|
+
const {
|
|
6
|
+
className: a,
|
|
7
|
+
style: m,
|
|
8
|
+
onSlide: l,
|
|
9
|
+
onZoom: i,
|
|
10
|
+
onFullscreenChange: y,
|
|
11
|
+
onReady: z,
|
|
12
|
+
...t
|
|
13
|
+
} = s, d = c(null), n = c(null), f = c(null);
|
|
14
|
+
return h(u, () => ({
|
|
15
|
+
getElements: () => {
|
|
16
|
+
if (!n.current) throw new Error("CIBeforeAfter: instance not yet initialized");
|
|
17
|
+
return n.current.getElements();
|
|
18
|
+
},
|
|
19
|
+
setPosition: (r) => {
|
|
20
|
+
var o;
|
|
21
|
+
return (o = n.current) == null ? void 0 : o.setPosition(r);
|
|
22
|
+
},
|
|
23
|
+
getPosition: () => {
|
|
24
|
+
var r;
|
|
25
|
+
return ((r = n.current) == null ? void 0 : r.getPosition()) ?? 50;
|
|
26
|
+
},
|
|
27
|
+
setZoom: (r) => {
|
|
28
|
+
var o;
|
|
29
|
+
return (o = n.current) == null ? void 0 : o.setZoom(r);
|
|
30
|
+
},
|
|
31
|
+
getZoom: () => {
|
|
32
|
+
var r;
|
|
33
|
+
return ((r = n.current) == null ? void 0 : r.getZoom()) ?? 1;
|
|
34
|
+
},
|
|
35
|
+
resetZoom: () => {
|
|
36
|
+
var r;
|
|
37
|
+
return (r = n.current) == null ? void 0 : r.resetZoom();
|
|
38
|
+
},
|
|
39
|
+
enterFullscreen: () => {
|
|
40
|
+
var r;
|
|
41
|
+
return (r = n.current) == null ? void 0 : r.enterFullscreen();
|
|
42
|
+
},
|
|
43
|
+
exitFullscreen: () => {
|
|
44
|
+
var r;
|
|
45
|
+
return (r = n.current) == null ? void 0 : r.exitFullscreen();
|
|
46
|
+
},
|
|
47
|
+
isFullscreen: () => {
|
|
48
|
+
var r;
|
|
49
|
+
return ((r = n.current) == null ? void 0 : r.isFullscreen()) ?? !1;
|
|
50
|
+
},
|
|
51
|
+
update: (r) => {
|
|
52
|
+
var o;
|
|
53
|
+
return (o = n.current) == null ? void 0 : o.update(r);
|
|
54
|
+
},
|
|
55
|
+
destroy: () => {
|
|
56
|
+
var r;
|
|
57
|
+
return (r = n.current) == null ? void 0 : r.destroy();
|
|
58
|
+
}
|
|
59
|
+
})), p(() => {
|
|
60
|
+
if (!d.current) return;
|
|
61
|
+
let r = !1, o = null;
|
|
62
|
+
return import("./js-cloudimage-before-after").then(
|
|
63
|
+
({ CIBeforeAfterCore: b }) => {
|
|
64
|
+
if (r || !d.current) return;
|
|
65
|
+
const C = {
|
|
66
|
+
...t,
|
|
67
|
+
onSlide: l,
|
|
68
|
+
onZoom: i,
|
|
69
|
+
onFullscreenChange: y,
|
|
70
|
+
onReady: z
|
|
71
|
+
};
|
|
72
|
+
o = new b(d.current, C), n.current = o, f.current && (o.update(f.current), f.current = null);
|
|
73
|
+
},
|
|
74
|
+
() => {
|
|
75
|
+
}
|
|
76
|
+
), () => {
|
|
77
|
+
r = !0, o == null || o.destroy(), n.current = null;
|
|
78
|
+
};
|
|
79
|
+
}, []), p(() => {
|
|
80
|
+
const r = {
|
|
81
|
+
...t,
|
|
82
|
+
onSlide: l,
|
|
83
|
+
onZoom: i,
|
|
84
|
+
onFullscreenChange: y,
|
|
85
|
+
onReady: z
|
|
86
|
+
};
|
|
87
|
+
if (!n.current) {
|
|
88
|
+
f.current = r;
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
n.current.update(r);
|
|
92
|
+
}, [
|
|
93
|
+
t.beforeSrc,
|
|
94
|
+
t.afterSrc,
|
|
95
|
+
t.beforeAlt,
|
|
96
|
+
t.afterAlt,
|
|
97
|
+
t.mode,
|
|
98
|
+
t.orientation,
|
|
99
|
+
t.initialPosition,
|
|
100
|
+
t.zoom,
|
|
101
|
+
t.zoomMax,
|
|
102
|
+
t.zoomMin,
|
|
103
|
+
t.theme,
|
|
104
|
+
t.handleStyle,
|
|
105
|
+
t.labels,
|
|
106
|
+
t.labelPosition,
|
|
107
|
+
t.fullscreenButton,
|
|
108
|
+
t.lazyLoad,
|
|
109
|
+
t.zoomControls,
|
|
110
|
+
t.zoomControlsPosition,
|
|
111
|
+
t.scrollHint,
|
|
112
|
+
t.keyboardStep,
|
|
113
|
+
t.keyboardLargeStep,
|
|
114
|
+
t.animate,
|
|
115
|
+
t.animateOnce,
|
|
116
|
+
t.cloudimage,
|
|
117
|
+
l,
|
|
118
|
+
i,
|
|
119
|
+
y,
|
|
120
|
+
z
|
|
121
|
+
]), /* @__PURE__ */ S("div", { ref: d, className: a, style: m });
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
function Z(e) {
|
|
125
|
+
const s = c(null), u = c(null), a = c(null);
|
|
126
|
+
return p(() => {
|
|
127
|
+
if (!s.current) return;
|
|
128
|
+
let m = !1, l = null;
|
|
129
|
+
return import("./js-cloudimage-before-after").then(
|
|
130
|
+
({ CIBeforeAfterCore: i }) => {
|
|
131
|
+
m || !s.current || (l = new i(s.current, e), u.current = l, a.current && (l.update(a.current), a.current = null));
|
|
132
|
+
},
|
|
133
|
+
() => {
|
|
134
|
+
}
|
|
135
|
+
), () => {
|
|
136
|
+
m = !0, l == null || l.destroy(), u.current = null;
|
|
137
|
+
};
|
|
138
|
+
}, []), p(() => {
|
|
139
|
+
if (!u.current) {
|
|
140
|
+
a.current = e;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
u.current.update(e);
|
|
144
|
+
}, [
|
|
145
|
+
e.beforeSrc,
|
|
146
|
+
e.afterSrc,
|
|
147
|
+
e.beforeAlt,
|
|
148
|
+
e.afterAlt,
|
|
149
|
+
e.mode,
|
|
150
|
+
e.orientation,
|
|
151
|
+
e.initialPosition,
|
|
152
|
+
e.zoom,
|
|
153
|
+
e.zoomMax,
|
|
154
|
+
e.zoomMin,
|
|
155
|
+
e.theme,
|
|
156
|
+
e.handleStyle,
|
|
157
|
+
e.labels,
|
|
158
|
+
e.labelPosition,
|
|
159
|
+
e.fullscreenButton,
|
|
160
|
+
e.lazyLoad,
|
|
161
|
+
e.zoomControls,
|
|
162
|
+
e.zoomControlsPosition,
|
|
163
|
+
e.scrollHint,
|
|
164
|
+
e.keyboardStep,
|
|
165
|
+
e.keyboardLargeStep,
|
|
166
|
+
e.animate,
|
|
167
|
+
e.animateOnce,
|
|
168
|
+
e.cloudimage,
|
|
169
|
+
e.onSlide,
|
|
170
|
+
e.onZoom,
|
|
171
|
+
e.onFullscreenChange,
|
|
172
|
+
e.onReady
|
|
173
|
+
]), { containerRef: s, instance: u };
|
|
174
|
+
}
|
|
175
|
+
export {
|
|
176
|
+
F as CIBeforeAfterViewer,
|
|
177
|
+
Z as useCIBeforeAfter
|
|
178
|
+
};
|
|
179
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/react/ci-before-after-viewer.tsx","../../src/react/use-ci-before-after.ts"],"sourcesContent":["import { forwardRef, useRef, useEffect, useImperativeHandle } from 'react';\nimport type { CIBeforeAfterViewerProps, CIBeforeAfterViewerRef } from './types';\nimport type { CIBeforeAfterConfig, CIBeforeAfterInstance } from '../core/types';\n\nexport const CIBeforeAfterViewer = forwardRef<CIBeforeAfterViewerRef, CIBeforeAfterViewerProps>(\n function CIBeforeAfterViewer(props, ref) {\n const {\n className,\n style,\n onSlide,\n onZoom,\n onFullscreenChange,\n onReady,\n ...configProps\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const instanceRef = useRef<CIBeforeAfterInstance | null>(null);\n const pendingConfigRef = useRef<Partial<CIBeforeAfterConfig> | null>(null);\n\n useImperativeHandle(ref, () => ({\n getElements: () => {\n if (!instanceRef.current) throw new Error('CIBeforeAfter: instance not yet initialized');\n return instanceRef.current.getElements();\n },\n setPosition: (p: number) => instanceRef.current?.setPosition(p),\n getPosition: () => instanceRef.current?.getPosition() ?? 50,\n setZoom: (l: number) => instanceRef.current?.setZoom(l),\n getZoom: () => instanceRef.current?.getZoom() ?? 1,\n resetZoom: () => instanceRef.current?.resetZoom(),\n enterFullscreen: () => instanceRef.current?.enterFullscreen(),\n exitFullscreen: () => instanceRef.current?.exitFullscreen(),\n isFullscreen: () => instanceRef.current?.isFullscreen() ?? false,\n update: (c: Partial<CIBeforeAfterConfig>) => instanceRef.current?.update(c),\n destroy: () => instanceRef.current?.destroy(),\n }));\n\n useEffect(() => {\n if (!containerRef.current) return;\n\n let cancelled = false;\n let inst: CIBeforeAfterInstance | null = null;\n\n import('../core/ci-before-after').then(\n ({ CIBeforeAfterCore }) => {\n // BUG-04: Guard against mount/unmount race\n if (cancelled || !containerRef.current) return;\n\n const config: CIBeforeAfterConfig = {\n ...configProps,\n onSlide,\n onZoom,\n onFullscreenChange,\n onReady,\n };\n\n inst = new CIBeforeAfterCore(containerRef.current, config);\n instanceRef.current = inst;\n\n // Apply any config changes that arrived during async import\n if (pendingConfigRef.current) {\n inst.update(pendingConfigRef.current);\n pendingConfigRef.current = null;\n }\n },\n () => { /* dynamic import failed — component stays empty */ },\n );\n\n return () => {\n cancelled = true;\n inst?.destroy();\n instanceRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Update on prop changes\n useEffect(() => {\n const config: Partial<CIBeforeAfterConfig> = {\n ...configProps,\n onSlide,\n onZoom,\n onFullscreenChange,\n onReady,\n };\n\n if (!instanceRef.current) {\n // Instance not yet initialized — store for later application\n pendingConfigRef.current = config;\n return;\n }\n\n instanceRef.current.update(config);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n configProps.beforeSrc,\n configProps.afterSrc,\n configProps.beforeAlt,\n configProps.afterAlt,\n configProps.mode,\n configProps.orientation,\n configProps.initialPosition,\n configProps.zoom,\n configProps.zoomMax,\n configProps.zoomMin,\n configProps.theme,\n configProps.handleStyle,\n configProps.labels,\n configProps.labelPosition,\n configProps.fullscreenButton,\n configProps.lazyLoad,\n configProps.zoomControls,\n configProps.zoomControlsPosition,\n configProps.scrollHint,\n configProps.keyboardStep,\n configProps.keyboardLargeStep,\n configProps.animate,\n configProps.animateOnce,\n configProps.cloudimage,\n onSlide,\n onZoom,\n onFullscreenChange,\n onReady,\n ]);\n\n return <div ref={containerRef} className={className} style={style} />;\n },\n);\n","import { useRef, useEffect } from 'react';\nimport type { CIBeforeAfterConfig, CIBeforeAfterInstance } from '../core/types';\n\nexport function useCIBeforeAfter(config: CIBeforeAfterConfig) {\n const containerRef = useRef<HTMLDivElement>(null);\n const instance = useRef<CIBeforeAfterInstance | null>(null);\n const pendingConfigRef = useRef<Partial<CIBeforeAfterConfig> | null>(null);\n\n useEffect(() => {\n if (!containerRef.current) return;\n\n let cancelled = false;\n let inst: CIBeforeAfterInstance | null = null;\n\n import('../core/ci-before-after').then(\n ({ CIBeforeAfterCore }) => {\n // BUG-04: Guard against mount/unmount race\n if (cancelled || !containerRef.current) return;\n inst = new CIBeforeAfterCore(containerRef.current, config);\n instance.current = inst;\n\n // Apply any config changes that arrived during async import\n if (pendingConfigRef.current) {\n inst.update(pendingConfigRef.current);\n pendingConfigRef.current = null;\n }\n },\n () => { /* dynamic import failed — hook stays empty */ },\n );\n\n return () => {\n cancelled = true;\n inst?.destroy();\n instance.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Update config when props change\n useEffect(() => {\n if (!instance.current) {\n // Instance not yet initialized — store for later application\n pendingConfigRef.current = config;\n return;\n }\n instance.current.update(config);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n config.beforeSrc,\n config.afterSrc,\n config.beforeAlt,\n config.afterAlt,\n config.mode,\n config.orientation,\n config.initialPosition,\n config.zoom,\n config.zoomMax,\n config.zoomMin,\n config.theme,\n config.handleStyle,\n config.labels,\n config.labelPosition,\n config.fullscreenButton,\n config.lazyLoad,\n config.zoomControls,\n config.zoomControlsPosition,\n config.scrollHint,\n config.keyboardStep,\n config.keyboardLargeStep,\n config.animate,\n config.animateOnce,\n config.cloudimage,\n config.onSlide,\n config.onZoom,\n config.onFullscreenChange,\n config.onReady,\n ]);\n\n return { containerRef, instance };\n}\n"],"names":["CIBeforeAfterViewer","forwardRef","props","ref","className","style","onSlide","onZoom","onFullscreenChange","onReady","configProps","containerRef","useRef","instanceRef","pendingConfigRef","useImperativeHandle","p","_a","l","c","useEffect","cancelled","inst","CIBeforeAfterCore","config","jsx","useCIBeforeAfter","instance"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CIBeforeAfterConfig, CIBeforeAfterInstance } from '../core/types';
|
|
2
|
+
import type { CSSProperties } from 'react';
|
|
3
|
+
export interface CIBeforeAfterViewerProps extends Omit<CIBeforeAfterConfig, 'onSlide' | 'onZoom' | 'onFullscreenChange' | 'onReady'> {
|
|
4
|
+
onSlide?: (position: number) => void;
|
|
5
|
+
onZoom?: (level: number) => void;
|
|
6
|
+
onFullscreenChange?: (isFullscreen: boolean) => void;
|
|
7
|
+
onReady?: () => void;
|
|
8
|
+
className?: string;
|
|
9
|
+
style?: CSSProperties;
|
|
10
|
+
}
|
|
11
|
+
export type CIBeforeAfterViewerRef = CIBeforeAfterInstance;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CIBeforeAfterConfig, CIBeforeAfterInstance } from '../core/types';
|
|
2
|
+
export declare function useCIBeforeAfter(config: CIBeforeAfterConfig): {
|
|
3
|
+
containerRef: import("react").RefObject<HTMLDivElement>;
|
|
4
|
+
instance: import("react").MutableRefObject<CIBeforeAfterInstance | null>;
|
|
5
|
+
};
|